feature(refactor): big update (#41)
This commit is contained in:
parent
59e9ff458a
commit
775702323a
3
.gitmodules
vendored
3
.gitmodules
vendored
@ -1,3 +1,6 @@
|
||||
[submodule "deps/zlib"]
|
||||
path = deps/zlib
|
||||
url = https://github.com/madler/zlib
|
||||
[submodule "deps/fmt"]
|
||||
path = deps/fmt
|
||||
url = https://github.com/fmtlib/fmt
|
||||
|
@ -1,4 +1,3 @@
|
||||
[![build](https://ci.appveyor.com/api/projects/status/defmhg4753c1ap1o?svg=true)](https://ci.appveyor.com/project/xensik/gsc-tool)
|
||||
[![build](https://github.com/xensik/gsc-tool/workflows/Build/badge.svg)](https://github.com/xensik/gsc-tool/actions)
|
||||
![license](https://img.shields.io/github/license/xensik/gsc-tool.svg)
|
||||
[![issues](https://img.shields.io/github/issues/xensik/gsc-tool)](https://github.com/xensik/gsc-tool/issues)
|
||||
@ -13,7 +12,7 @@ A utility to compile & decompile IW engine game scripts.
|
||||
- **IW6** *(Call of Duty: Ghosts)* `PC` `PS3` `PS4` `Xbox 360` `Xbox One`
|
||||
- **IW7** *(Call of Duty: Infinite Warfare)* `PC` `PS4` `Xbox One`
|
||||
- **IW8** *(Call of Duty: Modern Warfare (2019) / Warzone)* `PC` `PS4` `PS5` `Xbox One` `Xbox Series X|S`
|
||||
- **IW9** *(Call of Duty: Modern Warfare II (2022) / Warzone 2.0)* `PC` `PS4` `PS5` `Xbox One` `Xbox Series X|S`
|
||||
- **IW9** *(Call of Duty: Modern Warfare II (2022) / Warzone 2)* `PC` `PS4` `PS5` `Xbox One` `Xbox Series X|S`
|
||||
- **S1** *(Call of Duty: Advanced Warfare)* `PC` `PS3` `PS4` `Xbox 360` `Xbox One`
|
||||
- **S2** *(Call of Duty: WWII)* `PC` `PS4` `Xbox One`
|
||||
- **S4** *(Call of Duty: Vanguard)* `PC` `PS4` `PS5` `Xbox One` `Xbox Series X|S`
|
||||
@ -30,10 +29,10 @@ A utility to compile & decompile IW engine game scripts.
|
||||
**modes**: `asm`, `disasm`, `comp`, `decomp`
|
||||
- *note:* zonetool files (*.cgsc*, *.cgsc.stack*) use: `zasm`, `zdisasm`, `zcomp`, `zdecomp` modes
|
||||
|
||||
**games**: `iw5`, `iw6`, `iw7`, `iw8`, `s1`, `s2`, `s4`, `h1`, `h2`, `t6`
|
||||
- *note:* PS3 & Xbox 360 use `iw5c`, `iw6c`, `s1c` games
|
||||
**games**: `iw5`, `iw6`, `iw7`, `iw8`, `iw9`, `s1`, `s2`, `s4`, `h1`, `h2`, `t6`
|
||||
- *note:* PS3 & Xbox 360 use `iw5ps`, `iw5xb`, `iw6ps`, `iw6xb`, `s1ps`, `s1xb` games
|
||||
|
||||
**paths**: `file`, `directory` (recursive process all files inside the directory)
|
||||
**paths**: `file` or `directory` (recursive process all files inside the directory)
|
||||
|
||||
Example: ``./gsc-tool.exe comp iw5 ./data/iw5/my_fancy_script.gsc``
|
||||
|
||||
|
1
deps/fmt
vendored
Submodule
1
deps/fmt
vendored
Submodule
@ -0,0 +1 @@
|
||||
Subproject commit a33701196adfad74917046096bf5a2aa0ab0bb50
|
31
deps/fmt.lua
vendored
Normal file
31
deps/fmt.lua
vendored
Normal file
@ -0,0 +1,31 @@
|
||||
fmt = { base = path.join(dependencies.base, "fmt") }
|
||||
|
||||
function fmt:include()
|
||||
includedirs { path.join(fmt.base, "include") }
|
||||
end
|
||||
|
||||
function fmt:link()
|
||||
links { "fmt" }
|
||||
self:include()
|
||||
end
|
||||
|
||||
function fmt:project()
|
||||
project "fmt"
|
||||
kind "StaticLib"
|
||||
language "C++"
|
||||
|
||||
self:include()
|
||||
|
||||
files
|
||||
{
|
||||
path.join(fmt.base, "include/fmt/*.h"),
|
||||
path.join(fmt.base, "src/*.cc")
|
||||
}
|
||||
|
||||
removefiles
|
||||
{
|
||||
path.join(fmt.base, "src/fmt.cc")
|
||||
}
|
||||
end
|
||||
|
||||
table.insert(dependencies, fmt)
|
@ -1,9 +0,0 @@
|
||||
generate: iw5c
|
||||
|
||||
clean:
|
||||
rm -rf ./parser.hpp
|
||||
rm -rf ./parser.cpp
|
||||
|
||||
iw5c: parser.ypp
|
||||
bison parser.ypp -Wcounterexamples
|
||||
mv parser.hpp parser.cpp ../../../src/experimental/iw5c/xsk/
|
@ -1,888 +0,0 @@
|
||||
/* Copyright 2022 xensik. All rights reserved.
|
||||
//
|
||||
// Use of this source code is governed by a GNU GPLv3 license
|
||||
// that can be found in the LICENSE file.
|
||||
*/
|
||||
|
||||
%require "3.7"
|
||||
%skeleton "lalr1.cc"
|
||||
%language "c++"
|
||||
%output "parser.cpp"
|
||||
%defines "parser.hpp"
|
||||
%define api.prefix {IW5C}
|
||||
%define api.namespace {xsk::gsc::iw5c}
|
||||
%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 { xsk::gsc::iw5c::lexer& lexer }
|
||||
%parse-param { xsk::gsc::iw5c::lexer& lexer }
|
||||
%parse-param { xsk::gsc::ast::program::ptr& ast }
|
||||
|
||||
%code requires
|
||||
{
|
||||
#ifdef _MSC_VER
|
||||
#pragma warning(disable:4065)
|
||||
#pragma warning(disable:4127)
|
||||
#endif
|
||||
#include "iw5c.hpp"
|
||||
namespace xsk::gsc::iw5c { class lexer; }
|
||||
}
|
||||
|
||||
%code top
|
||||
{
|
||||
#include "stdafx.hpp"
|
||||
#include "parser.hpp"
|
||||
#include "lexer.hpp"
|
||||
using namespace xsk::gsc;
|
||||
xsk::gsc::iw5c::parser::symbol_type IW5Clex(xsk::gsc::iw5c::lexer& lexer);
|
||||
}
|
||||
|
||||
%token SH_DEFINE "#define"
|
||||
%token SH_UNDEF "#undef"
|
||||
%token SH_IFDEF "#ifdef"
|
||||
%token SH_IFNDEF "#ifndef"
|
||||
%token SH_IF "#if"
|
||||
%token SH_ELIF "#elif"
|
||||
%token SH_ELSE "#else"
|
||||
%token SH_ENDIF "#endif"
|
||||
%token DEVBEGIN "/#"
|
||||
%token DEVEND "#/"
|
||||
%token INLINE "#inline"
|
||||
%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 IF "if"
|
||||
%token ELSE "else"
|
||||
%token DO "do"
|
||||
%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 BREAKPOINT "breakpoint"
|
||||
%token PROFBEGIN "prof_begin"
|
||||
%token PROFEND "prof_end"
|
||||
%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_MUL "*="
|
||||
%token ASSIGN_DIV "/="
|
||||
%token ASSIGN_MOD "%="
|
||||
%token ASSIGN_BW_OR "|="
|
||||
%token ASSIGN_BW_AND "&="
|
||||
%token ASSIGN_BW_EXOR "^="
|
||||
%token ASSIGN_RSHIFT ">>="
|
||||
%token ASSIGN_LSHIFT "<<="
|
||||
%token BITWISE_OR "|"
|
||||
%token BITWISE_AND "&"
|
||||
%token BITWISE_EXOR "^"
|
||||
%token ADD "+"
|
||||
%token SUB "-"
|
||||
%token MUL "*"
|
||||
%token DIV "/"
|
||||
%token MOD "%"
|
||||
%token <std::string> PATH "path"
|
||||
%token <std::string> IDENTIFIER "identifier"
|
||||
%token <std::string> STRING "string literal"
|
||||
%token <std::string> ISTRING "localized string"
|
||||
%token <std::string> FLOAT "float"
|
||||
%token <std::string> INTEGER "integer"
|
||||
|
||||
%type <ast::program::ptr> program
|
||||
%type <ast::include::ptr> include
|
||||
%type <ast::decl> declaration
|
||||
%type <ast::decl_usingtree::ptr> decl_usingtree
|
||||
%type <ast::decl_constant::ptr> decl_constant
|
||||
%type <ast::decl_thread::ptr> decl_thread
|
||||
%type <ast::stmt> stmt
|
||||
%type <ast::stmt> stmt_or_dev
|
||||
%type <ast::stmt_list::ptr> stmt_list
|
||||
%type <ast::stmt_list::ptr> stmt_or_dev_list
|
||||
%type <ast::stmt_dev::ptr> stmt_dev
|
||||
%type <ast::stmt_list::ptr> stmt_block
|
||||
%type <ast::stmt_expr::ptr> stmt_expr
|
||||
%type <ast::stmt_call::ptr> stmt_call
|
||||
%type <ast::stmt_assign::ptr> stmt_assign
|
||||
%type <ast::stmt_endon::ptr> stmt_endon
|
||||
%type <ast::stmt_notify::ptr> stmt_notify
|
||||
%type <ast::stmt_wait::ptr> stmt_wait
|
||||
%type <ast::stmt_waittill::ptr> stmt_waittill
|
||||
%type <ast::stmt_waittillmatch::ptr> stmt_waittillmatch
|
||||
%type <ast::stmt_waittillframeend::ptr> stmt_waittillframeend
|
||||
%type <ast::stmt_if::ptr> stmt_if
|
||||
%type <ast::stmt_ifelse::ptr> stmt_ifelse
|
||||
%type <ast::stmt_while::ptr> stmt_while
|
||||
%type <ast::stmt_dowhile::ptr> stmt_dowhile
|
||||
%type <ast::stmt_for::ptr> stmt_for
|
||||
%type <ast::stmt_foreach::ptr> stmt_foreach
|
||||
%type <ast::stmt_switch::ptr> stmt_switch
|
||||
%type <ast::stmt_case::ptr> stmt_case
|
||||
%type <ast::stmt_default::ptr> stmt_default
|
||||
%type <ast::stmt_break::ptr> stmt_break
|
||||
%type <ast::stmt_continue::ptr> stmt_continue
|
||||
%type <ast::stmt_return::ptr> stmt_return
|
||||
%type <ast::stmt_breakpoint::ptr> stmt_breakpoint
|
||||
%type <ast::stmt_prof_begin::ptr> stmt_prof_begin
|
||||
%type <ast::stmt_prof_end::ptr> stmt_prof_end
|
||||
%type <ast::expr> expr
|
||||
%type <ast::expr> expr_or_empty
|
||||
%type <ast::expr> expr_assign
|
||||
%type <ast::expr> expr_increment
|
||||
%type <ast::expr> expr_decrement
|
||||
%type <ast::expr> expr_ternary
|
||||
%type <ast::expr> expr_binary
|
||||
%type <ast::expr> expr_primitive
|
||||
%type <ast::expr_complement::ptr> expr_complement
|
||||
%type <ast::expr_negate::ptr> expr_negate
|
||||
%type <ast::expr_not::ptr> expr_not
|
||||
%type <ast::expr_call::ptr> expr_call
|
||||
%type <ast::expr_method::ptr> expr_method
|
||||
%type <ast::call> expr_function
|
||||
%type <ast::call> expr_pointer
|
||||
%type <ast::expr_add_array::ptr> expr_add_array
|
||||
%type <ast::expr_parameters::ptr> expr_parameters
|
||||
%type <ast::expr_arguments::ptr> expr_arguments
|
||||
%type <ast::expr_arguments::ptr> expr_arguments_no_empty
|
||||
%type <ast::expr_reference::ptr> expr_reference
|
||||
%type <ast::expr> expr_tuple
|
||||
%type <ast::expr_tuple::ptr> expr_tuple_arguments
|
||||
%type <ast::expr> expr_tuple_types
|
||||
%type <ast::expr_array::ptr> expr_array
|
||||
%type <ast::expr_field::ptr> expr_field
|
||||
%type <ast::expr_size::ptr> expr_size
|
||||
%type <ast::expr_paren::ptr> expr_paren
|
||||
%type <ast::expr> expr_object
|
||||
%type <ast::expr_thisthread::ptr> expr_thisthread
|
||||
%type <ast::expr_empty_array::ptr> expr_empty_array
|
||||
%type <ast::expr_undefined::ptr> expr_undefined
|
||||
%type <ast::expr_game::ptr> expr_game
|
||||
%type <ast::expr_self::ptr> expr_self
|
||||
%type <ast::expr_anim::ptr> expr_anim
|
||||
%type <ast::expr_level::ptr> expr_level
|
||||
%type <ast::expr_animation::ptr> expr_animation
|
||||
%type <ast::expr_animtree::ptr> expr_animtree
|
||||
%type <ast::expr_identifier::ptr> expr_identifier_nosize
|
||||
%type <ast::expr_identifier::ptr> expr_identifier
|
||||
%type <ast::expr_path::ptr> expr_path
|
||||
%type <ast::expr_istring::ptr> expr_istring
|
||||
%type <ast::expr_string::ptr> expr_string
|
||||
%type <ast::expr_vector::ptr> expr_vector
|
||||
%type <ast::expr_float::ptr> expr_float
|
||||
%type <ast::expr_integer::ptr> expr_integer
|
||||
%type <ast::expr_false::ptr> expr_false
|
||||
%type <ast::expr_true::ptr> expr_true
|
||||
|
||||
%nonassoc SIZEOF
|
||||
%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_EXOR
|
||||
%left BITWISE_AND
|
||||
%left EQUALITY INEQUALITY
|
||||
%left LESS GREATER LESS_EQUAL GREATER_EQUAL
|
||||
%left LSHIFT RSHIFT
|
||||
%left ADD SUB
|
||||
%left MUL 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<ast::program>(@$); }
|
||||
;
|
||||
|
||||
program
|
||||
: program inline
|
||||
{ $$ = std::move($1); }
|
||||
| program include
|
||||
{ $$ = std::move($1); $$->includes.push_back(std::move($2)); }
|
||||
| program declaration
|
||||
{ $$ = std::move($1); $$->declarations.push_back(std::move($2)); }
|
||||
| inline
|
||||
{ $$ = std::make_unique<ast::program>(@$); }
|
||||
| include
|
||||
{ $$ = std::make_unique<ast::program>(@$); $$->includes.push_back(std::move($1)); }
|
||||
| declaration
|
||||
{ $$ = std::make_unique<ast::program>(@$); $$->declarations.push_back(std::move($1)); }
|
||||
;
|
||||
|
||||
inline
|
||||
: INLINE expr_path SEMICOLON { lexer.push_header($2->value); }
|
||||
;
|
||||
|
||||
include
|
||||
: INCLUDE expr_path SEMICOLON
|
||||
{ $$ = std::make_unique<ast::include>(@$, std::move($2)); }
|
||||
;
|
||||
|
||||
declaration
|
||||
: DEVBEGIN { $$.as_dev_begin = std::make_unique<ast::decl_dev_begin>(@$); }
|
||||
| DEVEND { $$.as_dev_end = std::make_unique<ast::decl_dev_end>(@$); }
|
||||
| decl_usingtree { $$.as_usingtree = std::move($1); }
|
||||
| decl_constant { $$.as_constant = std::move($1); }
|
||||
| decl_thread { $$.as_thread = std::move($1); }
|
||||
;
|
||||
|
||||
decl_usingtree
|
||||
: USINGTREE LPAREN expr_string RPAREN SEMICOLON
|
||||
{ lexer.ban_header(@$); $$ = std::make_unique<ast::decl_usingtree>(@$, std::move($3)); }
|
||||
;
|
||||
|
||||
decl_constant
|
||||
: expr_identifier ASSIGN expr SEMICOLON
|
||||
{ $$ = std::make_unique<ast::decl_constant>(@$, std::move($1), std::move($3)); }
|
||||
;
|
||||
|
||||
decl_thread
|
||||
: expr_identifier LPAREN expr_parameters RPAREN stmt_block
|
||||
{ lexer.ban_header(@$); $$ = std::make_unique<ast::decl_thread>(@$, std::move($1), std::move($3), std::move($5)); }
|
||||
;
|
||||
|
||||
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_if { $$.as_if = std::move($1); }
|
||||
| stmt_ifelse { $$.as_ifelse = std::move($1); }
|
||||
| stmt_while { $$.as_while = std::move($1); }
|
||||
| stmt_dowhile { $$.as_dowhile = 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_breakpoint { $$.as_breakpoint = std::move($1); }
|
||||
| stmt_prof_begin { $$.as_prof_begin = std::move($1); }
|
||||
| stmt_prof_end { $$.as_prof_end = std::move($1); }
|
||||
;
|
||||
|
||||
stmt_or_dev
|
||||
: stmt { $$ = std::move($1); }
|
||||
| stmt_dev { $$.as_dev = std::move($1); }
|
||||
;
|
||||
|
||||
stmt_list
|
||||
: stmt_list stmt
|
||||
{ $$ = std::move($1); $$->list.push_back(std::move($2)); }
|
||||
| stmt
|
||||
{ $$ = std::make_unique<ast::stmt_list>(@$); $$->list.push_back(std::move($1)); }
|
||||
;
|
||||
|
||||
stmt_or_dev_list
|
||||
: stmt_or_dev_list stmt_or_dev
|
||||
{ $$ = std::move($1); $$->list.push_back(std::move($2)); }
|
||||
| stmt_or_dev
|
||||
{ $$ = std::make_unique<ast::stmt_list>(@$); $$->list.push_back(std::move($1)); }
|
||||
;
|
||||
|
||||
stmt_dev
|
||||
: DEVBEGIN stmt_list DEVEND { $$ = std::make_unique<ast::stmt_dev>(@$, std::move($2)); }
|
||||
| DEVBEGIN DEVEND { $$ = std::make_unique<ast::stmt_dev>(@$, std::make_unique<ast::stmt_list>(@$)); }
|
||||
;
|
||||
|
||||
stmt_block
|
||||
: LBRACE stmt_or_dev_list RBRACE { $$ = std::move($2); }
|
||||
| LBRACE RBRACE { $$ = std::make_unique<ast::stmt_list>(@$); }
|
||||
;
|
||||
|
||||
stmt_expr
|
||||
: expr_assign
|
||||
{ $$ = std::make_unique<ast::stmt_expr>(@$, std::move($1)); }
|
||||
| expr_increment
|
||||
{ $$ = std::make_unique<ast::stmt_expr>(@$, std::move($1)); }
|
||||
| expr_decrement
|
||||
{ $$ = std::make_unique<ast::stmt_expr>(@$, std::move($1)); }
|
||||
|
|
||||
{ $$ = std::make_unique<ast::stmt_expr>(@$, std::make_unique<ast::node>(@$)); }
|
||||
;
|
||||
|
||||
stmt_call
|
||||
: expr_call SEMICOLON
|
||||
{ $$ = std::make_unique<ast::stmt_call>(@$, ast::expr(std::move($1))); }
|
||||
| expr_method SEMICOLON
|
||||
{ $$ = std::make_unique<ast::stmt_call>(@$, ast::expr(std::move($1))); }
|
||||
;
|
||||
|
||||
stmt_assign
|
||||
: expr_assign SEMICOLON
|
||||
{ $$ = std::make_unique<ast::stmt_assign>(@$, std::move($1)); }
|
||||
| expr_increment SEMICOLON
|
||||
{ $$ = std::make_unique<ast::stmt_assign>(@$, std::move($1)); }
|
||||
| expr_decrement SEMICOLON
|
||||
{ $$ = std::make_unique<ast::stmt_assign>(@$, std::move($1)); }
|
||||
;
|
||||
|
||||
stmt_endon
|
||||
: expr_object ENDON LPAREN expr RPAREN SEMICOLON
|
||||
{ $$ = std::make_unique<ast::stmt_endon>(@$, std::move($1), std::move($4)); }
|
||||
;
|
||||
|
||||
stmt_notify
|
||||
: expr_object NOTIFY LPAREN expr COMMA expr_arguments_no_empty RPAREN SEMICOLON
|
||||
{ $$ = std::make_unique<ast::stmt_notify>(@$, std::move($1), std::move($4), std::move($6)); }
|
||||
| expr_object NOTIFY LPAREN expr RPAREN SEMICOLON
|
||||
{ $$ = std::make_unique<ast::stmt_notify>(@$, std::move($1), std::move($4), std::make_unique<ast::expr_arguments>(@$)); }
|
||||
;
|
||||
|
||||
stmt_wait
|
||||
: WAIT expr SEMICOLON
|
||||
{ $$ = std::make_unique<ast::stmt_wait>(@$, std::move($2)); }
|
||||
;
|
||||
|
||||
stmt_waittill
|
||||
: expr_object WAITTILL LPAREN expr COMMA expr_arguments_no_empty RPAREN SEMICOLON
|
||||
{ $$ = std::make_unique<ast::stmt_waittill>(@$, std::move($1), std::move($4), std::move($6)); }
|
||||
| expr_object WAITTILL LPAREN expr RPAREN SEMICOLON
|
||||
{ $$ = std::make_unique<ast::stmt_waittill>(@$, std::move($1), std::move($4), std::make_unique<ast::expr_arguments>(@$)); }
|
||||
;
|
||||
|
||||
stmt_waittillmatch
|
||||
: expr_object WAITTILLMATCH LPAREN expr COMMA expr_arguments_no_empty RPAREN SEMICOLON
|
||||
{ $$ = std::make_unique<ast::stmt_waittillmatch>(@$, std::move($1), std::move($4), std::move($6)); }
|
||||
| expr_object WAITTILLMATCH LPAREN expr RPAREN SEMICOLON
|
||||
{ $$ = std::make_unique<ast::stmt_waittillmatch>(@$, std::move($1), std::move($4), std::make_unique<ast::expr_arguments>(@$)); }
|
||||
;
|
||||
|
||||
stmt_waittillframeend
|
||||
: WAITTILLFRAMEEND SEMICOLON
|
||||
{ $$ = std::make_unique<ast::stmt_waittillframeend>(@$); }
|
||||
;
|
||||
|
||||
stmt_if
|
||||
: IF LPAREN expr RPAREN stmt %prec THEN
|
||||
{ $$ = std::make_unique<ast::stmt_if>(@$, std::move($3), std::move($5)); }
|
||||
;
|
||||
|
||||
stmt_ifelse
|
||||
: IF LPAREN expr RPAREN stmt ELSE stmt
|
||||
{ $$ = std::make_unique<ast::stmt_ifelse>(@$, std::move($3), std::move($5), std::move($7)); }
|
||||
;
|
||||
|
||||
stmt_while
|
||||
: WHILE LPAREN expr RPAREN stmt
|
||||
{ $$ = std::make_unique<ast::stmt_while>(@$, std::move($3), std::move($5)); }
|
||||
;
|
||||
|
||||
stmt_dowhile
|
||||
: DO stmt WHILE LPAREN expr RPAREN SEMICOLON
|
||||
{ $$ = std::make_unique<ast::stmt_dowhile>(@$, std::move($5), std::move($2)); }
|
||||
;
|
||||
|
||||
stmt_for
|
||||
: FOR LPAREN stmt_expr SEMICOLON expr_or_empty SEMICOLON stmt_expr RPAREN stmt
|
||||
{ $$ = std::make_unique<ast::stmt_for>(@$, ast::stmt(std::move($3)), std::move($5), ast::stmt(std::move($7)), std::move($9)); }
|
||||
;
|
||||
|
||||
stmt_foreach
|
||||
: FOREACH LPAREN expr_identifier IN expr RPAREN stmt
|
||||
{ $$ = std::make_unique<ast::stmt_foreach>(@$, ast::expr(std::move($3)), std::move($5), std::move($7)); }
|
||||
| FOREACH LPAREN expr_identifier COMMA expr_identifier IN expr RPAREN stmt
|
||||
{ $$ = std::make_unique<ast::stmt_foreach>(@$, ast::expr(std::move($3)), ast::expr(std::move($5)), std::move($7), std::move($9)); }
|
||||
;
|
||||
|
||||
stmt_switch
|
||||
: SWITCH LPAREN expr RPAREN stmt_block
|
||||
{ $$ = std::make_unique<ast::stmt_switch>(@$, std::move($3), std::move($5)); }
|
||||
;
|
||||
|
||||
stmt_case
|
||||
: CASE expr_integer COLON
|
||||
{ $$ = std::make_unique<ast::stmt_case>(@$, ast::expr(std::move($2)), std::make_unique<ast::stmt_list>(@$)); }
|
||||
| CASE expr_string COLON
|
||||
{ $$ = std::make_unique<ast::stmt_case>(@$, ast::expr(std::move($2)), std::make_unique<ast::stmt_list>(@$)); }
|
||||
;
|
||||
|
||||
stmt_default
|
||||
: DEFAULT COLON
|
||||
{ $$ = std::make_unique<ast::stmt_default>(@$, std::make_unique<ast::stmt_list>(@$)); }
|
||||
;
|
||||
|
||||
stmt_break
|
||||
: BREAK SEMICOLON
|
||||
{ $$ = std::make_unique<ast::stmt_break>(@$); }
|
||||
;
|
||||
|
||||
stmt_continue
|
||||
: CONTINUE SEMICOLON
|
||||
{ $$ = std::make_unique<ast::stmt_continue>(@$); }
|
||||
;
|
||||
|
||||
stmt_return
|
||||
: RETURN expr SEMICOLON
|
||||
{ $$ = std::make_unique<ast::stmt_return>(@$, std::move($2)); }
|
||||
| RETURN SEMICOLON
|
||||
{ $$ = std::make_unique<ast::stmt_return>(@$, std::make_unique<ast::node>(@$)); }
|
||||
;
|
||||
|
||||
stmt_breakpoint
|
||||
: BREAKPOINT SEMICOLON
|
||||
{ $$ = std::make_unique<ast::stmt_breakpoint>(@$); }
|
||||
;
|
||||
|
||||
stmt_prof_begin
|
||||
: PROFBEGIN LPAREN expr_arguments RPAREN SEMICOLON
|
||||
{ $$ = std::make_unique<ast::stmt_prof_begin>(@$, std::move($3)); }
|
||||
;
|
||||
|
||||
stmt_prof_end
|
||||
: PROFEND LPAREN expr_arguments RPAREN SEMICOLON
|
||||
{ $$ = std::make_unique<ast::stmt_prof_end>(@$, std::move($3)); }
|
||||
;
|
||||
|
||||
expr
|
||||
: expr_ternary { $$ = std::move($1); }
|
||||
| expr_binary { $$ = std::move($1); }
|
||||
| expr_primitive { $$ = std::move($1); }
|
||||
;
|
||||
|
||||
expr_or_empty
|
||||
: expr { $$ = std::move($1); }
|
||||
| { $$.as_node = std::make_unique<ast::node>(@$); }
|
||||
;
|
||||
|
||||
expr_assign
|
||||
: expr_tuple ASSIGN expr
|
||||
{ $$.as_node = std::make_unique<ast::expr_assign_equal>(@$, std::move($1), std::move($3)); }
|
||||
| expr_object ASSIGN expr
|
||||
{ $$.as_node = std::make_unique<ast::expr_assign_equal>(@$, std::move($1), std::move($3)); }
|
||||
| expr_object ASSIGN_BW_OR expr
|
||||
{ $$.as_node = std::make_unique<ast::expr_assign_bitwise_or>(@$, std::move($1), std::move($3)); }
|
||||
| expr_object ASSIGN_BW_AND expr
|
||||
{ $$.as_node = std::make_unique<ast::expr_assign_bitwise_and>(@$, std::move($1), std::move($3)); }
|
||||
| expr_object ASSIGN_BW_EXOR expr
|
||||
{ $$.as_node = std::make_unique<ast::expr_assign_bitwise_exor>(@$, std::move($1), std::move($3)); }
|
||||
| expr_object ASSIGN_LSHIFT expr
|
||||
{ $$.as_node = std::make_unique<ast::expr_assign_shift_left>(@$, std::move($1),std::move( $3)); }
|
||||
| expr_object ASSIGN_RSHIFT expr
|
||||
{ $$.as_node = std::make_unique<ast::expr_assign_shift_right>(@$, std::move($1), std::move($3)); }
|
||||
| expr_object ASSIGN_ADD expr
|
||||
{ $$.as_node = std::make_unique<ast::expr_assign_add>(@$, std::move($1), std::move($3)); }
|
||||
| expr_object ASSIGN_SUB expr
|
||||
{ $$.as_node = std::make_unique<ast::expr_assign_sub>(@$, std::move($1), std::move($3)); }
|
||||
| expr_object ASSIGN_MUL expr
|
||||
{ $$.as_node = std::make_unique<ast::expr_assign_mul>(@$, std::move($1), std::move($3)); }
|
||||
| expr_object ASSIGN_DIV expr
|
||||
{ $$.as_node = std::make_unique<ast::expr_assign_div>(@$, std::move($1), std::move($3)); }
|
||||
| expr_object ASSIGN_MOD expr
|
||||
{ $$.as_node = std::make_unique<ast::expr_assign_mod>(@$, std::move($1), std::move($3)); }
|
||||
;
|
||||
|
||||
expr_increment
|
||||
: INCREMENT expr_object %prec PREINC
|
||||
{ $$.as_node = std::make_unique<ast::expr_increment>(@$, std::move($2), true); }
|
||||
| expr_object INCREMENT %prec POSTINC
|
||||
{ $$.as_node = std::make_unique<ast::expr_increment>(@$, std::move($1), false); }
|
||||
;
|
||||
|
||||
expr_decrement
|
||||
: DECREMENT expr_object %prec PREDEC
|
||||
{ $$.as_node = std::make_unique<ast::expr_decrement>(@$, std::move($2), true); }
|
||||
| expr_object DECREMENT %prec POSTDEC
|
||||
{ $$.as_node = std::make_unique<ast::expr_decrement>(@$, std::move($1), false); }
|
||||
;
|
||||
|
||||
expr_ternary
|
||||
: expr QMARK expr COLON expr %prec TERN
|
||||
{ $$.as_node = std::make_unique<ast::expr_ternary>(@$, std::move($1), std::move($3), std::move($5)); }
|
||||
;
|
||||
|
||||
expr_binary
|
||||
: expr OR expr
|
||||
{ $$.as_node = std::make_unique<ast::expr_or>(@$, std::move($1), std::move($3)); }
|
||||
| expr AND expr
|
||||
{ $$.as_node = std::make_unique<ast::expr_and>(@$, std::move($1), std::move($3)); }
|
||||
| expr EQUALITY expr
|
||||
{ $$.as_node = std::make_unique<ast::expr_equality>(@$, std::move($1), std::move($3)); }
|
||||
| expr INEQUALITY expr
|
||||
{ $$.as_node = std::make_unique<ast::expr_inequality>(@$, std::move($1), std::move($3)); }
|
||||
| expr LESS_EQUAL expr
|
||||
{ $$.as_node = std::make_unique<ast::expr_less_equal>(@$, std::move($1), std::move($3)); }
|
||||
| expr GREATER_EQUAL expr
|
||||
{ $$.as_node = std::make_unique<ast::expr_greater_equal>(@$, std::move($1), std::move($3)); }
|
||||
| expr LESS expr
|
||||
{ $$.as_node = std::make_unique<ast::expr_less>(@$, std::move($1), std::move($3)); }
|
||||
| expr GREATER expr
|
||||
{ $$.as_node = std::make_unique<ast::expr_greater>(@$, std::move($1), std::move($3)); }
|
||||
| expr BITWISE_OR expr
|
||||
{ $$.as_node = std::make_unique<ast::expr_bitwise_or>(@$, std::move($1), std::move($3)); }
|
||||
| expr BITWISE_AND expr
|
||||
{ $$.as_node = std::make_unique<ast::expr_bitwise_and>(@$, std::move($1), std::move($3)); }
|
||||
| expr BITWISE_EXOR expr
|
||||
{ $$.as_node = std::make_unique<ast::expr_bitwise_exor>(@$, std::move($1), std::move($3)); }
|
||||
| expr LSHIFT expr
|
||||
{ $$.as_node = std::make_unique<ast::expr_shift_left>(@$, std::move($1), std::move($3)); }
|
||||
| expr RSHIFT expr
|
||||
{ $$.as_node = std::make_unique<ast::expr_shift_right>(@$, std::move($1), std::move($3)); }
|
||||
| expr ADD expr
|
||||
{ $$.as_node = std::make_unique<ast::expr_add>(@$, std::move($1), std::move($3)); }
|
||||
| expr SUB expr
|
||||
{ $$.as_node = std::make_unique<ast::expr_sub>(@$, std::move($1), std::move($3)); }
|
||||
| expr MUL expr
|
||||
{ $$.as_node = std::make_unique<ast::expr_mul>(@$, std::move($1), std::move($3)); }
|
||||
| expr DIV expr
|
||||
{ $$.as_node = std::make_unique<ast::expr_div>(@$, std::move($1), std::move($3)); }
|
||||
| expr MOD expr
|
||||
{ $$.as_node = std::make_unique<ast::expr_mod>(@$, std::move($1), std::move($3)); }
|
||||
;
|
||||
|
||||
expr_primitive
|
||||
: expr_complement { $$.as_node = std::move($1); }
|
||||
| expr_negate { $$.as_node = std::move($1); }
|
||||
| expr_not { $$.as_node = std::move($1); }
|
||||
| expr_call { $$.as_node = std::move($1); }
|
||||
| expr_method { $$.as_node = std::move($1); }
|
||||
| expr_add_array { $$.as_node = std::move($1); }
|
||||
| expr_reference { $$.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); }
|
||||
| expr_paren { $$.as_node = std::move($1); }
|
||||
| expr_thisthread { $$.as_node = std::move($1); }
|
||||
| expr_empty_array { $$.as_node = std::move($1); }
|
||||
| expr_undefined { $$.as_node = std::move($1); }
|
||||
| expr_game { $$.as_node = std::move($1); }
|
||||
| expr_self { $$.as_node = std::move($1); }
|
||||
| expr_anim { $$.as_node = std::move($1); }
|
||||
| expr_level { $$.as_node = std::move($1); }
|
||||
| expr_animation { $$.as_node = std::move($1); }
|
||||
| expr_animtree { $$.as_node = std::move($1); }
|
||||
| expr_identifier { $$.as_node = std::move($1); }
|
||||
| expr_istring { $$.as_node = std::move($1); }
|
||||
| expr_string { $$.as_node = std::move($1); }
|
||||
| expr_vector { $$.as_node = std::move($1); }
|
||||
| expr_float { $$.as_node = std::move($1); }
|
||||
| expr_integer { $$.as_node = std::move($1); }
|
||||
| expr_false { $$.as_node = std::move($1); }
|
||||
| expr_true { $$.as_node = std::move($1); }
|
||||
;
|
||||
|
||||
expr_complement
|
||||
: COMPLEMENT expr
|
||||
{ $$ = std::make_unique<ast::expr_complement>(@$, std::move($2)); }
|
||||
;
|
||||
|
||||
expr_negate
|
||||
: SUB expr_identifier %prec NEG
|
||||
{ $$ = std::make_unique<ast::expr_negate>(@$, ast::expr(std::move($2))); }
|
||||
| SUB expr_paren %prec NEG
|
||||
{ $$ = std::make_unique<ast::expr_negate>(@$, ast::expr(std::move($2))); }
|
||||
| SUB expr_array %prec NEG
|
||||
{ $$ = std::make_unique<ast::expr_negate>(@$, ast::expr(std::move($2))); }
|
||||
| SUB expr_field %prec NEG
|
||||
{ $$ = std::make_unique<ast::expr_negate>(@$, ast::expr(std::move($2))); }
|
||||
;
|
||||
|
||||
expr_not
|
||||
: NOT expr
|
||||
{ $$ = std::make_unique<ast::expr_not>(@$, std::move($2)); }
|
||||
;
|
||||
|
||||
expr_call
|
||||
: expr_function { $$ = std::make_unique<ast::expr_call>(@$, std::move($1)); }
|
||||
| expr_pointer { $$ = std::make_unique<ast::expr_call>(@$, std::move($1)); }
|
||||
;
|
||||
expr_method
|
||||
: expr_object expr_function { $$ = std::make_unique<ast::expr_method>(@$, std::move($1), std::move($2)); }
|
||||
| expr_object expr_pointer { $$ = std::make_unique<ast::expr_method>(@$, std::move($1), std::move($2)); }
|
||||
;
|
||||
|
||||
expr_function
|
||||
: expr_identifier LPAREN expr_arguments RPAREN
|
||||
{ $$.as_function = std::make_unique<ast::expr_function>(@$, std::make_unique<ast::expr_path>(@$), std::move($1), std::move($3), ast::call::mode::normal); }
|
||||
| expr_path DOUBLECOLON expr_identifier LPAREN expr_arguments RPAREN
|
||||
{ $$.as_function = std::make_unique<ast::expr_function>(@$, std::move($1), std::move($3), std::move($5), ast::call::mode::normal); }
|
||||
| THREAD expr_identifier LPAREN expr_arguments RPAREN
|
||||
{ $$.as_function = std::make_unique<ast::expr_function>(@$, std::make_unique<ast::expr_path>(@$), std::move($2), std::move($4), ast::call::mode::thread); }
|
||||
| THREAD expr_path DOUBLECOLON expr_identifier LPAREN expr_arguments RPAREN
|
||||
{ $$.as_function = std::make_unique<ast::expr_function>(@$, std::move($2), std::move($4), std::move($6), ast::call::mode::thread); }
|
||||
| CHILDTHREAD expr_identifier LPAREN expr_arguments RPAREN
|
||||
{ $$.as_function = std::make_unique<ast::expr_function>(@$, std::make_unique<ast::expr_path>(@$), std::move($2), std::move($4), ast::call::mode::childthread); }
|
||||
| CHILDTHREAD expr_path DOUBLECOLON expr_identifier LPAREN expr_arguments RPAREN
|
||||
{ $$.as_function = std::make_unique<ast::expr_function>(@$, std::move($2), std::move($4), std::move($6), ast::call::mode::childthread); }
|
||||
;
|
||||
|
||||
expr_pointer
|
||||
: LBRACKET LBRACKET expr RBRACKET RBRACKET LPAREN expr_arguments RPAREN
|
||||
{ $$.as_pointer = std::make_unique<ast::expr_pointer>(@$, std::move($3), std::move($7), ast::call::mode::normal); }
|
||||
| THREAD LBRACKET LBRACKET expr RBRACKET RBRACKET LPAREN expr_arguments RPAREN
|
||||
{ $$.as_pointer = std::make_unique<ast::expr_pointer>(@$, std::move($4), std::move($8), ast::call::mode::thread); }
|
||||
| CHILDTHREAD LBRACKET LBRACKET expr RBRACKET RBRACKET LPAREN expr_arguments RPAREN
|
||||
{ $$.as_pointer = std::make_unique<ast::expr_pointer>(@$, std::move($4), std::move($8), ast::call::mode::childthread); }
|
||||
| CALL LBRACKET LBRACKET expr RBRACKET RBRACKET LPAREN expr_arguments RPAREN
|
||||
{ $$.as_pointer = std::make_unique<ast::expr_pointer>(@$, std::move($4), std::move($8), ast::call::mode::builtin); }
|
||||
;
|
||||
|
||||
expr_add_array
|
||||
: LBRACKET expr_arguments_no_empty RBRACKET
|
||||
{ $$ = std::make_unique<ast::expr_add_array>(@$, std::move($2)); }
|
||||
;
|
||||
|
||||
expr_parameters
|
||||
: expr_parameters COMMA expr_identifier
|
||||
{ $$ = std::move($1); $$->list.push_back(std::move($3)); }
|
||||
| expr_identifier
|
||||
{ $$ = std::make_unique<ast::expr_parameters>(@$); $$->list.push_back(std::move($1)); }
|
||||
|
|
||||
{ $$ = std::make_unique<ast::expr_parameters>(@$); }
|
||||
;
|
||||
|
||||
expr_arguments
|
||||
: expr_arguments_no_empty
|
||||
{ $$ = std::move($1); }
|
||||
|
|
||||
{ $$ = std::make_unique<ast::expr_arguments>(@$); }
|
||||
;
|
||||
|
||||
expr_arguments_no_empty
|
||||
: expr_arguments COMMA expr
|
||||
{ $$ = std::move($1); $$->list.push_back(std::move($3)); }
|
||||
| expr %prec ADD_ARRAY
|
||||
{ $$ = std::make_unique<ast::expr_arguments>(@$); $$->list.push_back(std::move($1)); }
|
||||
;
|
||||
|
||||
expr_reference
|
||||
: DOUBLECOLON expr_identifier
|
||||
{ $$ = std::make_unique<ast::expr_reference>(@$, std::make_unique<ast::expr_path>(@$), std::move($2)); }
|
||||
| expr_path DOUBLECOLON expr_identifier
|
||||
{ $$ = std::make_unique<ast::expr_reference>(@$, std::move($1), std::move($3)); }
|
||||
;
|
||||
|
||||
expr_tuple
|
||||
: LBRACKET expr_tuple_arguments RBRACKET
|
||||
{ $$.as_node = std::move($2); }
|
||||
;
|
||||
|
||||
expr_tuple_arguments
|
||||
: expr_tuple_arguments COMMA expr_tuple_types
|
||||
{ $$ = std::move($1); $$->list.push_back(std::move($3)); }
|
||||
| expr_tuple_types
|
||||
{ $$ = std::make_unique<ast::expr_tuple>(@$); $$->list.push_back(std::move($1)); }
|
||||
;
|
||||
|
||||
expr_tuple_types
|
||||
: expr_array { $$.as_node = std::move($1); }
|
||||
| expr_field { $$.as_node = std::move($1); }
|
||||
| expr_identifier { $$.as_node = std::move($1); }
|
||||
;
|
||||
|
||||
expr_array
|
||||
: expr_object LBRACKET expr RBRACKET
|
||||
{ $$ = std::make_unique<ast::expr_array>(@$, std::move($1), std::move($3)); }
|
||||
;
|
||||
|
||||
expr_field
|
||||
: expr_object DOT expr_identifier_nosize
|
||||
{ $$ = std::make_unique<ast::expr_field>(@$, std::move($1), std::move($3)); }
|
||||
;
|
||||
|
||||
expr_size
|
||||
: expr_object DOT SIZE %prec SIZEOF
|
||||
{ $$ = std::make_unique<ast::expr_size>(@$, std::move($1)); }
|
||||
;
|
||||
|
||||
expr_paren
|
||||
: LPAREN expr RPAREN
|
||||
{ $$ = std::make_unique<ast::expr_paren>(@$, std::move($2)); }
|
||||
;
|
||||
|
||||
expr_object
|
||||
: expr_call { $$.as_node = std::move($1); }
|
||||
| expr_method { $$.as_node = std::move($1); }
|
||||
| expr_array { $$.as_node = std::move($1); }
|
||||
| expr_field { $$.as_node = std::move($1); }
|
||||
| expr_game { $$.as_node = std::move($1); }
|
||||
| expr_self { $$.as_node = std::move($1); }
|
||||
| expr_anim { $$.as_node = std::move($1); }
|
||||
| expr_level { $$.as_node = std::move($1); }
|
||||
| expr_identifier { $$.as_node = std::move($1); }
|
||||
;
|
||||
|
||||
expr_thisthread
|
||||
: THISTHREAD
|
||||
{ $$ = std::make_unique<ast::expr_thisthread>(@$); };
|
||||
;
|
||||
|
||||
expr_empty_array
|
||||
: LBRACKET RBRACKET
|
||||
{ $$ = std::make_unique<ast::expr_empty_array>(@$); };
|
||||
;
|
||||
|
||||
expr_undefined
|
||||
: UNDEFINED
|
||||
{ $$ = std::make_unique<ast::expr_undefined>(@$); };
|
||||
;
|
||||
|
||||
expr_game
|
||||
: GAME
|
||||
{ $$ = std::make_unique<ast::expr_game>(@$); };
|
||||
;
|
||||
|
||||
expr_self
|
||||
: SELF
|
||||
{ $$ = std::make_unique<ast::expr_self>(@$); };
|
||||
;
|
||||
|
||||
expr_anim
|
||||
: ANIM
|
||||
{ $$ = std::make_unique<ast::expr_anim>(@$); };
|
||||
;
|
||||
|
||||
expr_level
|
||||
: LEVEL
|
||||
{ $$ = std::make_unique<ast::expr_level>(@$); };
|
||||
;
|
||||
|
||||
expr_animation
|
||||
: MOD IDENTIFIER %prec ANIMREF
|
||||
{ $$ = std::make_unique<ast::expr_animation>(@$, $2); };
|
||||
;
|
||||
|
||||
expr_animtree
|
||||
: ANIMTREE
|
||||
{ $$ = std::make_unique<ast::expr_animtree>(@$); };
|
||||
;
|
||||
|
||||
expr_identifier_nosize
|
||||
: IDENTIFIER
|
||||
{ $$ = std::make_unique<ast::expr_identifier>(@$, $1); };
|
||||
;
|
||||
|
||||
expr_identifier
|
||||
: IDENTIFIER
|
||||
{ $$ = std::make_unique<ast::expr_identifier>(@$, $1); };
|
||||
| SIZE
|
||||
{ $$ = std::make_unique<ast::expr_identifier>(@$, "size"); };
|
||||
;
|
||||
|
||||
expr_path
|
||||
: IDENTIFIER
|
||||
{ $$ = std::make_unique<ast::expr_path>(@$, $1); };
|
||||
| PATH
|
||||
{ $$ = std::make_unique<ast::expr_path>(@$, $1); };
|
||||
;
|
||||
|
||||
expr_istring
|
||||
: ISTRING
|
||||
{ $$ = std::make_unique<ast::expr_istring>(@$, $1); };
|
||||
;
|
||||
|
||||
expr_string
|
||||
: STRING
|
||||
{ $$ = std::make_unique<ast::expr_string>(@$, $1); };
|
||||
;
|
||||
|
||||
expr_vector
|
||||
: LPAREN expr COMMA expr COMMA expr RPAREN
|
||||
{ $$ = std::make_unique<ast::expr_vector>(@$, std::move($2), std::move($4), std::move($6)); };
|
||||
;
|
||||
|
||||
expr_float
|
||||
: SUB FLOAT %prec NEG
|
||||
{ $$ = std::make_unique<ast::expr_float>(@$, "-" + $2); };
|
||||
| FLOAT
|
||||
{ $$ = std::make_unique<ast::expr_float>(@$, $1); };
|
||||
;
|
||||
|
||||
expr_integer
|
||||
: SUB INTEGER %prec NEG
|
||||
{ $$ = std::make_unique<ast::expr_integer>(@$, "-" + $2); };
|
||||
| INTEGER
|
||||
{ $$ = std::make_unique<ast::expr_integer>(@$, $1); };
|
||||
;
|
||||
|
||||
expr_false
|
||||
: FALSE
|
||||
{ $$ = std::make_unique<ast::expr_false>(@$); };
|
||||
;
|
||||
|
||||
expr_true
|
||||
: TRUE
|
||||
{ $$ = std::make_unique<ast::expr_true>(@$); };
|
||||
;
|
||||
|
||||
%%
|
||||
|
||||
void xsk::gsc::iw5c::parser::error(const xsk::gsc::location& loc, const std::string& msg)
|
||||
{
|
||||
throw xsk::gsc::comp_error(loc, msg);
|
||||
}
|
@ -1,9 +0,0 @@
|
||||
generate: iw6c
|
||||
|
||||
clean:
|
||||
rm -rf ./parser.hpp
|
||||
rm -rf ./parser.cpp
|
||||
|
||||
iw6c: parser.ypp
|
||||
bison parser.ypp -Wcounterexamples
|
||||
mv parser.hpp parser.cpp ../../../src/experimental/iw6c/xsk/
|
@ -1,888 +0,0 @@
|
||||
/* Copyright 2022 xensik. All rights reserved.
|
||||
//
|
||||
// Use of this source code is governed by a GNU GPLv3 license
|
||||
// that can be found in the LICENSE file.
|
||||
*/
|
||||
|
||||
%require "3.7"
|
||||
%skeleton "lalr1.cc"
|
||||
%language "c++"
|
||||
%output "parser.cpp"
|
||||
%defines "parser.hpp"
|
||||
%define api.prefix {IW6C}
|
||||
%define api.namespace {xsk::gsc::iw6c}
|
||||
%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 { xsk::gsc::iw6c::lexer& lexer }
|
||||
%parse-param { xsk::gsc::iw6c::lexer& lexer }
|
||||
%parse-param { xsk::gsc::ast::program::ptr& ast }
|
||||
|
||||
%code requires
|
||||
{
|
||||
#ifdef _MSC_VER
|
||||
#pragma warning(disable:4065)
|
||||
#pragma warning(disable:4127)
|
||||
#endif
|
||||
#include "iw6c.hpp"
|
||||
namespace xsk::gsc::iw6c { class lexer; }
|
||||
}
|
||||
|
||||
%code top
|
||||
{
|
||||
#include "stdafx.hpp"
|
||||
#include "parser.hpp"
|
||||
#include "lexer.hpp"
|
||||
using namespace xsk::gsc;
|
||||
xsk::gsc::iw6c::parser::symbol_type IW6Clex(xsk::gsc::iw6c::lexer& lexer);
|
||||
}
|
||||
|
||||
%token SH_DEFINE "#define"
|
||||
%token SH_UNDEF "#undef"
|
||||
%token SH_IFDEF "#ifdef"
|
||||
%token SH_IFNDEF "#ifndef"
|
||||
%token SH_IF "#if"
|
||||
%token SH_ELIF "#elif"
|
||||
%token SH_ELSE "#else"
|
||||
%token SH_ENDIF "#endif"
|
||||
%token DEVBEGIN "/#"
|
||||
%token DEVEND "#/"
|
||||
%token INLINE "#inline"
|
||||
%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 IF "if"
|
||||
%token ELSE "else"
|
||||
%token DO "do"
|
||||
%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 BREAKPOINT "breakpoint"
|
||||
%token PROFBEGIN "prof_begin"
|
||||
%token PROFEND "prof_end"
|
||||
%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_MUL "*="
|
||||
%token ASSIGN_DIV "/="
|
||||
%token ASSIGN_MOD "%="
|
||||
%token ASSIGN_BW_OR "|="
|
||||
%token ASSIGN_BW_AND "&="
|
||||
%token ASSIGN_BW_EXOR "^="
|
||||
%token ASSIGN_RSHIFT ">>="
|
||||
%token ASSIGN_LSHIFT "<<="
|
||||
%token BITWISE_OR "|"
|
||||
%token BITWISE_AND "&"
|
||||
%token BITWISE_EXOR "^"
|
||||
%token ADD "+"
|
||||
%token SUB "-"
|
||||
%token MUL "*"
|
||||
%token DIV "/"
|
||||
%token MOD "%"
|
||||
%token <std::string> PATH "path"
|
||||
%token <std::string> IDENTIFIER "identifier"
|
||||
%token <std::string> STRING "string literal"
|
||||
%token <std::string> ISTRING "localized string"
|
||||
%token <std::string> FLOAT "float"
|
||||
%token <std::string> INTEGER "integer"
|
||||
|
||||
%type <ast::program::ptr> program
|
||||
%type <ast::include::ptr> include
|
||||
%type <ast::decl> declaration
|
||||
%type <ast::decl_usingtree::ptr> decl_usingtree
|
||||
%type <ast::decl_constant::ptr> decl_constant
|
||||
%type <ast::decl_thread::ptr> decl_thread
|
||||
%type <ast::stmt> stmt
|
||||
%type <ast::stmt> stmt_or_dev
|
||||
%type <ast::stmt_list::ptr> stmt_list
|
||||
%type <ast::stmt_list::ptr> stmt_or_dev_list
|
||||
%type <ast::stmt_dev::ptr> stmt_dev
|
||||
%type <ast::stmt_list::ptr> stmt_block
|
||||
%type <ast::stmt_expr::ptr> stmt_expr
|
||||
%type <ast::stmt_call::ptr> stmt_call
|
||||
%type <ast::stmt_assign::ptr> stmt_assign
|
||||
%type <ast::stmt_endon::ptr> stmt_endon
|
||||
%type <ast::stmt_notify::ptr> stmt_notify
|
||||
%type <ast::stmt_wait::ptr> stmt_wait
|
||||
%type <ast::stmt_waittill::ptr> stmt_waittill
|
||||
%type <ast::stmt_waittillmatch::ptr> stmt_waittillmatch
|
||||
%type <ast::stmt_waittillframeend::ptr> stmt_waittillframeend
|
||||
%type <ast::stmt_if::ptr> stmt_if
|
||||
%type <ast::stmt_ifelse::ptr> stmt_ifelse
|
||||
%type <ast::stmt_while::ptr> stmt_while
|
||||
%type <ast::stmt_dowhile::ptr> stmt_dowhile
|
||||
%type <ast::stmt_for::ptr> stmt_for
|
||||
%type <ast::stmt_foreach::ptr> stmt_foreach
|
||||
%type <ast::stmt_switch::ptr> stmt_switch
|
||||
%type <ast::stmt_case::ptr> stmt_case
|
||||
%type <ast::stmt_default::ptr> stmt_default
|
||||
%type <ast::stmt_break::ptr> stmt_break
|
||||
%type <ast::stmt_continue::ptr> stmt_continue
|
||||
%type <ast::stmt_return::ptr> stmt_return
|
||||
%type <ast::stmt_breakpoint::ptr> stmt_breakpoint
|
||||
%type <ast::stmt_prof_begin::ptr> stmt_prof_begin
|
||||
%type <ast::stmt_prof_end::ptr> stmt_prof_end
|
||||
%type <ast::expr> expr
|
||||
%type <ast::expr> expr_or_empty
|
||||
%type <ast::expr> expr_assign
|
||||
%type <ast::expr> expr_increment
|
||||
%type <ast::expr> expr_decrement
|
||||
%type <ast::expr> expr_ternary
|
||||
%type <ast::expr> expr_binary
|
||||
%type <ast::expr> expr_primitive
|
||||
%type <ast::expr_complement::ptr> expr_complement
|
||||
%type <ast::expr_negate::ptr> expr_negate
|
||||
%type <ast::expr_not::ptr> expr_not
|
||||
%type <ast::expr_call::ptr> expr_call
|
||||
%type <ast::expr_method::ptr> expr_method
|
||||
%type <ast::call> expr_function
|
||||
%type <ast::call> expr_pointer
|
||||
%type <ast::expr_add_array::ptr> expr_add_array
|
||||
%type <ast::expr_parameters::ptr> expr_parameters
|
||||
%type <ast::expr_arguments::ptr> expr_arguments
|
||||
%type <ast::expr_arguments::ptr> expr_arguments_no_empty
|
||||
%type <ast::expr_reference::ptr> expr_reference
|
||||
%type <ast::expr> expr_tuple
|
||||
%type <ast::expr_tuple::ptr> expr_tuple_arguments
|
||||
%type <ast::expr> expr_tuple_types
|
||||
%type <ast::expr_array::ptr> expr_array
|
||||
%type <ast::expr_field::ptr> expr_field
|
||||
%type <ast::expr_size::ptr> expr_size
|
||||
%type <ast::expr_paren::ptr> expr_paren
|
||||
%type <ast::expr> expr_object
|
||||
%type <ast::expr_thisthread::ptr> expr_thisthread
|
||||
%type <ast::expr_empty_array::ptr> expr_empty_array
|
||||
%type <ast::expr_undefined::ptr> expr_undefined
|
||||
%type <ast::expr_game::ptr> expr_game
|
||||
%type <ast::expr_self::ptr> expr_self
|
||||
%type <ast::expr_anim::ptr> expr_anim
|
||||
%type <ast::expr_level::ptr> expr_level
|
||||
%type <ast::expr_animation::ptr> expr_animation
|
||||
%type <ast::expr_animtree::ptr> expr_animtree
|
||||
%type <ast::expr_identifier::ptr> expr_identifier_nosize
|
||||
%type <ast::expr_identifier::ptr> expr_identifier
|
||||
%type <ast::expr_path::ptr> expr_path
|
||||
%type <ast::expr_istring::ptr> expr_istring
|
||||
%type <ast::expr_string::ptr> expr_string
|
||||
%type <ast::expr_vector::ptr> expr_vector
|
||||
%type <ast::expr_float::ptr> expr_float
|
||||
%type <ast::expr_integer::ptr> expr_integer
|
||||
%type <ast::expr_false::ptr> expr_false
|
||||
%type <ast::expr_true::ptr> expr_true
|
||||
|
||||
%nonassoc SIZEOF
|
||||
%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_EXOR
|
||||
%left BITWISE_AND
|
||||
%left EQUALITY INEQUALITY
|
||||
%left LESS GREATER LESS_EQUAL GREATER_EQUAL
|
||||
%left LSHIFT RSHIFT
|
||||
%left ADD SUB
|
||||
%left MUL 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<ast::program>(@$); }
|
||||
;
|
||||
|
||||
program
|
||||
: program inline
|
||||
{ $$ = std::move($1); }
|
||||
| program include
|
||||
{ $$ = std::move($1); $$->includes.push_back(std::move($2)); }
|
||||
| program declaration
|
||||
{ $$ = std::move($1); $$->declarations.push_back(std::move($2)); }
|
||||
| inline
|
||||
{ $$ = std::make_unique<ast::program>(@$); }
|
||||
| include
|
||||
{ $$ = std::make_unique<ast::program>(@$); $$->includes.push_back(std::move($1)); }
|
||||
| declaration
|
||||
{ $$ = std::make_unique<ast::program>(@$); $$->declarations.push_back(std::move($1)); }
|
||||
;
|
||||
|
||||
inline
|
||||
: INLINE expr_path SEMICOLON { lexer.push_header($2->value); }
|
||||
;
|
||||
|
||||
include
|
||||
: INCLUDE expr_path SEMICOLON
|
||||
{ $$ = std::make_unique<ast::include>(@$, std::move($2)); }
|
||||
;
|
||||
|
||||
declaration
|
||||
: DEVBEGIN { $$.as_dev_begin = std::make_unique<ast::decl_dev_begin>(@$); }
|
||||
| DEVEND { $$.as_dev_end = std::make_unique<ast::decl_dev_end>(@$); }
|
||||
| decl_usingtree { $$.as_usingtree = std::move($1); }
|
||||
| decl_constant { $$.as_constant = std::move($1); }
|
||||
| decl_thread { $$.as_thread = std::move($1); }
|
||||
;
|
||||
|
||||
decl_usingtree
|
||||
: USINGTREE LPAREN expr_string RPAREN SEMICOLON
|
||||
{ lexer.ban_header(@$); $$ = std::make_unique<ast::decl_usingtree>(@$, std::move($3)); }
|
||||
;
|
||||
|
||||
decl_constant
|
||||
: expr_identifier ASSIGN expr SEMICOLON
|
||||
{ $$ = std::make_unique<ast::decl_constant>(@$, std::move($1), std::move($3)); }
|
||||
;
|
||||
|
||||
decl_thread
|
||||
: expr_identifier LPAREN expr_parameters RPAREN stmt_block
|
||||
{ lexer.ban_header(@$); $$ = std::make_unique<ast::decl_thread>(@$, std::move($1), std::move($3), std::move($5)); }
|
||||
;
|
||||
|
||||
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_if { $$.as_if = std::move($1); }
|
||||
| stmt_ifelse { $$.as_ifelse = std::move($1); }
|
||||
| stmt_while { $$.as_while = std::move($1); }
|
||||
| stmt_dowhile { $$.as_dowhile = 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_breakpoint { $$.as_breakpoint = std::move($1); }
|
||||
| stmt_prof_begin { $$.as_prof_begin = std::move($1); }
|
||||
| stmt_prof_end { $$.as_prof_end = std::move($1); }
|
||||
;
|
||||
|
||||
stmt_or_dev
|
||||
: stmt { $$ = std::move($1); }
|
||||
| stmt_dev { $$.as_dev = std::move($1); }
|
||||
;
|
||||
|
||||
stmt_list
|
||||
: stmt_list stmt
|
||||
{ $$ = std::move($1); $$->list.push_back(std::move($2)); }
|
||||
| stmt
|
||||
{ $$ = std::make_unique<ast::stmt_list>(@$); $$->list.push_back(std::move($1)); }
|
||||
;
|
||||
|
||||
stmt_or_dev_list
|
||||
: stmt_or_dev_list stmt_or_dev
|
||||
{ $$ = std::move($1); $$->list.push_back(std::move($2)); }
|
||||
| stmt_or_dev
|
||||
{ $$ = std::make_unique<ast::stmt_list>(@$); $$->list.push_back(std::move($1)); }
|
||||
;
|
||||
|
||||
stmt_dev
|
||||
: DEVBEGIN stmt_list DEVEND { $$ = std::make_unique<ast::stmt_dev>(@$, std::move($2)); }
|
||||
| DEVBEGIN DEVEND { $$ = std::make_unique<ast::stmt_dev>(@$, std::make_unique<ast::stmt_list>(@$)); }
|
||||
;
|
||||
|
||||
stmt_block
|
||||
: LBRACE stmt_or_dev_list RBRACE { $$ = std::move($2); }
|
||||
| LBRACE RBRACE { $$ = std::make_unique<ast::stmt_list>(@$); }
|
||||
;
|
||||
|
||||
stmt_expr
|
||||
: expr_assign
|
||||
{ $$ = std::make_unique<ast::stmt_expr>(@$, std::move($1)); }
|
||||
| expr_increment
|
||||
{ $$ = std::make_unique<ast::stmt_expr>(@$, std::move($1)); }
|
||||
| expr_decrement
|
||||
{ $$ = std::make_unique<ast::stmt_expr>(@$, std::move($1)); }
|
||||
|
|
||||
{ $$ = std::make_unique<ast::stmt_expr>(@$, std::make_unique<ast::node>(@$)); }
|
||||
;
|
||||
|
||||
stmt_call
|
||||
: expr_call SEMICOLON
|
||||
{ $$ = std::make_unique<ast::stmt_call>(@$, ast::expr(std::move($1))); }
|
||||
| expr_method SEMICOLON
|
||||
{ $$ = std::make_unique<ast::stmt_call>(@$, ast::expr(std::move($1))); }
|
||||
;
|
||||
|
||||
stmt_assign
|
||||
: expr_assign SEMICOLON
|
||||
{ $$ = std::make_unique<ast::stmt_assign>(@$, std::move($1)); }
|
||||
| expr_increment SEMICOLON
|
||||
{ $$ = std::make_unique<ast::stmt_assign>(@$, std::move($1)); }
|
||||
| expr_decrement SEMICOLON
|
||||
{ $$ = std::make_unique<ast::stmt_assign>(@$, std::move($1)); }
|
||||
;
|
||||
|
||||
stmt_endon
|
||||
: expr_object ENDON LPAREN expr RPAREN SEMICOLON
|
||||
{ $$ = std::make_unique<ast::stmt_endon>(@$, std::move($1), std::move($4)); }
|
||||
;
|
||||
|
||||
stmt_notify
|
||||
: expr_object NOTIFY LPAREN expr COMMA expr_arguments_no_empty RPAREN SEMICOLON
|
||||
{ $$ = std::make_unique<ast::stmt_notify>(@$, std::move($1), std::move($4), std::move($6)); }
|
||||
| expr_object NOTIFY LPAREN expr RPAREN SEMICOLON
|
||||
{ $$ = std::make_unique<ast::stmt_notify>(@$, std::move($1), std::move($4), std::make_unique<ast::expr_arguments>(@$)); }
|
||||
;
|
||||
|
||||
stmt_wait
|
||||
: WAIT expr SEMICOLON
|
||||
{ $$ = std::make_unique<ast::stmt_wait>(@$, std::move($2)); }
|
||||
;
|
||||
|
||||
stmt_waittill
|
||||
: expr_object WAITTILL LPAREN expr COMMA expr_arguments_no_empty RPAREN SEMICOLON
|
||||
{ $$ = std::make_unique<ast::stmt_waittill>(@$, std::move($1), std::move($4), std::move($6)); }
|
||||
| expr_object WAITTILL LPAREN expr RPAREN SEMICOLON
|
||||
{ $$ = std::make_unique<ast::stmt_waittill>(@$, std::move($1), std::move($4), std::make_unique<ast::expr_arguments>(@$)); }
|
||||
;
|
||||
|
||||
stmt_waittillmatch
|
||||
: expr_object WAITTILLMATCH LPAREN expr COMMA expr_arguments_no_empty RPAREN SEMICOLON
|
||||
{ $$ = std::make_unique<ast::stmt_waittillmatch>(@$, std::move($1), std::move($4), std::move($6)); }
|
||||
| expr_object WAITTILLMATCH LPAREN expr RPAREN SEMICOLON
|
||||
{ $$ = std::make_unique<ast::stmt_waittillmatch>(@$, std::move($1), std::move($4), std::make_unique<ast::expr_arguments>(@$)); }
|
||||
;
|
||||
|
||||
stmt_waittillframeend
|
||||
: WAITTILLFRAMEEND SEMICOLON
|
||||
{ $$ = std::make_unique<ast::stmt_waittillframeend>(@$); }
|
||||
;
|
||||
|
||||
stmt_if
|
||||
: IF LPAREN expr RPAREN stmt %prec THEN
|
||||
{ $$ = std::make_unique<ast::stmt_if>(@$, std::move($3), std::move($5)); }
|
||||
;
|
||||
|
||||
stmt_ifelse
|
||||
: IF LPAREN expr RPAREN stmt ELSE stmt
|
||||
{ $$ = std::make_unique<ast::stmt_ifelse>(@$, std::move($3), std::move($5), std::move($7)); }
|
||||
;
|
||||
|
||||
stmt_while
|
||||
: WHILE LPAREN expr RPAREN stmt
|
||||
{ $$ = std::make_unique<ast::stmt_while>(@$, std::move($3), std::move($5)); }
|
||||
;
|
||||
|
||||
stmt_dowhile
|
||||
: DO stmt WHILE LPAREN expr RPAREN SEMICOLON
|
||||
{ $$ = std::make_unique<ast::stmt_dowhile>(@$, std::move($5), std::move($2)); }
|
||||
;
|
||||
|
||||
stmt_for
|
||||
: FOR LPAREN stmt_expr SEMICOLON expr_or_empty SEMICOLON stmt_expr RPAREN stmt
|
||||
{ $$ = std::make_unique<ast::stmt_for>(@$, ast::stmt(std::move($3)), std::move($5), ast::stmt(std::move($7)), std::move($9)); }
|
||||
;
|
||||
|
||||
stmt_foreach
|
||||
: FOREACH LPAREN expr_identifier IN expr RPAREN stmt
|
||||
{ $$ = std::make_unique<ast::stmt_foreach>(@$, ast::expr(std::move($3)), std::move($5), std::move($7)); }
|
||||
| FOREACH LPAREN expr_identifier COMMA expr_identifier IN expr RPAREN stmt
|
||||
{ $$ = std::make_unique<ast::stmt_foreach>(@$, ast::expr(std::move($3)), ast::expr(std::move($5)), std::move($7), std::move($9)); }
|
||||
;
|
||||
|
||||
stmt_switch
|
||||
: SWITCH LPAREN expr RPAREN stmt_block
|
||||
{ $$ = std::make_unique<ast::stmt_switch>(@$, std::move($3), std::move($5)); }
|
||||
;
|
||||
|
||||
stmt_case
|
||||
: CASE expr_integer COLON
|
||||
{ $$ = std::make_unique<ast::stmt_case>(@$, ast::expr(std::move($2)), std::make_unique<ast::stmt_list>(@$)); }
|
||||
| CASE expr_string COLON
|
||||
{ $$ = std::make_unique<ast::stmt_case>(@$, ast::expr(std::move($2)), std::make_unique<ast::stmt_list>(@$)); }
|
||||
;
|
||||
|
||||
stmt_default
|
||||
: DEFAULT COLON
|
||||
{ $$ = std::make_unique<ast::stmt_default>(@$, std::make_unique<ast::stmt_list>(@$)); }
|
||||
;
|
||||
|
||||
stmt_break
|
||||
: BREAK SEMICOLON
|
||||
{ $$ = std::make_unique<ast::stmt_break>(@$); }
|
||||
;
|
||||
|
||||
stmt_continue
|
||||
: CONTINUE SEMICOLON
|
||||
{ $$ = std::make_unique<ast::stmt_continue>(@$); }
|
||||
;
|
||||
|
||||
stmt_return
|
||||
: RETURN expr SEMICOLON
|
||||
{ $$ = std::make_unique<ast::stmt_return>(@$, std::move($2)); }
|
||||
| RETURN SEMICOLON
|
||||
{ $$ = std::make_unique<ast::stmt_return>(@$, std::make_unique<ast::node>(@$)); }
|
||||
;
|
||||
|
||||
stmt_breakpoint
|
||||
: BREAKPOINT SEMICOLON
|
||||
{ $$ = std::make_unique<ast::stmt_breakpoint>(@$); }
|
||||
;
|
||||
|
||||
stmt_prof_begin
|
||||
: PROFBEGIN LPAREN expr_arguments RPAREN SEMICOLON
|
||||
{ $$ = std::make_unique<ast::stmt_prof_begin>(@$, std::move($3)); }
|
||||
;
|
||||
|
||||
stmt_prof_end
|
||||
: PROFEND LPAREN expr_arguments RPAREN SEMICOLON
|
||||
{ $$ = std::make_unique<ast::stmt_prof_end>(@$, std::move($3)); }
|
||||
;
|
||||
|
||||
expr
|
||||
: expr_ternary { $$ = std::move($1); }
|
||||
| expr_binary { $$ = std::move($1); }
|
||||
| expr_primitive { $$ = std::move($1); }
|
||||
;
|
||||
|
||||
expr_or_empty
|
||||
: expr { $$ = std::move($1); }
|
||||
| { $$.as_node = std::make_unique<ast::node>(@$); }
|
||||
;
|
||||
|
||||
expr_assign
|
||||
: expr_tuple ASSIGN expr
|
||||
{ $$.as_node = std::make_unique<ast::expr_assign_equal>(@$, std::move($1), std::move($3)); }
|
||||
| expr_object ASSIGN expr
|
||||
{ $$.as_node = std::make_unique<ast::expr_assign_equal>(@$, std::move($1), std::move($3)); }
|
||||
| expr_object ASSIGN_BW_OR expr
|
||||
{ $$.as_node = std::make_unique<ast::expr_assign_bitwise_or>(@$, std::move($1), std::move($3)); }
|
||||
| expr_object ASSIGN_BW_AND expr
|
||||
{ $$.as_node = std::make_unique<ast::expr_assign_bitwise_and>(@$, std::move($1), std::move($3)); }
|
||||
| expr_object ASSIGN_BW_EXOR expr
|
||||
{ $$.as_node = std::make_unique<ast::expr_assign_bitwise_exor>(@$, std::move($1), std::move($3)); }
|
||||
| expr_object ASSIGN_LSHIFT expr
|
||||
{ $$.as_node = std::make_unique<ast::expr_assign_shift_left>(@$, std::move($1),std::move( $3)); }
|
||||
| expr_object ASSIGN_RSHIFT expr
|
||||
{ $$.as_node = std::make_unique<ast::expr_assign_shift_right>(@$, std::move($1), std::move($3)); }
|
||||
| expr_object ASSIGN_ADD expr
|
||||
{ $$.as_node = std::make_unique<ast::expr_assign_add>(@$, std::move($1), std::move($3)); }
|
||||
| expr_object ASSIGN_SUB expr
|
||||
{ $$.as_node = std::make_unique<ast::expr_assign_sub>(@$, std::move($1), std::move($3)); }
|
||||
| expr_object ASSIGN_MUL expr
|
||||
{ $$.as_node = std::make_unique<ast::expr_assign_mul>(@$, std::move($1), std::move($3)); }
|
||||
| expr_object ASSIGN_DIV expr
|
||||
{ $$.as_node = std::make_unique<ast::expr_assign_div>(@$, std::move($1), std::move($3)); }
|
||||
| expr_object ASSIGN_MOD expr
|
||||
{ $$.as_node = std::make_unique<ast::expr_assign_mod>(@$, std::move($1), std::move($3)); }
|
||||
;
|
||||
|
||||
expr_increment
|
||||
: INCREMENT expr_object %prec PREINC
|
||||
{ $$.as_node = std::make_unique<ast::expr_increment>(@$, std::move($2), true); }
|
||||
| expr_object INCREMENT %prec POSTINC
|
||||
{ $$.as_node = std::make_unique<ast::expr_increment>(@$, std::move($1), false); }
|
||||
;
|
||||
|
||||
expr_decrement
|
||||
: DECREMENT expr_object %prec PREDEC
|
||||
{ $$.as_node = std::make_unique<ast::expr_decrement>(@$, std::move($2), true); }
|
||||
| expr_object DECREMENT %prec POSTDEC
|
||||
{ $$.as_node = std::make_unique<ast::expr_decrement>(@$, std::move($1), false); }
|
||||
;
|
||||
|
||||
expr_ternary
|
||||
: expr QMARK expr COLON expr %prec TERN
|
||||
{ $$.as_node = std::make_unique<ast::expr_ternary>(@$, std::move($1), std::move($3), std::move($5)); }
|
||||
;
|
||||
|
||||
expr_binary
|
||||
: expr OR expr
|
||||
{ $$.as_node = std::make_unique<ast::expr_or>(@$, std::move($1), std::move($3)); }
|
||||
| expr AND expr
|
||||
{ $$.as_node = std::make_unique<ast::expr_and>(@$, std::move($1), std::move($3)); }
|
||||
| expr EQUALITY expr
|
||||
{ $$.as_node = std::make_unique<ast::expr_equality>(@$, std::move($1), std::move($3)); }
|
||||
| expr INEQUALITY expr
|
||||
{ $$.as_node = std::make_unique<ast::expr_inequality>(@$, std::move($1), std::move($3)); }
|
||||
| expr LESS_EQUAL expr
|
||||
{ $$.as_node = std::make_unique<ast::expr_less_equal>(@$, std::move($1), std::move($3)); }
|
||||
| expr GREATER_EQUAL expr
|
||||
{ $$.as_node = std::make_unique<ast::expr_greater_equal>(@$, std::move($1), std::move($3)); }
|
||||
| expr LESS expr
|
||||
{ $$.as_node = std::make_unique<ast::expr_less>(@$, std::move($1), std::move($3)); }
|
||||
| expr GREATER expr
|
||||
{ $$.as_node = std::make_unique<ast::expr_greater>(@$, std::move($1), std::move($3)); }
|
||||
| expr BITWISE_OR expr
|
||||
{ $$.as_node = std::make_unique<ast::expr_bitwise_or>(@$, std::move($1), std::move($3)); }
|
||||
| expr BITWISE_AND expr
|
||||
{ $$.as_node = std::make_unique<ast::expr_bitwise_and>(@$, std::move($1), std::move($3)); }
|
||||
| expr BITWISE_EXOR expr
|
||||
{ $$.as_node = std::make_unique<ast::expr_bitwise_exor>(@$, std::move($1), std::move($3)); }
|
||||
| expr LSHIFT expr
|
||||
{ $$.as_node = std::make_unique<ast::expr_shift_left>(@$, std::move($1), std::move($3)); }
|
||||
| expr RSHIFT expr
|
||||
{ $$.as_node = std::make_unique<ast::expr_shift_right>(@$, std::move($1), std::move($3)); }
|
||||
| expr ADD expr
|
||||
{ $$.as_node = std::make_unique<ast::expr_add>(@$, std::move($1), std::move($3)); }
|
||||
| expr SUB expr
|
||||
{ $$.as_node = std::make_unique<ast::expr_sub>(@$, std::move($1), std::move($3)); }
|
||||
| expr MUL expr
|
||||
{ $$.as_node = std::make_unique<ast::expr_mul>(@$, std::move($1), std::move($3)); }
|
||||
| expr DIV expr
|
||||
{ $$.as_node = std::make_unique<ast::expr_div>(@$, std::move($1), std::move($3)); }
|
||||
| expr MOD expr
|
||||
{ $$.as_node = std::make_unique<ast::expr_mod>(@$, std::move($1), std::move($3)); }
|
||||
;
|
||||
|
||||
expr_primitive
|
||||
: expr_complement { $$.as_node = std::move($1); }
|
||||
| expr_negate { $$.as_node = std::move($1); }
|
||||
| expr_not { $$.as_node = std::move($1); }
|
||||
| expr_call { $$.as_node = std::move($1); }
|
||||
| expr_method { $$.as_node = std::move($1); }
|
||||
| expr_add_array { $$.as_node = std::move($1); }
|
||||
| expr_reference { $$.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); }
|
||||
| expr_paren { $$.as_node = std::move($1); }
|
||||
| expr_thisthread { $$.as_node = std::move($1); }
|
||||
| expr_empty_array { $$.as_node = std::move($1); }
|
||||
| expr_undefined { $$.as_node = std::move($1); }
|
||||
| expr_game { $$.as_node = std::move($1); }
|
||||
| expr_self { $$.as_node = std::move($1); }
|
||||
| expr_anim { $$.as_node = std::move($1); }
|
||||
| expr_level { $$.as_node = std::move($1); }
|
||||
| expr_animation { $$.as_node = std::move($1); }
|
||||
| expr_animtree { $$.as_node = std::move($1); }
|
||||
| expr_identifier { $$.as_node = std::move($1); }
|
||||
| expr_istring { $$.as_node = std::move($1); }
|
||||
| expr_string { $$.as_node = std::move($1); }
|
||||
| expr_vector { $$.as_node = std::move($1); }
|
||||
| expr_float { $$.as_node = std::move($1); }
|
||||
| expr_integer { $$.as_node = std::move($1); }
|
||||
| expr_false { $$.as_node = std::move($1); }
|
||||
| expr_true { $$.as_node = std::move($1); }
|
||||
;
|
||||
|
||||
expr_complement
|
||||
: COMPLEMENT expr
|
||||
{ $$ = std::make_unique<ast::expr_complement>(@$, std::move($2)); }
|
||||
;
|
||||
|
||||
expr_negate
|
||||
: SUB expr_identifier %prec NEG
|
||||
{ $$ = std::make_unique<ast::expr_negate>(@$, ast::expr(std::move($2))); }
|
||||
| SUB expr_paren %prec NEG
|
||||
{ $$ = std::make_unique<ast::expr_negate>(@$, ast::expr(std::move($2))); }
|
||||
| SUB expr_array %prec NEG
|
||||
{ $$ = std::make_unique<ast::expr_negate>(@$, ast::expr(std::move($2))); }
|
||||
| SUB expr_field %prec NEG
|
||||
{ $$ = std::make_unique<ast::expr_negate>(@$, ast::expr(std::move($2))); }
|
||||
;
|
||||
|
||||
expr_not
|
||||
: NOT expr
|
||||
{ $$ = std::make_unique<ast::expr_not>(@$, std::move($2)); }
|
||||
;
|
||||
|
||||
expr_call
|
||||
: expr_function { $$ = std::make_unique<ast::expr_call>(@$, std::move($1)); }
|
||||
| expr_pointer { $$ = std::make_unique<ast::expr_call>(@$, std::move($1)); }
|
||||
;
|
||||
expr_method
|
||||
: expr_object expr_function { $$ = std::make_unique<ast::expr_method>(@$, std::move($1), std::move($2)); }
|
||||
| expr_object expr_pointer { $$ = std::make_unique<ast::expr_method>(@$, std::move($1), std::move($2)); }
|
||||
;
|
||||
|
||||
expr_function
|
||||
: expr_identifier LPAREN expr_arguments RPAREN
|
||||
{ $$.as_function = std::make_unique<ast::expr_function>(@$, std::make_unique<ast::expr_path>(@$), std::move($1), std::move($3), ast::call::mode::normal); }
|
||||
| expr_path DOUBLECOLON expr_identifier LPAREN expr_arguments RPAREN
|
||||
{ $$.as_function = std::make_unique<ast::expr_function>(@$, std::move($1), std::move($3), std::move($5), ast::call::mode::normal); }
|
||||
| THREAD expr_identifier LPAREN expr_arguments RPAREN
|
||||
{ $$.as_function = std::make_unique<ast::expr_function>(@$, std::make_unique<ast::expr_path>(@$), std::move($2), std::move($4), ast::call::mode::thread); }
|
||||
| THREAD expr_path DOUBLECOLON expr_identifier LPAREN expr_arguments RPAREN
|
||||
{ $$.as_function = std::make_unique<ast::expr_function>(@$, std::move($2), std::move($4), std::move($6), ast::call::mode::thread); }
|
||||
| CHILDTHREAD expr_identifier LPAREN expr_arguments RPAREN
|
||||
{ $$.as_function = std::make_unique<ast::expr_function>(@$, std::make_unique<ast::expr_path>(@$), std::move($2), std::move($4), ast::call::mode::childthread); }
|
||||
| CHILDTHREAD expr_path DOUBLECOLON expr_identifier LPAREN expr_arguments RPAREN
|
||||
{ $$.as_function = std::make_unique<ast::expr_function>(@$, std::move($2), std::move($4), std::move($6), ast::call::mode::childthread); }
|
||||
;
|
||||
|
||||
expr_pointer
|
||||
: LBRACKET LBRACKET expr RBRACKET RBRACKET LPAREN expr_arguments RPAREN
|
||||
{ $$.as_pointer = std::make_unique<ast::expr_pointer>(@$, std::move($3), std::move($7), ast::call::mode::normal); }
|
||||
| THREAD LBRACKET LBRACKET expr RBRACKET RBRACKET LPAREN expr_arguments RPAREN
|
||||
{ $$.as_pointer = std::make_unique<ast::expr_pointer>(@$, std::move($4), std::move($8), ast::call::mode::thread); }
|
||||
| CHILDTHREAD LBRACKET LBRACKET expr RBRACKET RBRACKET LPAREN expr_arguments RPAREN
|
||||
{ $$.as_pointer = std::make_unique<ast::expr_pointer>(@$, std::move($4), std::move($8), ast::call::mode::childthread); }
|
||||
| CALL LBRACKET LBRACKET expr RBRACKET RBRACKET LPAREN expr_arguments RPAREN
|
||||
{ $$.as_pointer = std::make_unique<ast::expr_pointer>(@$, std::move($4), std::move($8), ast::call::mode::builtin); }
|
||||
;
|
||||
|
||||
expr_add_array
|
||||
: LBRACKET expr_arguments_no_empty RBRACKET
|
||||
{ $$ = std::make_unique<ast::expr_add_array>(@$, std::move($2)); }
|
||||
;
|
||||
|
||||
expr_parameters
|
||||
: expr_parameters COMMA expr_identifier
|
||||
{ $$ = std::move($1); $$->list.push_back(std::move($3)); }
|
||||
| expr_identifier
|
||||
{ $$ = std::make_unique<ast::expr_parameters>(@$); $$->list.push_back(std::move($1)); }
|
||||
|
|
||||
{ $$ = std::make_unique<ast::expr_parameters>(@$); }
|
||||
;
|
||||
|
||||
expr_arguments
|
||||
: expr_arguments_no_empty
|
||||
{ $$ = std::move($1); }
|
||||
|
|
||||
{ $$ = std::make_unique<ast::expr_arguments>(@$); }
|
||||
;
|
||||
|
||||
expr_arguments_no_empty
|
||||
: expr_arguments COMMA expr
|
||||
{ $$ = std::move($1); $$->list.push_back(std::move($3)); }
|
||||
| expr %prec ADD_ARRAY
|
||||
{ $$ = std::make_unique<ast::expr_arguments>(@$); $$->list.push_back(std::move($1)); }
|
||||
;
|
||||
|
||||
expr_reference
|
||||
: DOUBLECOLON expr_identifier
|
||||
{ $$ = std::make_unique<ast::expr_reference>(@$, std::make_unique<ast::expr_path>(@$), std::move($2)); }
|
||||
| expr_path DOUBLECOLON expr_identifier
|
||||
{ $$ = std::make_unique<ast::expr_reference>(@$, std::move($1), std::move($3)); }
|
||||
;
|
||||
|
||||
expr_tuple
|
||||
: LBRACKET expr_tuple_arguments RBRACKET
|
||||
{ $$.as_node = std::move($2); }
|
||||
;
|
||||
|
||||
expr_tuple_arguments
|
||||
: expr_tuple_arguments COMMA expr_tuple_types
|
||||
{ $$ = std::move($1); $$->list.push_back(std::move($3)); }
|
||||
| expr_tuple_types
|
||||
{ $$ = std::make_unique<ast::expr_tuple>(@$); $$->list.push_back(std::move($1)); }
|
||||
;
|
||||
|
||||
expr_tuple_types
|
||||
: expr_array { $$.as_node = std::move($1); }
|
||||
| expr_field { $$.as_node = std::move($1); }
|
||||
| expr_identifier { $$.as_node = std::move($1); }
|
||||
;
|
||||
|
||||
expr_array
|
||||
: expr_object LBRACKET expr RBRACKET
|
||||
{ $$ = std::make_unique<ast::expr_array>(@$, std::move($1), std::move($3)); }
|
||||
;
|
||||
|
||||
expr_field
|
||||
: expr_object DOT expr_identifier_nosize
|
||||
{ $$ = std::make_unique<ast::expr_field>(@$, std::move($1), std::move($3)); }
|
||||
;
|
||||
|
||||
expr_size
|
||||
: expr_object DOT SIZE %prec SIZEOF
|
||||
{ $$ = std::make_unique<ast::expr_size>(@$, std::move($1)); }
|
||||
;
|
||||
|
||||
expr_paren
|
||||
: LPAREN expr RPAREN
|
||||
{ $$ = std::make_unique<ast::expr_paren>(@$, std::move($2)); }
|
||||
;
|
||||
|
||||
expr_object
|
||||
: expr_call { $$.as_node = std::move($1); }
|
||||
| expr_method { $$.as_node = std::move($1); }
|
||||
| expr_array { $$.as_node = std::move($1); }
|
||||
| expr_field { $$.as_node = std::move($1); }
|
||||
| expr_game { $$.as_node = std::move($1); }
|
||||
| expr_self { $$.as_node = std::move($1); }
|
||||
| expr_anim { $$.as_node = std::move($1); }
|
||||
| expr_level { $$.as_node = std::move($1); }
|
||||
| expr_identifier { $$.as_node = std::move($1); }
|
||||
;
|
||||
|
||||
expr_thisthread
|
||||
: THISTHREAD
|
||||
{ $$ = std::make_unique<ast::expr_thisthread>(@$); };
|
||||
;
|
||||
|
||||
expr_empty_array
|
||||
: LBRACKET RBRACKET
|
||||
{ $$ = std::make_unique<ast::expr_empty_array>(@$); };
|
||||
;
|
||||
|
||||
expr_undefined
|
||||
: UNDEFINED
|
||||
{ $$ = std::make_unique<ast::expr_undefined>(@$); };
|
||||
;
|
||||
|
||||
expr_game
|
||||
: GAME
|
||||
{ $$ = std::make_unique<ast::expr_game>(@$); };
|
||||
;
|
||||
|
||||
expr_self
|
||||
: SELF
|
||||
{ $$ = std::make_unique<ast::expr_self>(@$); };
|
||||
;
|
||||
|
||||
expr_anim
|
||||
: ANIM
|
||||
{ $$ = std::make_unique<ast::expr_anim>(@$); };
|
||||
;
|
||||
|
||||
expr_level
|
||||
: LEVEL
|
||||
{ $$ = std::make_unique<ast::expr_level>(@$); };
|
||||
;
|
||||
|
||||
expr_animation
|
||||
: MOD IDENTIFIER %prec ANIMREF
|
||||
{ $$ = std::make_unique<ast::expr_animation>(@$, $2); };
|
||||
;
|
||||
|
||||
expr_animtree
|
||||
: ANIMTREE
|
||||
{ $$ = std::make_unique<ast::expr_animtree>(@$); };
|
||||
;
|
||||
|
||||
expr_identifier_nosize
|
||||
: IDENTIFIER
|
||||
{ $$ = std::make_unique<ast::expr_identifier>(@$, $1); };
|
||||
;
|
||||
|
||||
expr_identifier
|
||||
: IDENTIFIER
|
||||
{ $$ = std::make_unique<ast::expr_identifier>(@$, $1); };
|
||||
| SIZE
|
||||
{ $$ = std::make_unique<ast::expr_identifier>(@$, "size"); };
|
||||
;
|
||||
|
||||
expr_path
|
||||
: IDENTIFIER
|
||||
{ $$ = std::make_unique<ast::expr_path>(@$, $1); };
|
||||
| PATH
|
||||
{ $$ = std::make_unique<ast::expr_path>(@$, $1); };
|
||||
;
|
||||
|
||||
expr_istring
|
||||
: ISTRING
|
||||
{ $$ = std::make_unique<ast::expr_istring>(@$, $1); };
|
||||
;
|
||||
|
||||
expr_string
|
||||
: STRING
|
||||
{ $$ = std::make_unique<ast::expr_string>(@$, $1); };
|
||||
;
|
||||
|
||||
expr_vector
|
||||
: LPAREN expr COMMA expr COMMA expr RPAREN
|
||||
{ $$ = std::make_unique<ast::expr_vector>(@$, std::move($2), std::move($4), std::move($6)); };
|
||||
;
|
||||
|
||||
expr_float
|
||||
: SUB FLOAT %prec NEG
|
||||
{ $$ = std::make_unique<ast::expr_float>(@$, "-" + $2); };
|
||||
| FLOAT
|
||||
{ $$ = std::make_unique<ast::expr_float>(@$, $1); };
|
||||
;
|
||||
|
||||
expr_integer
|
||||
: SUB INTEGER %prec NEG
|
||||
{ $$ = std::make_unique<ast::expr_integer>(@$, "-" + $2); };
|
||||
| INTEGER
|
||||
{ $$ = std::make_unique<ast::expr_integer>(@$, $1); };
|
||||
;
|
||||
|
||||
expr_false
|
||||
: FALSE
|
||||
{ $$ = std::make_unique<ast::expr_false>(@$); };
|
||||
;
|
||||
|
||||
expr_true
|
||||
: TRUE
|
||||
{ $$ = std::make_unique<ast::expr_true>(@$); };
|
||||
;
|
||||
|
||||
%%
|
||||
|
||||
void xsk::gsc::iw6c::parser::error(const xsk::gsc::location& loc, const std::string& msg)
|
||||
{
|
||||
throw xsk::gsc::comp_error(loc, msg);
|
||||
}
|
@ -1,9 +0,0 @@
|
||||
generate: s1c
|
||||
|
||||
clean:
|
||||
rm -rf ./parser.hpp
|
||||
rm -rf ./parser.cpp
|
||||
|
||||
s1c: parser.ypp
|
||||
bison parser.ypp -Wcounterexamples
|
||||
mv parser.hpp parser.cpp ../../../src/experimental/s1c/xsk/
|
@ -1,898 +0,0 @@
|
||||
/* Copyright 2022 xensik. All rights reserved.
|
||||
//
|
||||
// Use of this source code is governed by a GNU GPLv3 license
|
||||
// that can be found in the LICENSE file.
|
||||
*/
|
||||
|
||||
%require "3.7"
|
||||
%skeleton "lalr1.cc"
|
||||
%language "c++"
|
||||
%output "parser.cpp"
|
||||
%defines "parser.hpp"
|
||||
%define api.prefix {S1C}
|
||||
%define api.namespace {xsk::gsc::s1c}
|
||||
%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 { xsk::gsc::s1c::lexer& lexer }
|
||||
%parse-param { xsk::gsc::s1c::lexer& lexer }
|
||||
%parse-param { xsk::gsc::ast::program::ptr& ast }
|
||||
|
||||
%code requires
|
||||
{
|
||||
#ifdef _MSC_VER
|
||||
#pragma warning(disable:4065)
|
||||
#pragma warning(disable:4127)
|
||||
#endif
|
||||
#include "s1c.hpp"
|
||||
namespace xsk::gsc::s1c { class lexer; }
|
||||
}
|
||||
|
||||
%code top
|
||||
{
|
||||
#include "stdafx.hpp"
|
||||
#include "parser.hpp"
|
||||
#include "lexer.hpp"
|
||||
using namespace xsk::gsc;
|
||||
xsk::gsc::s1c::parser::symbol_type S1Clex(xsk::gsc::s1c::lexer& lexer);
|
||||
}
|
||||
|
||||
%token SH_DEFINE "#define"
|
||||
%token SH_UNDEF "#undef"
|
||||
%token SH_IFDEF "#ifdef"
|
||||
%token SH_IFNDEF "#ifndef"
|
||||
%token SH_IF "#if"
|
||||
%token SH_ELIF "#elif"
|
||||
%token SH_ELSE "#else"
|
||||
%token SH_ENDIF "#endif"
|
||||
%token DEVBEGIN "/#"
|
||||
%token DEVEND "#/"
|
||||
%token INLINE "#inline"
|
||||
%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 DO "do"
|
||||
%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 BREAKPOINT "breakpoint"
|
||||
%token PROFBEGIN "prof_begin"
|
||||
%token PROFEND "prof_end"
|
||||
%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_MUL "*="
|
||||
%token ASSIGN_DIV "/="
|
||||
%token ASSIGN_MOD "%="
|
||||
%token ASSIGN_BW_OR "|="
|
||||
%token ASSIGN_BW_AND "&="
|
||||
%token ASSIGN_BW_EXOR "^="
|
||||
%token ASSIGN_RSHIFT ">>="
|
||||
%token ASSIGN_LSHIFT "<<="
|
||||
%token BITWISE_OR "|"
|
||||
%token BITWISE_AND "&"
|
||||
%token BITWISE_EXOR "^"
|
||||
%token ADD "+"
|
||||
%token SUB "-"
|
||||
%token MUL "*"
|
||||
%token DIV "/"
|
||||
%token MOD "%"
|
||||
%token <std::string> PATH "path"
|
||||
%token <std::string> IDENTIFIER "identifier"
|
||||
%token <std::string> STRING "string literal"
|
||||
%token <std::string> ISTRING "localized string"
|
||||
%token <std::string> FLOAT "float"
|
||||
%token <std::string> INTEGER "integer"
|
||||
|
||||
%type <ast::program::ptr> program
|
||||
%type <ast::include::ptr> include
|
||||
%type <ast::decl> declaration
|
||||
%type <ast::decl_usingtree::ptr> decl_usingtree
|
||||
%type <ast::decl_constant::ptr> decl_constant
|
||||
%type <ast::decl_thread::ptr> decl_thread
|
||||
%type <ast::stmt> stmt
|
||||
%type <ast::stmt> stmt_or_dev
|
||||
%type <ast::stmt_list::ptr> stmt_list
|
||||
%type <ast::stmt_list::ptr> stmt_or_dev_list
|
||||
%type <ast::stmt_dev::ptr> stmt_dev
|
||||
%type <ast::stmt_list::ptr> stmt_block
|
||||
%type <ast::stmt_expr::ptr> stmt_expr
|
||||
%type <ast::stmt_call::ptr> stmt_call
|
||||
%type <ast::stmt_assign::ptr> stmt_assign
|
||||
%type <ast::stmt_endon::ptr> stmt_endon
|
||||
%type <ast::stmt_notify::ptr> stmt_notify
|
||||
%type <ast::stmt_wait::ptr> stmt_wait
|
||||
%type <ast::stmt_waittill::ptr> stmt_waittill
|
||||
%type <ast::stmt_waittillmatch::ptr> stmt_waittillmatch
|
||||
%type <ast::stmt_waittillframeend::ptr> stmt_waittillframeend
|
||||
%type <ast::stmt_waitframe::ptr> stmt_waitframe
|
||||
%type <ast::stmt_if::ptr> stmt_if
|
||||
%type <ast::stmt_ifelse::ptr> stmt_ifelse
|
||||
%type <ast::stmt_while::ptr> stmt_while
|
||||
%type <ast::stmt_dowhile::ptr> stmt_dowhile
|
||||
%type <ast::stmt_for::ptr> stmt_for
|
||||
%type <ast::stmt_foreach::ptr> stmt_foreach
|
||||
%type <ast::stmt_switch::ptr> stmt_switch
|
||||
%type <ast::stmt_case::ptr> stmt_case
|
||||
%type <ast::stmt_default::ptr> stmt_default
|
||||
%type <ast::stmt_break::ptr> stmt_break
|
||||
%type <ast::stmt_continue::ptr> stmt_continue
|
||||
%type <ast::stmt_return::ptr> stmt_return
|
||||
%type <ast::stmt_breakpoint::ptr> stmt_breakpoint
|
||||
%type <ast::stmt_prof_begin::ptr> stmt_prof_begin
|
||||
%type <ast::stmt_prof_end::ptr> stmt_prof_end
|
||||
%type <ast::expr> expr
|
||||
%type <ast::expr> expr_or_empty
|
||||
%type <ast::expr> expr_assign
|
||||
%type <ast::expr> expr_increment
|
||||
%type <ast::expr> expr_decrement
|
||||
%type <ast::expr> expr_ternary
|
||||
%type <ast::expr> expr_binary
|
||||
%type <ast::expr> expr_primitive
|
||||
%type <ast::expr_complement::ptr> expr_complement
|
||||
%type <ast::expr_negate::ptr> expr_negate
|
||||
%type <ast::expr_not::ptr> expr_not
|
||||
%type <ast::expr_call::ptr> expr_call
|
||||
%type <ast::expr_method::ptr> expr_method
|
||||
%type <ast::call> expr_function
|
||||
%type <ast::call> expr_pointer
|
||||
%type <ast::expr_add_array::ptr> expr_add_array
|
||||
%type <ast::expr_parameters::ptr> expr_parameters
|
||||
%type <ast::expr_arguments::ptr> expr_arguments
|
||||
%type <ast::expr_arguments::ptr> expr_arguments_no_empty
|
||||
%type <ast::expr_reference::ptr> expr_reference
|
||||
%type <ast::expr> expr_tuple
|
||||
%type <ast::expr_tuple::ptr> expr_tuple_arguments
|
||||
%type <ast::expr> expr_tuple_types
|
||||
%type <ast::expr_array::ptr> expr_array
|
||||
%type <ast::expr_field::ptr> expr_field
|
||||
%type <ast::expr_size::ptr> expr_size
|
||||
%type <ast::expr_paren::ptr> expr_paren
|
||||
%type <ast::expr> expr_object
|
||||
%type <ast::expr_thisthread::ptr> expr_thisthread
|
||||
%type <ast::expr_empty_array::ptr> expr_empty_array
|
||||
%type <ast::expr_undefined::ptr> expr_undefined
|
||||
%type <ast::expr_game::ptr> expr_game
|
||||
%type <ast::expr_self::ptr> expr_self
|
||||
%type <ast::expr_anim::ptr> expr_anim
|
||||
%type <ast::expr_level::ptr> expr_level
|
||||
%type <ast::expr_animation::ptr> expr_animation
|
||||
%type <ast::expr_animtree::ptr> expr_animtree
|
||||
%type <ast::expr_identifier::ptr> expr_identifier_nosize
|
||||
%type <ast::expr_identifier::ptr> expr_identifier
|
||||
%type <ast::expr_path::ptr> expr_path
|
||||
%type <ast::expr_istring::ptr> expr_istring
|
||||
%type <ast::expr_string::ptr> expr_string
|
||||
%type <ast::expr_vector::ptr> expr_vector
|
||||
%type <ast::expr_float::ptr> expr_float
|
||||
%type <ast::expr_integer::ptr> expr_integer
|
||||
%type <ast::expr_false::ptr> expr_false
|
||||
%type <ast::expr_true::ptr> expr_true
|
||||
|
||||
%nonassoc SIZEOF
|
||||
%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_EXOR
|
||||
%left BITWISE_AND
|
||||
%left EQUALITY INEQUALITY
|
||||
%left LESS GREATER LESS_EQUAL GREATER_EQUAL
|
||||
%left LSHIFT RSHIFT
|
||||
%left ADD SUB
|
||||
%left MUL 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<ast::program>(@$); }
|
||||
;
|
||||
|
||||
program
|
||||
: program inline
|
||||
{ $$ = std::move($1); }
|
||||
| program include
|
||||
{ $$ = std::move($1); $$->includes.push_back(std::move($2)); }
|
||||
| program declaration
|
||||
{ $$ = std::move($1); $$->declarations.push_back(std::move($2)); }
|
||||
| inline
|
||||
{ $$ = std::make_unique<ast::program>(@$); }
|
||||
| include
|
||||
{ $$ = std::make_unique<ast::program>(@$); $$->includes.push_back(std::move($1)); }
|
||||
| declaration
|
||||
{ $$ = std::make_unique<ast::program>(@$); $$->declarations.push_back(std::move($1)); }
|
||||
;
|
||||
|
||||
inline
|
||||
: INLINE expr_path SEMICOLON { lexer.push_header($2->value); }
|
||||
;
|
||||
|
||||
include
|
||||
: INCLUDE expr_path SEMICOLON
|
||||
{ $$ = std::make_unique<ast::include>(@$, std::move($2)); }
|
||||
;
|
||||
|
||||
declaration
|
||||
: DEVBEGIN { $$.as_dev_begin = std::make_unique<ast::decl_dev_begin>(@$); }
|
||||
| DEVEND { $$.as_dev_end = std::make_unique<ast::decl_dev_end>(@$); }
|
||||
| decl_usingtree { $$.as_usingtree = std::move($1); }
|
||||
| decl_constant { $$.as_constant = std::move($1); }
|
||||
| decl_thread { $$.as_thread = std::move($1); }
|
||||
;
|
||||
|
||||
decl_usingtree
|
||||
: USINGTREE LPAREN expr_string RPAREN SEMICOLON
|
||||
{ lexer.ban_header(@$); $$ = std::make_unique<ast::decl_usingtree>(@$, std::move($3)); }
|
||||
;
|
||||
|
||||
decl_constant
|
||||
: expr_identifier ASSIGN expr SEMICOLON
|
||||
{ $$ = std::make_unique<ast::decl_constant>(@$, std::move($1), std::move($3)); }
|
||||
;
|
||||
|
||||
decl_thread
|
||||
: expr_identifier LPAREN expr_parameters RPAREN stmt_block
|
||||
{ lexer.ban_header(@$); $$ = std::make_unique<ast::decl_thread>(@$, std::move($1), std::move($3), std::move($5)); }
|
||||
;
|
||||
|
||||
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_dowhile { $$.as_dowhile = 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_breakpoint { $$.as_breakpoint = std::move($1); }
|
||||
| stmt_prof_begin { $$.as_prof_begin = std::move($1); }
|
||||
| stmt_prof_end { $$.as_prof_end = std::move($1); }
|
||||
;
|
||||
|
||||
stmt_or_dev
|
||||
: stmt { $$ = std::move($1); }
|
||||
| stmt_dev { $$.as_dev = std::move($1); }
|
||||
;
|
||||
|
||||
stmt_list
|
||||
: stmt_list stmt
|
||||
{ $$ = std::move($1); $$->list.push_back(std::move($2)); }
|
||||
| stmt
|
||||
{ $$ = std::make_unique<ast::stmt_list>(@$); $$->list.push_back(std::move($1)); }
|
||||
;
|
||||
|
||||
stmt_or_dev_list
|
||||
: stmt_or_dev_list stmt_or_dev
|
||||
{ $$ = std::move($1); $$->list.push_back(std::move($2)); }
|
||||
| stmt_or_dev
|
||||
{ $$ = std::make_unique<ast::stmt_list>(@$); $$->list.push_back(std::move($1)); }
|
||||
;
|
||||
|
||||
stmt_dev
|
||||
: DEVBEGIN stmt_list DEVEND { $$ = std::make_unique<ast::stmt_dev>(@$, std::move($2)); }
|
||||
| DEVBEGIN DEVEND { $$ = std::make_unique<ast::stmt_dev>(@$, std::make_unique<ast::stmt_list>(@$)); }
|
||||
;
|
||||
|
||||
stmt_block
|
||||
: LBRACE stmt_or_dev_list RBRACE { $$ = std::move($2); }
|
||||
| LBRACE RBRACE { $$ = std::make_unique<ast::stmt_list>(@$); }
|
||||
;
|
||||
|
||||
stmt_expr
|
||||
: expr_assign
|
||||
{ $$ = std::make_unique<ast::stmt_expr>(@$, std::move($1)); }
|
||||
| expr_increment
|
||||
{ $$ = std::make_unique<ast::stmt_expr>(@$, std::move($1)); }
|
||||
| expr_decrement
|
||||
{ $$ = std::make_unique<ast::stmt_expr>(@$, std::move($1)); }
|
||||
|
|
||||
{ $$ = std::make_unique<ast::stmt_expr>(@$, std::make_unique<ast::node>(@$)); }
|
||||
;
|
||||
|
||||
stmt_call
|
||||
: expr_call SEMICOLON
|
||||
{ $$ = std::make_unique<ast::stmt_call>(@$, ast::expr(std::move($1))); }
|
||||
| expr_method SEMICOLON
|
||||
{ $$ = std::make_unique<ast::stmt_call>(@$, ast::expr(std::move($1))); }
|
||||
;
|
||||
|
||||
stmt_assign
|
||||
: expr_assign SEMICOLON
|
||||
{ $$ = std::make_unique<ast::stmt_assign>(@$, std::move($1)); }
|
||||
| expr_increment SEMICOLON
|
||||
{ $$ = std::make_unique<ast::stmt_assign>(@$, std::move($1)); }
|
||||
| expr_decrement SEMICOLON
|
||||
{ $$ = std::make_unique<ast::stmt_assign>(@$, std::move($1)); }
|
||||
;
|
||||
|
||||
stmt_endon
|
||||
: expr_object ENDON LPAREN expr RPAREN SEMICOLON
|
||||
{ $$ = std::make_unique<ast::stmt_endon>(@$, std::move($1), std::move($4)); }
|
||||
;
|
||||
|
||||
stmt_notify
|
||||
: expr_object NOTIFY LPAREN expr COMMA expr_arguments_no_empty RPAREN SEMICOLON
|
||||
{ $$ = std::make_unique<ast::stmt_notify>(@$, std::move($1), std::move($4), std::move($6)); }
|
||||
| expr_object NOTIFY LPAREN expr RPAREN SEMICOLON
|
||||
{ $$ = std::make_unique<ast::stmt_notify>(@$, std::move($1), std::move($4), std::make_unique<ast::expr_arguments>(@$)); }
|
||||
;
|
||||
|
||||
stmt_wait
|
||||
: WAIT expr SEMICOLON
|
||||
{ $$ = std::make_unique<ast::stmt_wait>(@$, std::move($2)); }
|
||||
;
|
||||
|
||||
stmt_waittill
|
||||
: expr_object WAITTILL LPAREN expr COMMA expr_arguments_no_empty RPAREN SEMICOLON
|
||||
{ $$ = std::make_unique<ast::stmt_waittill>(@$, std::move($1), std::move($4), std::move($6)); }
|
||||
| expr_object WAITTILL LPAREN expr RPAREN SEMICOLON
|
||||
{ $$ = std::make_unique<ast::stmt_waittill>(@$, std::move($1), std::move($4), std::make_unique<ast::expr_arguments>(@$)); }
|
||||
;
|
||||
|
||||
stmt_waittillmatch
|
||||
: expr_object WAITTILLMATCH LPAREN expr COMMA expr_arguments_no_empty RPAREN SEMICOLON
|
||||
{ $$ = std::make_unique<ast::stmt_waittillmatch>(@$, std::move($1), std::move($4), std::move($6)); }
|
||||
| expr_object WAITTILLMATCH LPAREN expr RPAREN SEMICOLON
|
||||
{ $$ = std::make_unique<ast::stmt_waittillmatch>(@$, std::move($1), std::move($4), std::make_unique<ast::expr_arguments>(@$)); }
|
||||
;
|
||||
|
||||
stmt_waittillframeend
|
||||
: WAITTILLFRAMEEND SEMICOLON
|
||||
{ $$ = std::make_unique<ast::stmt_waittillframeend>(@$); }
|
||||
;
|
||||
|
||||
stmt_waitframe
|
||||
: WAITFRAME SEMICOLON
|
||||
{ $$ = std::make_unique<ast::stmt_waitframe>(@$); }
|
||||
| WAITFRAME LPAREN RPAREN SEMICOLON
|
||||
{ $$ = std::make_unique<ast::stmt_waitframe>(@$); }
|
||||
;
|
||||
|
||||
stmt_if
|
||||
: IF LPAREN expr RPAREN stmt %prec THEN
|
||||
{ $$ = std::make_unique<ast::stmt_if>(@$, std::move($3), std::move($5)); }
|
||||
;
|
||||
|
||||
stmt_ifelse
|
||||
: IF LPAREN expr RPAREN stmt ELSE stmt
|
||||
{ $$ = std::make_unique<ast::stmt_ifelse>(@$, std::move($3), std::move($5), std::move($7)); }
|
||||
;
|
||||
|
||||
stmt_while
|
||||
: WHILE LPAREN expr RPAREN stmt
|
||||
{ $$ = std::make_unique<ast::stmt_while>(@$, std::move($3), std::move($5)); }
|
||||
;
|
||||
|
||||
stmt_dowhile
|
||||
: DO stmt WHILE LPAREN expr RPAREN SEMICOLON
|
||||
{ $$ = std::make_unique<ast::stmt_dowhile>(@$, std::move($5), std::move($2)); }
|
||||
;
|
||||
|
||||
stmt_for
|
||||
: FOR LPAREN stmt_expr SEMICOLON expr_or_empty SEMICOLON stmt_expr RPAREN stmt
|
||||
{ $$ = std::make_unique<ast::stmt_for>(@$, ast::stmt(std::move($3)), std::move($5), ast::stmt(std::move($7)), std::move($9)); }
|
||||
;
|
||||
|
||||
stmt_foreach
|
||||
: FOREACH LPAREN expr_identifier IN expr RPAREN stmt
|
||||
{ $$ = std::make_unique<ast::stmt_foreach>(@$, ast::expr(std::move($3)), std::move($5), std::move($7)); }
|
||||
| FOREACH LPAREN expr_identifier COMMA expr_identifier IN expr RPAREN stmt
|
||||
{ $$ = std::make_unique<ast::stmt_foreach>(@$, ast::expr(std::move($3)), ast::expr(std::move($5)), std::move($7), std::move($9)); }
|
||||
;
|
||||
|
||||
stmt_switch
|
||||
: SWITCH LPAREN expr RPAREN stmt_block
|
||||
{ $$ = std::make_unique<ast::stmt_switch>(@$, std::move($3), std::move($5)); }
|
||||
;
|
||||
|
||||
stmt_case
|
||||
: CASE expr_integer COLON
|
||||
{ $$ = std::make_unique<ast::stmt_case>(@$, ast::expr(std::move($2)), std::make_unique<ast::stmt_list>(@$)); }
|
||||
| CASE expr_string COLON
|
||||
{ $$ = std::make_unique<ast::stmt_case>(@$, ast::expr(std::move($2)), std::make_unique<ast::stmt_list>(@$)); }
|
||||
;
|
||||
|
||||
stmt_default
|
||||
: DEFAULT COLON
|
||||
{ $$ = std::make_unique<ast::stmt_default>(@$, std::make_unique<ast::stmt_list>(@$)); }
|
||||
;
|
||||
|
||||
stmt_break
|
||||
: BREAK SEMICOLON
|
||||
{ $$ = std::make_unique<ast::stmt_break>(@$); }
|
||||
;
|
||||
|
||||
stmt_continue
|
||||
: CONTINUE SEMICOLON
|
||||
{ $$ = std::make_unique<ast::stmt_continue>(@$); }
|
||||
;
|
||||
|
||||
stmt_return
|
||||
: RETURN expr SEMICOLON
|
||||
{ $$ = std::make_unique<ast::stmt_return>(@$, std::move($2)); }
|
||||
| RETURN SEMICOLON
|
||||
{ $$ = std::make_unique<ast::stmt_return>(@$, std::make_unique<ast::node>(@$)); }
|
||||
;
|
||||
|
||||
stmt_breakpoint
|
||||
: BREAKPOINT SEMICOLON
|
||||
{ $$ = std::make_unique<ast::stmt_breakpoint>(@$); }
|
||||
;
|
||||
|
||||
stmt_prof_begin
|
||||
: PROFBEGIN LPAREN expr_arguments RPAREN SEMICOLON
|
||||
{ $$ = std::make_unique<ast::stmt_prof_begin>(@$, std::move($3)); }
|
||||
;
|
||||
|
||||
stmt_prof_end
|
||||
: PROFEND LPAREN expr_arguments RPAREN SEMICOLON
|
||||
{ $$ = std::make_unique<ast::stmt_prof_end>(@$, std::move($3)); }
|
||||
;
|
||||
|
||||
expr
|
||||
: expr_ternary { $$ = std::move($1); }
|
||||
| expr_binary { $$ = std::move($1); }
|
||||
| expr_primitive { $$ = std::move($1); }
|
||||
;
|
||||
|
||||
expr_or_empty
|
||||
: expr { $$ = std::move($1); }
|
||||
| { $$.as_node = std::make_unique<ast::node>(@$); }
|
||||
;
|
||||
|
||||
expr_assign
|
||||
: expr_tuple ASSIGN expr
|
||||
{ $$.as_node = std::make_unique<ast::expr_assign_equal>(@$, std::move($1), std::move($3)); }
|
||||
| expr_object ASSIGN expr
|
||||
{ $$.as_node = std::make_unique<ast::expr_assign_equal>(@$, std::move($1), std::move($3)); }
|
||||
| expr_object ASSIGN_BW_OR expr
|
||||
{ $$.as_node = std::make_unique<ast::expr_assign_bitwise_or>(@$, std::move($1), std::move($3)); }
|
||||
| expr_object ASSIGN_BW_AND expr
|
||||
{ $$.as_node = std::make_unique<ast::expr_assign_bitwise_and>(@$, std::move($1), std::move($3)); }
|
||||
| expr_object ASSIGN_BW_EXOR expr
|
||||
{ $$.as_node = std::make_unique<ast::expr_assign_bitwise_exor>(@$, std::move($1), std::move($3)); }
|
||||
| expr_object ASSIGN_LSHIFT expr
|
||||
{ $$.as_node = std::make_unique<ast::expr_assign_shift_left>(@$, std::move($1),std::move( $3)); }
|
||||
| expr_object ASSIGN_RSHIFT expr
|
||||
{ $$.as_node = std::make_unique<ast::expr_assign_shift_right>(@$, std::move($1), std::move($3)); }
|
||||
| expr_object ASSIGN_ADD expr
|
||||
{ $$.as_node = std::make_unique<ast::expr_assign_add>(@$, std::move($1), std::move($3)); }
|
||||
| expr_object ASSIGN_SUB expr
|
||||
{ $$.as_node = std::make_unique<ast::expr_assign_sub>(@$, std::move($1), std::move($3)); }
|
||||
| expr_object ASSIGN_MUL expr
|
||||
{ $$.as_node = std::make_unique<ast::expr_assign_mul>(@$, std::move($1), std::move($3)); }
|
||||
| expr_object ASSIGN_DIV expr
|
||||
{ $$.as_node = std::make_unique<ast::expr_assign_div>(@$, std::move($1), std::move($3)); }
|
||||
| expr_object ASSIGN_MOD expr
|
||||
{ $$.as_node = std::make_unique<ast::expr_assign_mod>(@$, std::move($1), std::move($3)); }
|
||||
;
|
||||
|
||||
expr_increment
|
||||
: INCREMENT expr_object %prec PREINC
|
||||
{ $$.as_node = std::make_unique<ast::expr_increment>(@$, std::move($2), true); }
|
||||
| expr_object INCREMENT %prec POSTINC
|
||||
{ $$.as_node = std::make_unique<ast::expr_increment>(@$, std::move($1), false); }
|
||||
;
|
||||
|
||||
expr_decrement
|
||||
: DECREMENT expr_object %prec PREDEC
|
||||
{ $$.as_node = std::make_unique<ast::expr_decrement>(@$, std::move($2), true); }
|
||||
| expr_object DECREMENT %prec POSTDEC
|
||||
{ $$.as_node = std::make_unique<ast::expr_decrement>(@$, std::move($1), false); }
|
||||
;
|
||||
|
||||
expr_ternary
|
||||
: expr QMARK expr COLON expr %prec TERN
|
||||
{ $$.as_node = std::make_unique<ast::expr_ternary>(@$, std::move($1), std::move($3), std::move($5)); }
|
||||
;
|
||||
|
||||
expr_binary
|
||||
: expr OR expr
|
||||
{ $$.as_node = std::make_unique<ast::expr_or>(@$, std::move($1), std::move($3)); }
|
||||
| expr AND expr
|
||||
{ $$.as_node = std::make_unique<ast::expr_and>(@$, std::move($1), std::move($3)); }
|
||||
| expr EQUALITY expr
|
||||
{ $$.as_node = std::make_unique<ast::expr_equality>(@$, std::move($1), std::move($3)); }
|
||||
| expr INEQUALITY expr
|
||||
{ $$.as_node = std::make_unique<ast::expr_inequality>(@$, std::move($1), std::move($3)); }
|
||||
| expr LESS_EQUAL expr
|
||||
{ $$.as_node = std::make_unique<ast::expr_less_equal>(@$, std::move($1), std::move($3)); }
|
||||
| expr GREATER_EQUAL expr
|
||||
{ $$.as_node = std::make_unique<ast::expr_greater_equal>(@$, std::move($1), std::move($3)); }
|
||||
| expr LESS expr
|
||||
{ $$.as_node = std::make_unique<ast::expr_less>(@$, std::move($1), std::move($3)); }
|
||||
| expr GREATER expr
|
||||
{ $$.as_node = std::make_unique<ast::expr_greater>(@$, std::move($1), std::move($3)); }
|
||||
| expr BITWISE_OR expr
|
||||
{ $$.as_node = std::make_unique<ast::expr_bitwise_or>(@$, std::move($1), std::move($3)); }
|
||||
| expr BITWISE_AND expr
|
||||
{ $$.as_node = std::make_unique<ast::expr_bitwise_and>(@$, std::move($1), std::move($3)); }
|
||||
| expr BITWISE_EXOR expr
|
||||
{ $$.as_node = std::make_unique<ast::expr_bitwise_exor>(@$, std::move($1), std::move($3)); }
|
||||
| expr LSHIFT expr
|
||||
{ $$.as_node = std::make_unique<ast::expr_shift_left>(@$, std::move($1), std::move($3)); }
|
||||
| expr RSHIFT expr
|
||||
{ $$.as_node = std::make_unique<ast::expr_shift_right>(@$, std::move($1), std::move($3)); }
|
||||
| expr ADD expr
|
||||
{ $$.as_node = std::make_unique<ast::expr_add>(@$, std::move($1), std::move($3)); }
|
||||
| expr SUB expr
|
||||
{ $$.as_node = std::make_unique<ast::expr_sub>(@$, std::move($1), std::move($3)); }
|
||||
| expr MUL expr
|
||||
{ $$.as_node = std::make_unique<ast::expr_mul>(@$, std::move($1), std::move($3)); }
|
||||
| expr DIV expr
|
||||
{ $$.as_node = std::make_unique<ast::expr_div>(@$, std::move($1), std::move($3)); }
|
||||
| expr MOD expr
|
||||
{ $$.as_node = std::make_unique<ast::expr_mod>(@$, std::move($1), std::move($3)); }
|
||||
;
|
||||
|
||||
expr_primitive
|
||||
: expr_complement { $$.as_node = std::move($1); }
|
||||
| expr_negate { $$.as_node = std::move($1); }
|
||||
| expr_not { $$.as_node = std::move($1); }
|
||||
| expr_call { $$.as_node = std::move($1); }
|
||||
| expr_method { $$.as_node = std::move($1); }
|
||||
| expr_add_array { $$.as_node = std::move($1); }
|
||||
| expr_reference { $$.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); }
|
||||
| expr_paren { $$.as_node = std::move($1); }
|
||||
| expr_thisthread { $$.as_node = std::move($1); }
|
||||
| expr_empty_array { $$.as_node = std::move($1); }
|
||||
| expr_undefined { $$.as_node = std::move($1); }
|
||||
| expr_game { $$.as_node = std::move($1); }
|
||||
| expr_self { $$.as_node = std::move($1); }
|
||||
| expr_anim { $$.as_node = std::move($1); }
|
||||
| expr_level { $$.as_node = std::move($1); }
|
||||
| expr_animation { $$.as_node = std::move($1); }
|
||||
| expr_animtree { $$.as_node = std::move($1); }
|
||||
| expr_identifier { $$.as_node = std::move($1); }
|
||||
| expr_istring { $$.as_node = std::move($1); }
|
||||
| expr_string { $$.as_node = std::move($1); }
|
||||
| expr_vector { $$.as_node = std::move($1); }
|
||||
| expr_float { $$.as_node = std::move($1); }
|
||||
| expr_integer { $$.as_node = std::move($1); }
|
||||
| expr_false { $$.as_node = std::move($1); }
|
||||
| expr_true { $$.as_node = std::move($1); }
|
||||
;
|
||||
|
||||
expr_complement
|
||||
: COMPLEMENT expr
|
||||
{ $$ = std::make_unique<ast::expr_complement>(@$, std::move($2)); }
|
||||
;
|
||||
|
||||
expr_negate
|
||||
: SUB expr_identifier %prec NEG
|
||||
{ $$ = std::make_unique<ast::expr_negate>(@$, ast::expr(std::move($2))); }
|
||||
| SUB expr_paren %prec NEG
|
||||
{ $$ = std::make_unique<ast::expr_negate>(@$, ast::expr(std::move($2))); }
|
||||
| SUB expr_array %prec NEG
|
||||
{ $$ = std::make_unique<ast::expr_negate>(@$, ast::expr(std::move($2))); }
|
||||
| SUB expr_field %prec NEG
|
||||
{ $$ = std::make_unique<ast::expr_negate>(@$, ast::expr(std::move($2))); }
|
||||
;
|
||||
|
||||
expr_not
|
||||
: NOT expr
|
||||
{ $$ = std::make_unique<ast::expr_not>(@$, std::move($2)); }
|
||||
;
|
||||
|
||||
expr_call
|
||||
: expr_function { $$ = std::make_unique<ast::expr_call>(@$, std::move($1)); }
|
||||
| expr_pointer { $$ = std::make_unique<ast::expr_call>(@$, std::move($1)); }
|
||||
;
|
||||
expr_method
|
||||
: expr_object expr_function { $$ = std::make_unique<ast::expr_method>(@$, std::move($1), std::move($2)); }
|
||||
| expr_object expr_pointer { $$ = std::make_unique<ast::expr_method>(@$, std::move($1), std::move($2)); }
|
||||
;
|
||||
|
||||
expr_function
|
||||
: expr_identifier LPAREN expr_arguments RPAREN
|
||||
{ $$.as_function = std::make_unique<ast::expr_function>(@$, std::make_unique<ast::expr_path>(@$), std::move($1), std::move($3), ast::call::mode::normal); }
|
||||
| expr_path DOUBLECOLON expr_identifier LPAREN expr_arguments RPAREN
|
||||
{ $$.as_function = std::make_unique<ast::expr_function>(@$, std::move($1), std::move($3), std::move($5), ast::call::mode::normal); }
|
||||
| THREAD expr_identifier LPAREN expr_arguments RPAREN
|
||||
{ $$.as_function = std::make_unique<ast::expr_function>(@$, std::make_unique<ast::expr_path>(@$), std::move($2), std::move($4), ast::call::mode::thread); }
|
||||
| THREAD expr_path DOUBLECOLON expr_identifier LPAREN expr_arguments RPAREN
|
||||
{ $$.as_function = std::make_unique<ast::expr_function>(@$, std::move($2), std::move($4), std::move($6), ast::call::mode::thread); }
|
||||
| CHILDTHREAD expr_identifier LPAREN expr_arguments RPAREN
|
||||
{ $$.as_function = std::make_unique<ast::expr_function>(@$, std::make_unique<ast::expr_path>(@$), std::move($2), std::move($4), ast::call::mode::childthread); }
|
||||
| CHILDTHREAD expr_path DOUBLECOLON expr_identifier LPAREN expr_arguments RPAREN
|
||||
{ $$.as_function = std::make_unique<ast::expr_function>(@$, std::move($2), std::move($4), std::move($6), ast::call::mode::childthread); }
|
||||
;
|
||||
|
||||
expr_pointer
|
||||
: LBRACKET LBRACKET expr RBRACKET RBRACKET LPAREN expr_arguments RPAREN
|
||||
{ $$.as_pointer = std::make_unique<ast::expr_pointer>(@$, std::move($3), std::move($7), ast::call::mode::normal); }
|
||||
| THREAD LBRACKET LBRACKET expr RBRACKET RBRACKET LPAREN expr_arguments RPAREN
|
||||
{ $$.as_pointer = std::make_unique<ast::expr_pointer>(@$, std::move($4), std::move($8), ast::call::mode::thread); }
|
||||
| CHILDTHREAD LBRACKET LBRACKET expr RBRACKET RBRACKET LPAREN expr_arguments RPAREN
|
||||
{ $$.as_pointer = std::make_unique<ast::expr_pointer>(@$, std::move($4), std::move($8), ast::call::mode::childthread); }
|
||||
| CALL LBRACKET LBRACKET expr RBRACKET RBRACKET LPAREN expr_arguments RPAREN
|
||||
{ $$.as_pointer = std::make_unique<ast::expr_pointer>(@$, std::move($4), std::move($8), ast::call::mode::builtin); }
|
||||
;
|
||||
|
||||
expr_add_array
|
||||
: LBRACKET expr_arguments_no_empty RBRACKET
|
||||
{ $$ = std::make_unique<ast::expr_add_array>(@$, std::move($2)); }
|
||||
;
|
||||
|
||||
expr_parameters
|
||||
: expr_parameters COMMA expr_identifier
|
||||
{ $$ = std::move($1); $$->list.push_back(std::move($3)); }
|
||||
| expr_identifier
|
||||
{ $$ = std::make_unique<ast::expr_parameters>(@$); $$->list.push_back(std::move($1)); }
|
||||
|
|
||||
{ $$ = std::make_unique<ast::expr_parameters>(@$); }
|
||||
;
|
||||
|
||||
expr_arguments
|
||||
: expr_arguments_no_empty
|
||||
{ $$ = std::move($1); }
|
||||
|
|
||||
{ $$ = std::make_unique<ast::expr_arguments>(@$); }
|
||||
;
|
||||
|
||||
expr_arguments_no_empty
|
||||
: expr_arguments COMMA expr
|
||||
{ $$ = std::move($1); $$->list.push_back(std::move($3)); }
|
||||
| expr %prec ADD_ARRAY
|
||||
{ $$ = std::make_unique<ast::expr_arguments>(@$); $$->list.push_back(std::move($1)); }
|
||||
;
|
||||
|
||||
expr_reference
|
||||
: DOUBLECOLON expr_identifier
|
||||
{ $$ = std::make_unique<ast::expr_reference>(@$, std::make_unique<ast::expr_path>(@$), std::move($2)); }
|
||||
| expr_path DOUBLECOLON expr_identifier
|
||||
{ $$ = std::make_unique<ast::expr_reference>(@$, std::move($1), std::move($3)); }
|
||||
;
|
||||
|
||||
expr_tuple
|
||||
: LBRACKET expr_tuple_arguments RBRACKET
|
||||
{ $$.as_node = std::move($2); }
|
||||
;
|
||||
|
||||
expr_tuple_arguments
|
||||
: expr_tuple_arguments COMMA expr_tuple_types
|
||||
{ $$ = std::move($1); $$->list.push_back(std::move($3)); }
|
||||
| expr_tuple_types
|
||||
{ $$ = std::make_unique<ast::expr_tuple>(@$); $$->list.push_back(std::move($1)); }
|
||||
;
|
||||
|
||||
expr_tuple_types
|
||||
: expr_array { $$.as_node = std::move($1); }
|
||||
| expr_field { $$.as_node = std::move($1); }
|
||||
| expr_identifier { $$.as_node = std::move($1); }
|
||||
;
|
||||
|
||||
expr_array
|
||||
: expr_object LBRACKET expr RBRACKET
|
||||
{ $$ = std::make_unique<ast::expr_array>(@$, std::move($1), std::move($3)); }
|
||||
;
|
||||
|
||||
expr_field
|
||||
: expr_object DOT expr_identifier_nosize
|
||||
{ $$ = std::make_unique<ast::expr_field>(@$, std::move($1), std::move($3)); }
|
||||
;
|
||||
|
||||
expr_size
|
||||
: expr_object DOT SIZE %prec SIZEOF
|
||||
{ $$ = std::make_unique<ast::expr_size>(@$, std::move($1)); }
|
||||
;
|
||||
|
||||
expr_paren
|
||||
: LPAREN expr RPAREN
|
||||
{ $$ = std::make_unique<ast::expr_paren>(@$, std::move($2)); }
|
||||
;
|
||||
|
||||
expr_object
|
||||
: expr_call { $$.as_node = std::move($1); }
|
||||
| expr_method { $$.as_node = std::move($1); }
|
||||
| expr_array { $$.as_node = std::move($1); }
|
||||
| expr_field { $$.as_node = std::move($1); }
|
||||
| expr_game { $$.as_node = std::move($1); }
|
||||
| expr_self { $$.as_node = std::move($1); }
|
||||
| expr_anim { $$.as_node = std::move($1); }
|
||||
| expr_level { $$.as_node = std::move($1); }
|
||||
| expr_identifier { $$.as_node = std::move($1); }
|
||||
;
|
||||
|
||||
expr_thisthread
|
||||
: THISTHREAD
|
||||
{ $$ = std::make_unique<ast::expr_thisthread>(@$); };
|
||||
;
|
||||
|
||||
expr_empty_array
|
||||
: LBRACKET RBRACKET
|
||||
{ $$ = std::make_unique<ast::expr_empty_array>(@$); };
|
||||
;
|
||||
|
||||
expr_undefined
|
||||
: UNDEFINED
|
||||
{ $$ = std::make_unique<ast::expr_undefined>(@$); };
|
||||
;
|
||||
|
||||
expr_game
|
||||
: GAME
|
||||
{ $$ = std::make_unique<ast::expr_game>(@$); };
|
||||
;
|
||||
|
||||
expr_self
|
||||
: SELF
|
||||
{ $$ = std::make_unique<ast::expr_self>(@$); };
|
||||
;
|
||||
|
||||
expr_anim
|
||||
: ANIM
|
||||
{ $$ = std::make_unique<ast::expr_anim>(@$); };
|
||||
;
|
||||
|
||||
expr_level
|
||||
: LEVEL
|
||||
{ $$ = std::make_unique<ast::expr_level>(@$); };
|
||||
;
|
||||
|
||||
expr_animation
|
||||
: MOD IDENTIFIER %prec ANIMREF
|
||||
{ $$ = std::make_unique<ast::expr_animation>(@$, $2); };
|
||||
;
|
||||
|
||||
expr_animtree
|
||||
: ANIMTREE
|
||||
{ $$ = std::make_unique<ast::expr_animtree>(@$); };
|
||||
;
|
||||
|
||||
expr_identifier_nosize
|
||||
: IDENTIFIER
|
||||
{ $$ = std::make_unique<ast::expr_identifier>(@$, $1); };
|
||||
;
|
||||
|
||||
expr_identifier
|
||||
: IDENTIFIER
|
||||
{ $$ = std::make_unique<ast::expr_identifier>(@$, $1); };
|
||||
| SIZE
|
||||
{ $$ = std::make_unique<ast::expr_identifier>(@$, "size"); };
|
||||
;
|
||||
|
||||
expr_path
|
||||
: IDENTIFIER
|
||||
{ $$ = std::make_unique<ast::expr_path>(@$, $1); };
|
||||
| PATH
|
||||
{ $$ = std::make_unique<ast::expr_path>(@$, $1); };
|
||||
;
|
||||
|
||||
expr_istring
|
||||
: ISTRING
|
||||
{ $$ = std::make_unique<ast::expr_istring>(@$, $1); };
|
||||
;
|
||||
|
||||
expr_string
|
||||
: STRING
|
||||
{ $$ = std::make_unique<ast::expr_string>(@$, $1); };
|
||||
;
|
||||
|
||||
expr_vector
|
||||
: LPAREN expr COMMA expr COMMA expr RPAREN
|
||||
{ $$ = std::make_unique<ast::expr_vector>(@$, std::move($2), std::move($4), std::move($6)); };
|
||||
;
|
||||
|
||||
expr_float
|
||||
: SUB FLOAT %prec NEG
|
||||
{ $$ = std::make_unique<ast::expr_float>(@$, "-" + $2); };
|
||||
| FLOAT
|
||||
{ $$ = std::make_unique<ast::expr_float>(@$, $1); };
|
||||
;
|
||||
|
||||
expr_integer
|
||||
: SUB INTEGER %prec NEG
|
||||
{ $$ = std::make_unique<ast::expr_integer>(@$, "-" + $2); };
|
||||
| INTEGER
|
||||
{ $$ = std::make_unique<ast::expr_integer>(@$, $1); };
|
||||
;
|
||||
|
||||
expr_false
|
||||
: FALSE
|
||||
{ $$ = std::make_unique<ast::expr_false>(@$); };
|
||||
;
|
||||
|
||||
expr_true
|
||||
: TRUE
|
||||
{ $$ = std::make_unique<ast::expr_true>(@$); };
|
||||
;
|
||||
|
||||
%%
|
||||
|
||||
void xsk::gsc::s1c::parser::error(const xsk::gsc::location& loc, const std::string& msg)
|
||||
{
|
||||
throw xsk::gsc::comp_error(loc, msg);
|
||||
}
|
@ -1,9 +1,9 @@
|
||||
generate: h2
|
||||
generate: gsc
|
||||
|
||||
clean:
|
||||
rm -rf ./parser.hpp
|
||||
rm -rf ./parser.cpp
|
||||
|
||||
h2: parser.ypp
|
||||
gsc: parser.ypp
|
||||
bison parser.ypp -Wcounterexamples
|
||||
mv parser.hpp parser.cpp ../../src/h2/xsk/
|
||||
mv parser.hpp parser.cpp ../../src/gsc/
|
982
gen/gsc/parser.ypp
Normal file
982
gen/gsc/parser.ypp
Normal file
@ -0,0 +1,982 @@
|
||||
/* Copyright 2023 xensik. All rights reserved.
|
||||
//
|
||||
// Use of this source code is governed by a GNU GPLv3 license
|
||||
// that can be found in the LICENSE file.
|
||||
*/
|
||||
|
||||
%require "3.7"
|
||||
%skeleton "lalr1.cc"
|
||||
%language "c++"
|
||||
%output "parser.cpp"
|
||||
%defines "parser.hpp"
|
||||
%define api.prefix {GSC}
|
||||
%define api.namespace {xsk::gsc}
|
||||
%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 { xsk::gsc::lexer& lexer }
|
||||
%parse-param { xsk::gsc::context const* ctx_ }
|
||||
%parse-param { xsk::gsc::lexer& lexer }
|
||||
%parse-param { xsk::gsc::program::ptr& ast }
|
||||
%parse-param { std::uint32_t index }
|
||||
|
||||
%code requires
|
||||
{
|
||||
#ifdef _MSC_VER
|
||||
#pragma warning(disable:4065)
|
||||
#pragma warning(disable:4127)
|
||||
#endif
|
||||
#include "context.hpp"
|
||||
namespace xsk::gsc { class lexer; }
|
||||
}
|
||||
|
||||
%code top
|
||||
{
|
||||
#include "stdinc.hpp"
|
||||
#include "parser.hpp"
|
||||
#include "lexer.hpp"
|
||||
using namespace xsk::gsc;
|
||||
namespace xsk::gsc
|
||||
{
|
||||
auto GSClex(lexer& lexer) -> parser::symbol_type;
|
||||
auto parse_switch(stmt_switch& stm) -> void;
|
||||
}
|
||||
}
|
||||
|
||||
%token SH_DEFINE "#define"
|
||||
%token SH_UNDEF "#undef"
|
||||
%token SH_IFDEF "#ifdef"
|
||||
%token SH_IFNDEF "#ifndef"
|
||||
%token SH_IF "#if"
|
||||
%token SH_ELIF "#elif"
|
||||
%token SH_ELSE "#else"
|
||||
%token SH_ENDIF "#endif"
|
||||
%token DEVBEGIN "/#"
|
||||
%token DEVEND "#/"
|
||||
%token INLINE "#inline"
|
||||
%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 DO "do"
|
||||
%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 BREAKPOINT "breakpoint"
|
||||
%token PROFBEGIN "prof_begin"
|
||||
%token PROFEND "prof_end"
|
||||
%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 ISDEFINED "isdefined"
|
||||
%token ISTRUE "istrue"
|
||||
%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_MUL "*="
|
||||
%token ASSIGN_DIV "/="
|
||||
%token ASSIGN_MOD "%="
|
||||
%token ASSIGN_BW_OR "|="
|
||||
%token ASSIGN_BW_AND "&="
|
||||
%token ASSIGN_BW_EXOR "^="
|
||||
%token ASSIGN_RSHIFT ">>="
|
||||
%token ASSIGN_LSHIFT "<<="
|
||||
%token BITWISE_OR "|"
|
||||
%token BITWISE_AND "&"
|
||||
%token BITWISE_EXOR "^"
|
||||
%token ADD "+"
|
||||
%token SUB "-"
|
||||
%token MUL "*"
|
||||
%token DIV "/"
|
||||
%token MOD "%"
|
||||
%token <std::string> PATH "path"
|
||||
%token <std::string> IDENTIFIER "identifier"
|
||||
%token <std::string> STRING "string literal"
|
||||
%token <std::string> ISTRING "localized string"
|
||||
%token <std::string> FLOAT "float"
|
||||
%token <std::string> INTEGER "integer"
|
||||
|
||||
%type <program::ptr> program
|
||||
%type <include::ptr> include
|
||||
%type <decl> declaration
|
||||
%type <decl_usingtree::ptr> decl_usingtree
|
||||
%type <decl_function::ptr> decl_function
|
||||
%type <stmt> stmt
|
||||
%type <stmt> stmt_or_dev
|
||||
%type <stmt_list::ptr> stmt_list
|
||||
%type <stmt_list::ptr> stmt_or_dev_list
|
||||
%type <stmt_dev::ptr> stmt_dev
|
||||
%type <stmt_list::ptr> stmt_block
|
||||
%type <stmt_expr::ptr> stmt_expr
|
||||
%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_dowhile::ptr> stmt_dowhile
|
||||
%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_breakpoint::ptr> stmt_breakpoint
|
||||
%type <stmt_prof_begin::ptr> stmt_prof_begin
|
||||
%type <stmt_prof_end::ptr> stmt_prof_end
|
||||
%type <expr> expr
|
||||
%type <expr> expr_or_empty
|
||||
%type <expr> expr_assign
|
||||
%type <expr> expr_increment
|
||||
%type <expr> expr_decrement
|
||||
%type <expr> expr_ternary
|
||||
%type <expr> expr_binary
|
||||
%type <expr> expr_primitive
|
||||
%type <expr_complement::ptr> expr_complement
|
||||
%type <expr_negate::ptr> expr_negate
|
||||
%type <expr_not::ptr> expr_not
|
||||
%type <expr_call::ptr> expr_call
|
||||
%type <expr_method::ptr> expr_method
|
||||
%type <call> expr_function
|
||||
%type <call> expr_pointer
|
||||
%type <expr_add_array::ptr> expr_add_array
|
||||
%type <expr_parameters::ptr> expr_parameters
|
||||
%type <expr_arguments::ptr> expr_arguments
|
||||
%type <expr_arguments::ptr> expr_arguments_no_empty
|
||||
%type <expr_isdefined::ptr> expr_isdefined
|
||||
%type <expr_istrue::ptr> expr_istrue
|
||||
%type <expr_reference::ptr> expr_reference
|
||||
%type <expr> expr_tuple
|
||||
%type <expr_tuple::ptr> expr_tuple_arguments
|
||||
%type <expr> expr_tuple_types
|
||||
%type <expr_array::ptr> expr_array
|
||||
%type <expr_field::ptr> expr_field
|
||||
%type <expr_size::ptr> expr_size
|
||||
%type <expr_paren::ptr> expr_paren
|
||||
%type <expr> expr_object
|
||||
%type <expr_thisthread::ptr> expr_thisthread
|
||||
%type <expr_empty_array::ptr> expr_empty_array
|
||||
%type <expr_undefined::ptr> expr_undefined
|
||||
%type <expr_game::ptr> expr_game
|
||||
%type <expr_self::ptr> expr_self
|
||||
%type <expr_anim::ptr> expr_anim
|
||||
%type <expr_level::ptr> expr_level
|
||||
%type <expr_animation::ptr> expr_animation
|
||||
%type <expr_animtree::ptr> expr_animtree
|
||||
%type <expr_identifier::ptr> expr_identifier_nosize
|
||||
%type <expr_identifier::ptr> expr_identifier
|
||||
%type <expr_path::ptr> expr_path
|
||||
%type <expr_istring::ptr> expr_istring
|
||||
%type <expr_string::ptr> expr_string
|
||||
%type <expr_vector::ptr> expr_vector
|
||||
%type <expr_float::ptr> expr_float
|
||||
%type <expr_integer::ptr> expr_integer
|
||||
%type <expr_false::ptr> expr_false
|
||||
%type <expr_true::ptr> expr_true
|
||||
|
||||
%nonassoc SIZEOF
|
||||
%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_EXOR
|
||||
%left BITWISE_AND
|
||||
%left EQUALITY INEQUALITY
|
||||
%left LESS GREATER LESS_EQUAL GREATER_EQUAL
|
||||
%left LSHIFT RSHIFT
|
||||
%left ADD SUB
|
||||
%left MUL DIV MOD
|
||||
%right NOT COMPLEMENT
|
||||
|
||||
%precedence NEG
|
||||
%precedence ANIMREF
|
||||
%precedence PREINC PREDEC
|
||||
%precedence POSTINC POSTDEC
|
||||
|
||||
%start root
|
||||
|
||||
%%
|
||||
|
||||
root
|
||||
: program { ast = std::move($1); }
|
||||
| { ast = make_program(@$); }
|
||||
;
|
||||
|
||||
program
|
||||
: program inline
|
||||
{ $$ = std::move($1); }
|
||||
| program include
|
||||
{ $$ = std::move($1); $$->includes.push_back(std::move($2)); }
|
||||
| program declaration
|
||||
{ $$ = std::move($1); $$->declarations.push_back(std::move($2)); }
|
||||
| inline
|
||||
{ $$ = make_program(@$); }
|
||||
| include
|
||||
{ $$ = make_program(@$); $$->includes.push_back(std::move($1)); }
|
||||
| declaration
|
||||
{ $$ = make_program(@$); $$->declarations.push_back(std::move($1)); }
|
||||
;
|
||||
|
||||
inline
|
||||
: INLINE expr_path SEMICOLON { lexer.push_header($2->value); }
|
||||
;
|
||||
|
||||
include
|
||||
: INCLUDE expr_path SEMICOLON
|
||||
{ $$ = make_include(@$, std::move($2)); }
|
||||
;
|
||||
|
||||
declaration
|
||||
: DEVBEGIN { $$.as_dev_begin = make_decl_dev_begin(@$); }
|
||||
| DEVEND { $$.as_dev_end = make_decl_dev_end(@$); }
|
||||
| decl_usingtree { $$.as_usingtree = std::move($1); }
|
||||
| decl_function { $$.as_function = std::move($1); }
|
||||
;
|
||||
|
||||
decl_usingtree
|
||||
: USINGTREE LPAREN expr_string RPAREN SEMICOLON
|
||||
{ lexer.ban_header(@$); $$ = make_decl_usingtree(@$, std::move($3)); }
|
||||
;
|
||||
|
||||
decl_function
|
||||
: expr_identifier LPAREN expr_parameters RPAREN stmt_block
|
||||
{ lexer.ban_header(@$); $$ = make_decl_function(@$, std::move($1), std::move($3), std::move($5)); }
|
||||
;
|
||||
|
||||
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_dowhile { $$.as_dowhile = 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_breakpoint { $$.as_breakpoint = std::move($1); }
|
||||
| stmt_prof_begin { $$.as_prof_begin = std::move($1); }
|
||||
| stmt_prof_end { $$.as_prof_end = std::move($1); }
|
||||
;
|
||||
|
||||
stmt_or_dev
|
||||
: stmt { $$ = std::move($1); }
|
||||
| stmt_dev { $$.as_dev = std::move($1); }
|
||||
;
|
||||
|
||||
stmt_list
|
||||
: stmt_list stmt
|
||||
{ $$ = std::move($1); $$->list.push_back(std::move($2)); }
|
||||
| stmt
|
||||
{ $$ = make_stmt_list(@$); $$->list.push_back(std::move($1)); }
|
||||
;
|
||||
|
||||
stmt_or_dev_list
|
||||
: stmt_or_dev_list stmt_or_dev
|
||||
{ $$ = std::move($1); $$->list.push_back(std::move($2)); }
|
||||
| stmt_or_dev
|
||||
{ $$ = make_stmt_list(@$); $$->list.push_back(std::move($1)); }
|
||||
;
|
||||
|
||||
stmt_dev
|
||||
: DEVBEGIN stmt_list DEVEND { $$ = make_stmt_dev(@$, std::move($2)); }
|
||||
| DEVBEGIN DEVEND { $$ = make_stmt_dev(@$, make_stmt_list(@$)); }
|
||||
;
|
||||
|
||||
stmt_block
|
||||
: LBRACE stmt_or_dev_list RBRACE { $$ = std::move($2); }
|
||||
| LBRACE RBRACE { $$ = make_stmt_list(@$); }
|
||||
;
|
||||
|
||||
stmt_expr
|
||||
: expr_assign
|
||||
{ $$ = make_stmt_expr(@$, std::move($1)); }
|
||||
| expr_increment
|
||||
{ $$ = make_stmt_expr(@$, std::move($1)); }
|
||||
| expr_decrement
|
||||
{ $$ = make_stmt_expr(@$, std::move($1)); }
|
||||
|
|
||||
{ $$ = make_stmt_expr(@$, make_node(@$)); }
|
||||
;
|
||||
|
||||
stmt_call
|
||||
: expr_call SEMICOLON
|
||||
{ $$ = make_stmt_call(@$, expr{ std::move($1) }); }
|
||||
| expr_method SEMICOLON
|
||||
{ $$ = make_stmt_call(@$, expr{ std::move($1) }); }
|
||||
;
|
||||
|
||||
stmt_assign
|
||||
: expr_assign SEMICOLON
|
||||
{ $$ = make_stmt_assign(@$, std::move($1)); }
|
||||
| expr_increment SEMICOLON
|
||||
{ $$ = make_stmt_assign(@$, std::move($1)); }
|
||||
| expr_decrement SEMICOLON
|
||||
{ $$ = make_stmt_assign(@$, std::move($1)); }
|
||||
;
|
||||
|
||||
stmt_endon
|
||||
: expr_object ENDON LPAREN expr RPAREN SEMICOLON
|
||||
{ $$ = make_stmt_endon(@$, std::move($1), std::move($4)); }
|
||||
;
|
||||
|
||||
stmt_notify
|
||||
: expr_object NOTIFY LPAREN expr COMMA expr_arguments_no_empty RPAREN SEMICOLON
|
||||
{ $$ = make_stmt_notify(@$, std::move($1), std::move($4), std::move($6)); }
|
||||
| expr_object NOTIFY LPAREN expr RPAREN SEMICOLON
|
||||
{ $$ = make_stmt_notify(@$, std::move($1), std::move($4), make_expr_arguments(@$)); }
|
||||
;
|
||||
|
||||
stmt_wait
|
||||
: WAIT expr SEMICOLON
|
||||
{ $$ = make_stmt_wait(@$, std::move($2)); }
|
||||
;
|
||||
|
||||
stmt_waittill
|
||||
: expr_object WAITTILL LPAREN expr COMMA expr_arguments_no_empty RPAREN SEMICOLON
|
||||
{ $$ = make_stmt_waittill(@$, std::move($1), std::move($4), std::move($6)); }
|
||||
| expr_object WAITTILL LPAREN expr RPAREN SEMICOLON
|
||||
{ $$ = make_stmt_waittill(@$, std::move($1), std::move($4), make_expr_arguments(@$)); }
|
||||
;
|
||||
|
||||
stmt_waittillmatch
|
||||
: expr_object WAITTILLMATCH LPAREN expr COMMA expr_arguments_no_empty RPAREN SEMICOLON
|
||||
{ $$ = make_stmt_waittillmatch(@$, std::move($1), std::move($4), std::move($6)); }
|
||||
| expr_object WAITTILLMATCH LPAREN expr RPAREN SEMICOLON
|
||||
{ $$ = make_stmt_waittillmatch(@$, std::move($1), std::move($4), make_expr_arguments(@$)); }
|
||||
;
|
||||
|
||||
stmt_waittillframeend
|
||||
: WAITTILLFRAMEEND SEMICOLON
|
||||
{ $$ = make_stmt_waittillframeend(@$); }
|
||||
;
|
||||
|
||||
stmt_waitframe
|
||||
: WAITFRAME SEMICOLON
|
||||
{ $$ = make_stmt_waitframe(@$); }
|
||||
| WAITFRAME LPAREN RPAREN SEMICOLON
|
||||
{ $$ = make_stmt_waitframe(@$); }
|
||||
;
|
||||
|
||||
stmt_if
|
||||
: IF LPAREN expr RPAREN stmt %prec THEN
|
||||
{ $$ = make_stmt_if(@$, std::move($3), std::move($5)); }
|
||||
;
|
||||
|
||||
stmt_ifelse
|
||||
: IF LPAREN expr RPAREN stmt ELSE stmt
|
||||
{ $$ = make_stmt_ifelse(@$, std::move($3), std::move($5), std::move($7)); }
|
||||
;
|
||||
|
||||
stmt_while
|
||||
: WHILE LPAREN expr RPAREN stmt
|
||||
{ $$ = make_stmt_while(@$, std::move($3), std::move($5)); }
|
||||
;
|
||||
|
||||
stmt_dowhile
|
||||
: DO stmt WHILE LPAREN expr RPAREN SEMICOLON
|
||||
{ $$ = make_stmt_dowhile(@$, std::move($5), std::move($2)); }
|
||||
;
|
||||
|
||||
stmt_for
|
||||
: FOR LPAREN stmt_expr SEMICOLON expr_or_empty SEMICOLON stmt_expr RPAREN stmt
|
||||
{ $$ = make_stmt_for(@$, stmt{ std::move($3) }, std::move($5), stmt{ std::move($7) }, std::move($9)); }
|
||||
;
|
||||
|
||||
stmt_foreach
|
||||
: FOREACH LPAREN expr_identifier IN expr RPAREN stmt
|
||||
{
|
||||
auto array = expr{ make_expr_identifier(@$, fmt::format("_temp_{}", ++index)) };
|
||||
auto key = expr{ make_expr_identifier(@$, fmt::format("_temp_{}", ++index)) };
|
||||
$$ = make_stmt_foreach(@$, std::move($5), expr{ std::move($3) }, expr{ make_node(@$) }, std::move(array), std::move(key), std::move($7), false); }
|
||||
| FOREACH LPAREN expr_identifier COMMA expr_identifier IN expr RPAREN stmt
|
||||
{
|
||||
auto array = expr{ make_expr_identifier(@$, fmt::format("_temp_{}", ++index)) };
|
||||
auto key = (ctx_->props() & props::foreach) ? expr{ make_expr_identifier(@$, fmt::format("_temp_{}", ++index)) } : expr{ std::move($3) };
|
||||
$$ = make_stmt_foreach(@$, std::move($7), expr{ std::move($5) }, (ctx_->props() & props::foreach) ? expr{ std::move($3) } : expr{ make_node(@$) }, std::move(array), std::move(key), std::move($9), true);
|
||||
}
|
||||
;
|
||||
|
||||
stmt_switch
|
||||
: SWITCH LPAREN expr RPAREN stmt_block
|
||||
{ $$ = make_stmt_switch(@$, std::move($3), std::move($5));
|
||||
parse_switch(*$$);
|
||||
}
|
||||
;
|
||||
|
||||
stmt_case
|
||||
: CASE expr_integer COLON
|
||||
{ $$ = make_stmt_case(@$, expr{ std::move($2) }, make_stmt_list(@$)); }
|
||||
| CASE expr_string COLON
|
||||
{ $$ = make_stmt_case(@$, expr{ std::move($2) }, make_stmt_list(@$)); }
|
||||
;
|
||||
|
||||
stmt_default
|
||||
: DEFAULT COLON
|
||||
{ $$ = make_stmt_default(@$, make_stmt_list(@$)); }
|
||||
;
|
||||
|
||||
stmt_break
|
||||
: BREAK SEMICOLON
|
||||
{ $$ = make_stmt_break(@$); }
|
||||
;
|
||||
|
||||
stmt_continue
|
||||
: CONTINUE SEMICOLON
|
||||
{ $$ = make_stmt_continue(@$); }
|
||||
;
|
||||
|
||||
stmt_return
|
||||
: RETURN expr SEMICOLON
|
||||
{ $$ = make_stmt_return(@$, std::move($2)); }
|
||||
| RETURN SEMICOLON
|
||||
{ $$ = make_stmt_return(@$, make_node(@$)); }
|
||||
;
|
||||
|
||||
stmt_breakpoint
|
||||
: BREAKPOINT SEMICOLON
|
||||
{ $$ = make_stmt_breakpoint(@$); }
|
||||
;
|
||||
|
||||
stmt_prof_begin
|
||||
: PROFBEGIN LPAREN expr_arguments RPAREN SEMICOLON
|
||||
{ $$ = make_stmt_prof_begin(@$, std::move($3)); }
|
||||
;
|
||||
|
||||
stmt_prof_end
|
||||
: PROFEND LPAREN expr_arguments RPAREN SEMICOLON
|
||||
{ $$ = make_stmt_prof_end(@$, std::move($3)); }
|
||||
;
|
||||
|
||||
expr
|
||||
: expr_ternary { $$ = std::move($1); }
|
||||
| expr_binary { $$ = std::move($1); }
|
||||
| expr_primitive { $$ = std::move($1); }
|
||||
;
|
||||
|
||||
expr_or_empty
|
||||
: expr { $$ = std::move($1); }
|
||||
| { $$.as_node = make_node(@$); }
|
||||
;
|
||||
|
||||
expr_assign
|
||||
: expr_tuple ASSIGN expr
|
||||
{ $$.as_node = make_expr_assign_equal(@$, std::move($1), std::move($3)); }
|
||||
| expr_object ASSIGN expr
|
||||
{ $$.as_node = make_expr_assign_equal(@$, std::move($1), std::move($3)); }
|
||||
| expr_object ASSIGN_BW_OR expr
|
||||
{ $$.as_node = make_expr_assign_bitwise_or(@$, std::move($1), std::move($3)); }
|
||||
| expr_object ASSIGN_BW_AND expr
|
||||
{ $$.as_node = make_expr_assign_bitwise_and(@$, std::move($1), std::move($3)); }
|
||||
| expr_object ASSIGN_BW_EXOR expr
|
||||
{ $$.as_node = make_expr_assign_bitwise_exor(@$, std::move($1), std::move($3)); }
|
||||
| expr_object ASSIGN_LSHIFT expr
|
||||
{ $$.as_node = make_expr_assign_shift_left(@$, std::move($1),std::move( $3)); }
|
||||
| expr_object ASSIGN_RSHIFT expr
|
||||
{ $$.as_node = make_expr_assign_shift_right(@$, std::move($1), std::move($3)); }
|
||||
| expr_object ASSIGN_ADD expr
|
||||
{ $$.as_node = make_expr_assign_add(@$, std::move($1), std::move($3)); }
|
||||
| expr_object ASSIGN_SUB expr
|
||||
{ $$.as_node = make_expr_assign_sub(@$, std::move($1), std::move($3)); }
|
||||
| expr_object ASSIGN_MUL expr
|
||||
{ $$.as_node = make_expr_assign_mul(@$, std::move($1), std::move($3)); }
|
||||
| expr_object ASSIGN_DIV expr
|
||||
{ $$.as_node = make_expr_assign_div(@$, std::move($1), std::move($3)); }
|
||||
| expr_object ASSIGN_MOD expr
|
||||
{ $$.as_node = make_expr_assign_mod(@$, std::move($1), std::move($3)); }
|
||||
;
|
||||
|
||||
expr_increment
|
||||
: INCREMENT expr_object %prec PREINC
|
||||
{ $$.as_node = make_expr_increment(@$, std::move($2), true); }
|
||||
| expr_object INCREMENT %prec POSTINC
|
||||
{ $$.as_node = make_expr_increment(@$, std::move($1), false); }
|
||||
;
|
||||
|
||||
expr_decrement
|
||||
: DECREMENT expr_object %prec PREDEC
|
||||
{ $$.as_node = make_expr_decrement(@$, std::move($2), true); }
|
||||
| expr_object DECREMENT %prec POSTDEC
|
||||
{ $$.as_node = make_expr_decrement(@$, std::move($1), false); }
|
||||
;
|
||||
|
||||
expr_ternary
|
||||
: expr QMARK expr COLON expr %prec TERN
|
||||
{ $$.as_node = make_expr_ternary(@$, std::move($1), std::move($3), std::move($5)); }
|
||||
;
|
||||
|
||||
expr_binary
|
||||
: expr OR expr
|
||||
{ $$.as_node = make_expr_or(@$, std::move($1), std::move($3)); }
|
||||
| expr AND expr
|
||||
{ $$.as_node = make_expr_and(@$, std::move($1), std::move($3)); }
|
||||
| expr EQUALITY expr
|
||||
{ $$.as_node = make_expr_equality(@$, std::move($1), std::move($3)); }
|
||||
| expr INEQUALITY expr
|
||||
{ $$.as_node = make_expr_inequality(@$, std::move($1), std::move($3)); }
|
||||
| expr LESS_EQUAL expr
|
||||
{ $$.as_node = make_expr_less_equal(@$, std::move($1), std::move($3)); }
|
||||
| expr GREATER_EQUAL expr
|
||||
{ $$.as_node = make_expr_greater_equal(@$, std::move($1), std::move($3)); }
|
||||
| expr LESS expr
|
||||
{ $$.as_node = make_expr_less(@$, std::move($1), std::move($3)); }
|
||||
| expr GREATER expr
|
||||
{ $$.as_node = make_expr_greater(@$, std::move($1), std::move($3)); }
|
||||
| expr BITWISE_OR expr
|
||||
{ $$.as_node = make_expr_bitwise_or(@$, std::move($1), std::move($3)); }
|
||||
| expr BITWISE_AND expr
|
||||
{ $$.as_node = make_expr_bitwise_and(@$, std::move($1), std::move($3)); }
|
||||
| expr BITWISE_EXOR expr
|
||||
{ $$.as_node = make_expr_bitwise_exor(@$, std::move($1), std::move($3)); }
|
||||
| expr LSHIFT expr
|
||||
{ $$.as_node = make_expr_shift_left(@$, std::move($1), std::move($3)); }
|
||||
| expr RSHIFT expr
|
||||
{ $$.as_node = make_expr_shift_right(@$, std::move($1), std::move($3)); }
|
||||
| expr ADD expr
|
||||
{ $$.as_node = make_expr_add(@$, std::move($1), std::move($3)); }
|
||||
| expr SUB expr
|
||||
{ $$.as_node = make_expr_sub(@$, std::move($1), std::move($3)); }
|
||||
| expr MUL expr
|
||||
{ $$.as_node = make_expr_mul(@$, std::move($1), std::move($3)); }
|
||||
| expr DIV expr
|
||||
{ $$.as_node = make_expr_div(@$, std::move($1), std::move($3)); }
|
||||
| expr MOD expr
|
||||
{ $$.as_node = make_expr_mod(@$, std::move($1), std::move($3)); }
|
||||
;
|
||||
|
||||
expr_primitive
|
||||
: expr_complement { $$.as_node = std::move($1); }
|
||||
| expr_negate { $$.as_node = std::move($1); }
|
||||
| expr_not { $$.as_node = std::move($1); }
|
||||
| expr_call { $$.as_node = std::move($1); }
|
||||
| expr_method { $$.as_node = std::move($1); }
|
||||
| expr_add_array { $$.as_node = std::move($1); }
|
||||
| expr_isdefined { $$.as_node = std::move($1); }
|
||||
| expr_istrue { $$.as_node = std::move($1); }
|
||||
| expr_reference { $$.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); }
|
||||
| expr_paren { $$.as_node = std::move($1); }
|
||||
| expr_thisthread { $$.as_node = std::move($1); }
|
||||
| expr_empty_array { $$.as_node = std::move($1); }
|
||||
| expr_undefined { $$.as_node = std::move($1); }
|
||||
| expr_game { $$.as_node = std::move($1); }
|
||||
| expr_self { $$.as_node = std::move($1); }
|
||||
| expr_anim { $$.as_node = std::move($1); }
|
||||
| expr_level { $$.as_node = std::move($1); }
|
||||
| expr_animation { $$.as_node = std::move($1); }
|
||||
| expr_animtree { $$.as_node = std::move($1); }
|
||||
| expr_identifier { $$.as_node = std::move($1); }
|
||||
| expr_istring { $$.as_node = std::move($1); }
|
||||
| expr_string { $$.as_node = std::move($1); }
|
||||
| expr_vector { $$.as_node = std::move($1); }
|
||||
| expr_float { $$.as_node = std::move($1); }
|
||||
| expr_integer { $$.as_node = std::move($1); }
|
||||
| expr_false { $$.as_node = std::move($1); }
|
||||
| expr_true { $$.as_node = std::move($1); }
|
||||
;
|
||||
|
||||
expr_complement
|
||||
: COMPLEMENT expr
|
||||
{ $$ = make_expr_complement(@$, std::move($2)); }
|
||||
;
|
||||
|
||||
expr_negate
|
||||
: SUB expr_identifier %prec NEG
|
||||
{ $$ = make_expr_negate(@$, expr{ std::move($2) }); }
|
||||
| SUB expr_paren %prec NEG
|
||||
{ $$ = make_expr_negate(@$, expr{ std::move($2) }); }
|
||||
| SUB expr_array %prec NEG
|
||||
{ $$ = make_expr_negate(@$, expr{ std::move($2) }); }
|
||||
| SUB expr_field %prec NEG
|
||||
{ $$ = make_expr_negate(@$, expr{ std::move($2) }); }
|
||||
;
|
||||
|
||||
expr_not
|
||||
: NOT expr
|
||||
{ $$ = make_expr_not(@$, std::move($2)); }
|
||||
;
|
||||
|
||||
expr_call
|
||||
: expr_function { $$ = make_expr_call(@$, std::move($1)); }
|
||||
| expr_pointer { $$ = make_expr_call(@$, std::move($1)); }
|
||||
;
|
||||
expr_method
|
||||
: expr_object expr_function { $$ = make_expr_method(@$, std::move($1), std::move($2)); }
|
||||
| expr_object expr_pointer { $$ = make_expr_method(@$, std::move($1), std::move($2)); }
|
||||
;
|
||||
|
||||
expr_function
|
||||
: expr_identifier LPAREN expr_arguments RPAREN
|
||||
{ $$.as_function = make_expr_function(@$, make_expr_path(@$), std::move($1), std::move($3), call::mode::normal); }
|
||||
| expr_path DOUBLECOLON expr_identifier LPAREN expr_arguments RPAREN
|
||||
{ $$.as_function = make_expr_function(@$, std::move($1), std::move($3), std::move($5), call::mode::normal); }
|
||||
| THREAD expr_identifier LPAREN expr_arguments RPAREN
|
||||
{ $$.as_function = make_expr_function(@$, make_expr_path(@$), std::move($2), std::move($4), call::mode::thread); }
|
||||
| THREAD expr_path DOUBLECOLON expr_identifier LPAREN expr_arguments RPAREN
|
||||
{ $$.as_function = make_expr_function(@$, std::move($2), std::move($4), std::move($6), call::mode::thread); }
|
||||
| CHILDTHREAD expr_identifier LPAREN expr_arguments RPAREN
|
||||
{ $$.as_function = make_expr_function(@$, make_expr_path(@$), std::move($2), std::move($4), call::mode::childthread); }
|
||||
| CHILDTHREAD expr_path DOUBLECOLON expr_identifier LPAREN expr_arguments RPAREN
|
||||
{ $$.as_function = make_expr_function(@$, std::move($2), std::move($4), std::move($6), call::mode::childthread); }
|
||||
;
|
||||
|
||||
expr_pointer
|
||||
: LBRACKET LBRACKET expr RBRACKET RBRACKET LPAREN expr_arguments RPAREN
|
||||
{ $$.as_pointer = make_expr_pointer(@$, std::move($3), std::move($7), call::mode::normal); }
|
||||
| THREAD LBRACKET LBRACKET expr RBRACKET RBRACKET LPAREN expr_arguments RPAREN
|
||||
{ $$.as_pointer = make_expr_pointer(@$, std::move($4), std::move($8), call::mode::thread); }
|
||||
| CHILDTHREAD LBRACKET LBRACKET expr RBRACKET RBRACKET LPAREN expr_arguments RPAREN
|
||||
{ $$.as_pointer = make_expr_pointer(@$, std::move($4), std::move($8), call::mode::childthread); }
|
||||
| CALL LBRACKET LBRACKET expr RBRACKET RBRACKET LPAREN expr_arguments RPAREN
|
||||
{ $$.as_pointer = make_expr_pointer(@$, std::move($4), std::move($8), call::mode::builtin); }
|
||||
;
|
||||
|
||||
expr_add_array
|
||||
: LBRACKET expr_arguments_no_empty RBRACKET
|
||||
{ $$ = make_expr_add_array(@$, std::move($2)); }
|
||||
;
|
||||
|
||||
expr_parameters
|
||||
: expr_parameters COMMA expr_identifier
|
||||
{ $$ = std::move($1); $$->list.push_back(std::move($3)); }
|
||||
| expr_identifier
|
||||
{ $$ = make_expr_parameters(@$); $$->list.push_back(std::move($1)); }
|
||||
|
|
||||
{ $$ = make_expr_parameters(@$); }
|
||||
;
|
||||
|
||||
expr_arguments
|
||||
: expr_arguments_no_empty
|
||||
{ $$ = std::move($1); }
|
||||
|
|
||||
{ $$ = make_expr_arguments(@$); }
|
||||
;
|
||||
|
||||
expr_arguments_no_empty
|
||||
: expr_arguments COMMA expr
|
||||
{ $$ = std::move($1); $$->list.push_back(std::move($3)); }
|
||||
| expr %prec ADD_ARRAY
|
||||
{ $$ = make_expr_arguments(@$); $$->list.push_back(std::move($1)); }
|
||||
;
|
||||
|
||||
expr_isdefined
|
||||
: ISDEFINED LPAREN expr RPAREN
|
||||
{ $$ = make_expr_isdefined(@$, std::move($3)); }
|
||||
;
|
||||
|
||||
expr_istrue
|
||||
: ISTRUE LPAREN expr RPAREN
|
||||
{ $$ = make_expr_istrue(@$, std::move($3)); }
|
||||
;
|
||||
|
||||
expr_reference
|
||||
: DOUBLECOLON expr_identifier
|
||||
{ $$ = make_expr_reference(@$, make_expr_path(@$), std::move($2)); }
|
||||
| expr_path DOUBLECOLON expr_identifier
|
||||
{ $$ = make_expr_reference(@$, std::move($1), std::move($3)); }
|
||||
;
|
||||
|
||||
expr_tuple
|
||||
: LBRACKET expr_tuple_arguments RBRACKET
|
||||
{ $$.as_node = std::move($2);
|
||||
$$.as_tuple->temp = expr{ std::make_unique<expr_identifier>($$.loc(), fmt::format("_temp_{}", ++index)) };
|
||||
}
|
||||
;
|
||||
|
||||
expr_tuple_arguments
|
||||
: expr_tuple_arguments COMMA expr_tuple_types
|
||||
{ $$ = std::move($1); $$->list.push_back(std::move($3)); }
|
||||
| expr_tuple_types
|
||||
{ $$ = make_expr_tuple(@$); $$->list.push_back(std::move($1)); }
|
||||
;
|
||||
|
||||
expr_tuple_types
|
||||
: expr_array { $$.as_node = std::move($1); }
|
||||
| expr_field { $$.as_node = std::move($1); }
|
||||
| expr_identifier { $$.as_node = std::move($1); }
|
||||
;
|
||||
|
||||
expr_array
|
||||
: expr_object LBRACKET expr RBRACKET
|
||||
{ $$ = make_expr_array(@$, std::move($1), std::move($3)); }
|
||||
;
|
||||
|
||||
expr_field
|
||||
: expr_object DOT expr_identifier_nosize
|
||||
{ $$ = make_expr_field(@$, std::move($1), std::move($3)); }
|
||||
;
|
||||
|
||||
expr_size
|
||||
: expr_object DOT SIZE %prec SIZEOF
|
||||
{ $$ = make_expr_size(@$, std::move($1)); }
|
||||
;
|
||||
|
||||
expr_paren
|
||||
: LPAREN expr RPAREN
|
||||
{ $$ = make_expr_paren(@$, std::move($2)); }
|
||||
;
|
||||
|
||||
expr_object
|
||||
: expr_call { $$.as_node = std::move($1); }
|
||||
| expr_method { $$.as_node = std::move($1); }
|
||||
| expr_array { $$.as_node = std::move($1); }
|
||||
| expr_field { $$.as_node = std::move($1); }
|
||||
| expr_game { $$.as_node = std::move($1); }
|
||||
| expr_self { $$.as_node = std::move($1); }
|
||||
| expr_anim { $$.as_node = std::move($1); }
|
||||
| expr_level { $$.as_node = std::move($1); }
|
||||
| expr_identifier { $$.as_node = std::move($1); }
|
||||
;
|
||||
|
||||
expr_thisthread
|
||||
: THISTHREAD
|
||||
{ $$ = make_expr_thisthread(@$); };
|
||||
;
|
||||
|
||||
expr_empty_array
|
||||
: LBRACKET RBRACKET
|
||||
{ $$ = make_expr_empty_array(@$); };
|
||||
;
|
||||
|
||||
expr_undefined
|
||||
: UNDEFINED
|
||||
{ $$ = make_expr_undefined(@$); };
|
||||
;
|
||||
|
||||
expr_game
|
||||
: GAME
|
||||
{ $$ = make_expr_game(@$); };
|
||||
;
|
||||
|
||||
expr_self
|
||||
: SELF
|
||||
{ $$ = make_expr_self(@$); };
|
||||
;
|
||||
|
||||
expr_anim
|
||||
: ANIM
|
||||
{ $$ = make_expr_anim(@$); };
|
||||
;
|
||||
|
||||
expr_level
|
||||
: LEVEL
|
||||
{ $$ = make_expr_level(@$); };
|
||||
;
|
||||
|
||||
expr_animation
|
||||
: MOD IDENTIFIER %prec ANIMREF
|
||||
{ $$ = make_expr_animation(@$, $2); };
|
||||
;
|
||||
|
||||
expr_animtree
|
||||
: ANIMTREE
|
||||
{ $$ = make_expr_animtree(@$); };
|
||||
;
|
||||
|
||||
expr_identifier_nosize
|
||||
: IDENTIFIER
|
||||
{ $$ = make_expr_identifier(@$, $1); };
|
||||
;
|
||||
|
||||
expr_identifier
|
||||
: IDENTIFIER
|
||||
{ $$ = make_expr_identifier(@$, $1); };
|
||||
| SIZE
|
||||
{ $$ = make_expr_identifier(@$, "size"); };
|
||||
;
|
||||
|
||||
expr_path
|
||||
: PATH DIV IDENTIFIER
|
||||
{ $$ = make_expr_path(@$, $1 + "/" + $3); };
|
||||
| IDENTIFIER
|
||||
{ $$ = make_expr_path(@$, $1); };
|
||||
| PATH
|
||||
{ $$ = make_expr_path(@$, $1); };
|
||||
;
|
||||
|
||||
expr_istring
|
||||
: ISTRING
|
||||
{ $$ = make_expr_istring(@$, $1); };
|
||||
;
|
||||
|
||||
expr_string
|
||||
: STRING
|
||||
{ $$ = make_expr_string(@$, $1); };
|
||||
;
|
||||
|
||||
expr_vector
|
||||
: LPAREN expr COMMA expr COMMA expr RPAREN
|
||||
{ $$ = make_expr_vector(@$, std::move($2), std::move($4), std::move($6)); };
|
||||
;
|
||||
|
||||
expr_float
|
||||
: SUB FLOAT %prec NEG
|
||||
{ $$ = make_expr_float(@$, "-" + $2); };
|
||||
| FLOAT
|
||||
{ $$ = make_expr_float(@$, $1); };
|
||||
;
|
||||
|
||||
expr_integer
|
||||
: SUB INTEGER %prec NEG
|
||||
{ $$ = make_expr_integer(@$, "-" + $2); };
|
||||
| INTEGER
|
||||
{ $$ = make_expr_integer(@$, $1); };
|
||||
;
|
||||
|
||||
expr_false
|
||||
: FALSE
|
||||
{ $$ = make_expr_false(@$); };
|
||||
;
|
||||
|
||||
expr_true
|
||||
: TRUE
|
||||
{ $$ = make_expr_true(@$); };
|
||||
;
|
||||
|
||||
%%
|
||||
|
||||
namespace xsk::gsc
|
||||
{
|
||||
|
||||
void parser::error(location const& loc, std::string const& msg)
|
||||
{
|
||||
throw comp_error(loc, msg);
|
||||
}
|
||||
|
||||
auto parse_switch(stmt_switch& stm) -> void
|
||||
{
|
||||
auto body = make_stmt_list(stm.body->loc());
|
||||
auto current_case = stmt{ nullptr };
|
||||
|
||||
auto num = stm.body->list.size();
|
||||
|
||||
for (auto i = 0u; i < num; i++)
|
||||
{
|
||||
auto& entry = stm.body->list[0];
|
||||
|
||||
if (entry == node::stmt_case || entry == node::stmt_default)
|
||||
{
|
||||
if (current_case.as_node != nullptr)
|
||||
{
|
||||
body->list.push_back(std::move(current_case));
|
||||
}
|
||||
|
||||
current_case = std::move(stm.body->list[0]);
|
||||
stm.body->list.erase(stm.body->list.begin());
|
||||
}
|
||||
else
|
||||
{
|
||||
if (current_case.as_node != nullptr)
|
||||
{
|
||||
if (current_case == node::stmt_case)
|
||||
{
|
||||
current_case.as_case->body->list.push_back(std::move(entry));
|
||||
stm.body->list.erase(stm.body->list.begin());
|
||||
}
|
||||
else
|
||||
{
|
||||
current_case.as_default->body->list.push_back(std::move(entry));
|
||||
stm.body->list.erase(stm.body->list.begin());
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
throw comp_error(entry.loc(), "missing case statement");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (current_case.as_node != nullptr)
|
||||
{
|
||||
body->list.push_back(std::move(current_case));
|
||||
}
|
||||
|
||||
stm.body = std::move(body);
|
||||
}
|
||||
|
||||
} // namespace xsk::gsc
|
@ -1,9 +0,0 @@
|
||||
generate: h1
|
||||
|
||||
clean:
|
||||
rm -rf ./parser.hpp
|
||||
rm -rf ./parser.cpp
|
||||
|
||||
h1: parser.ypp
|
||||
bison parser.ypp -Wcounterexamples
|
||||
mv parser.hpp parser.cpp ../../src/h1/xsk/
|
@ -1,898 +0,0 @@
|
||||
/* Copyright 2022 xensik. All rights reserved.
|
||||
//
|
||||
// Use of this source code is governed by a GNU GPLv3 license
|
||||
// that can be found in the LICENSE file.
|
||||
*/
|
||||
|
||||
%require "3.7"
|
||||
%skeleton "lalr1.cc"
|
||||
%language "c++"
|
||||
%output "parser.cpp"
|
||||
%defines "parser.hpp"
|
||||
%define api.prefix {H1}
|
||||
%define api.namespace {xsk::gsc::h1}
|
||||
%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 { xsk::gsc::h1::lexer& lexer }
|
||||
%parse-param { xsk::gsc::h1::lexer& lexer }
|
||||
%parse-param { xsk::gsc::ast::program::ptr& ast }
|
||||
|
||||
%code requires
|
||||
{
|
||||
#ifdef _MSC_VER
|
||||
#pragma warning(disable:4065)
|
||||
#pragma warning(disable:4127)
|
||||
#endif
|
||||
#include "h1.hpp"
|
||||
namespace xsk::gsc::h1 { class lexer; }
|
||||
}
|
||||
|
||||
%code top
|
||||
{
|
||||
#include "stdafx.hpp"
|
||||
#include "parser.hpp"
|
||||
#include "lexer.hpp"
|
||||
using namespace xsk::gsc;
|
||||
xsk::gsc::h1::parser::symbol_type H1lex(xsk::gsc::h1::lexer& lexer);
|
||||
}
|
||||
|
||||
%token SH_DEFINE "#define"
|
||||
%token SH_UNDEF "#undef"
|
||||
%token SH_IFDEF "#ifdef"
|
||||
%token SH_IFNDEF "#ifndef"
|
||||
%token SH_IF "#if"
|
||||
%token SH_ELIF "#elif"
|
||||
%token SH_ELSE "#else"
|
||||
%token SH_ENDIF "#endif"
|
||||
%token DEVBEGIN "/#"
|
||||
%token DEVEND "#/"
|
||||
%token INLINE "#inline"
|
||||
%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 DO "do"
|
||||
%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 BREAKPOINT "breakpoint"
|
||||
%token PROFBEGIN "prof_begin"
|
||||
%token PROFEND "prof_end"
|
||||
%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_MUL "*="
|
||||
%token ASSIGN_DIV "/="
|
||||
%token ASSIGN_MOD "%="
|
||||
%token ASSIGN_BW_OR "|="
|
||||
%token ASSIGN_BW_AND "&="
|
||||
%token ASSIGN_BW_EXOR "^="
|
||||
%token ASSIGN_RSHIFT ">>="
|
||||
%token ASSIGN_LSHIFT "<<="
|
||||
%token BITWISE_OR "|"
|
||||
%token BITWISE_AND "&"
|
||||
%token BITWISE_EXOR "^"
|
||||
%token ADD "+"
|
||||
%token SUB "-"
|
||||
%token MUL "*"
|
||||
%token DIV "/"
|
||||
%token MOD "%"
|
||||
%token <std::string> PATH "path"
|
||||
%token <std::string> IDENTIFIER "identifier"
|
||||
%token <std::string> STRING "string literal"
|
||||
%token <std::string> ISTRING "localized string"
|
||||
%token <std::string> FLOAT "float"
|
||||
%token <std::string> INTEGER "integer"
|
||||
|
||||
%type <ast::program::ptr> program
|
||||
%type <ast::include::ptr> include
|
||||
%type <ast::decl> declaration
|
||||
%type <ast::decl_usingtree::ptr> decl_usingtree
|
||||
%type <ast::decl_constant::ptr> decl_constant
|
||||
%type <ast::decl_thread::ptr> decl_thread
|
||||
%type <ast::stmt> stmt
|
||||
%type <ast::stmt> stmt_or_dev
|
||||
%type <ast::stmt_list::ptr> stmt_list
|
||||
%type <ast::stmt_list::ptr> stmt_or_dev_list
|
||||
%type <ast::stmt_dev::ptr> stmt_dev
|
||||
%type <ast::stmt_list::ptr> stmt_block
|
||||
%type <ast::stmt_expr::ptr> stmt_expr
|
||||
%type <ast::stmt_call::ptr> stmt_call
|
||||
%type <ast::stmt_assign::ptr> stmt_assign
|
||||
%type <ast::stmt_endon::ptr> stmt_endon
|
||||
%type <ast::stmt_notify::ptr> stmt_notify
|
||||
%type <ast::stmt_wait::ptr> stmt_wait
|
||||
%type <ast::stmt_waittill::ptr> stmt_waittill
|
||||
%type <ast::stmt_waittillmatch::ptr> stmt_waittillmatch
|
||||
%type <ast::stmt_waittillframeend::ptr> stmt_waittillframeend
|
||||
%type <ast::stmt_waitframe::ptr> stmt_waitframe
|
||||
%type <ast::stmt_if::ptr> stmt_if
|
||||
%type <ast::stmt_ifelse::ptr> stmt_ifelse
|
||||
%type <ast::stmt_while::ptr> stmt_while
|
||||
%type <ast::stmt_dowhile::ptr> stmt_dowhile
|
||||
%type <ast::stmt_for::ptr> stmt_for
|
||||
%type <ast::stmt_foreach::ptr> stmt_foreach
|
||||
%type <ast::stmt_switch::ptr> stmt_switch
|
||||
%type <ast::stmt_case::ptr> stmt_case
|
||||
%type <ast::stmt_default::ptr> stmt_default
|
||||
%type <ast::stmt_break::ptr> stmt_break
|
||||
%type <ast::stmt_continue::ptr> stmt_continue
|
||||
%type <ast::stmt_return::ptr> stmt_return
|
||||
%type <ast::stmt_breakpoint::ptr> stmt_breakpoint
|
||||
%type <ast::stmt_prof_begin::ptr> stmt_prof_begin
|
||||
%type <ast::stmt_prof_end::ptr> stmt_prof_end
|
||||
%type <ast::expr> expr
|
||||
%type <ast::expr> expr_or_empty
|
||||
%type <ast::expr> expr_assign
|
||||
%type <ast::expr> expr_increment
|
||||
%type <ast::expr> expr_decrement
|
||||
%type <ast::expr> expr_ternary
|
||||
%type <ast::expr> expr_binary
|
||||
%type <ast::expr> expr_primitive
|
||||
%type <ast::expr_complement::ptr> expr_complement
|
||||
%type <ast::expr_negate::ptr> expr_negate
|
||||
%type <ast::expr_not::ptr> expr_not
|
||||
%type <ast::expr_call::ptr> expr_call
|
||||
%type <ast::expr_method::ptr> expr_method
|
||||
%type <ast::call> expr_function
|
||||
%type <ast::call> expr_pointer
|
||||
%type <ast::expr_add_array::ptr> expr_add_array
|
||||
%type <ast::expr_parameters::ptr> expr_parameters
|
||||
%type <ast::expr_arguments::ptr> expr_arguments
|
||||
%type <ast::expr_arguments::ptr> expr_arguments_no_empty
|
||||
%type <ast::expr_reference::ptr> expr_reference
|
||||
%type <ast::expr> expr_tuple
|
||||
%type <ast::expr_tuple::ptr> expr_tuple_arguments
|
||||
%type <ast::expr> expr_tuple_types
|
||||
%type <ast::expr_array::ptr> expr_array
|
||||
%type <ast::expr_field::ptr> expr_field
|
||||
%type <ast::expr_size::ptr> expr_size
|
||||
%type <ast::expr_paren::ptr> expr_paren
|
||||
%type <ast::expr> expr_object
|
||||
%type <ast::expr_thisthread::ptr> expr_thisthread
|
||||
%type <ast::expr_empty_array::ptr> expr_empty_array
|
||||
%type <ast::expr_undefined::ptr> expr_undefined
|
||||
%type <ast::expr_game::ptr> expr_game
|
||||
%type <ast::expr_self::ptr> expr_self
|
||||
%type <ast::expr_anim::ptr> expr_anim
|
||||
%type <ast::expr_level::ptr> expr_level
|
||||
%type <ast::expr_animation::ptr> expr_animation
|
||||
%type <ast::expr_animtree::ptr> expr_animtree
|
||||
%type <ast::expr_identifier::ptr> expr_identifier_nosize
|
||||
%type <ast::expr_identifier::ptr> expr_identifier
|
||||
%type <ast::expr_path::ptr> expr_path
|
||||
%type <ast::expr_istring::ptr> expr_istring
|
||||
%type <ast::expr_string::ptr> expr_string
|
||||
%type <ast::expr_vector::ptr> expr_vector
|
||||
%type <ast::expr_float::ptr> expr_float
|
||||
%type <ast::expr_integer::ptr> expr_integer
|
||||
%type <ast::expr_false::ptr> expr_false
|
||||
%type <ast::expr_true::ptr> expr_true
|
||||
|
||||
%nonassoc SIZEOF
|
||||
%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_EXOR
|
||||
%left BITWISE_AND
|
||||
%left EQUALITY INEQUALITY
|
||||
%left LESS GREATER LESS_EQUAL GREATER_EQUAL
|
||||
%left LSHIFT RSHIFT
|
||||
%left ADD SUB
|
||||
%left MUL 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<ast::program>(@$); }
|
||||
;
|
||||
|
||||
program
|
||||
: program inline
|
||||
{ $$ = std::move($1); }
|
||||
| program include
|
||||
{ $$ = std::move($1); $$->includes.push_back(std::move($2)); }
|
||||
| program declaration
|
||||
{ $$ = std::move($1); $$->declarations.push_back(std::move($2)); }
|
||||
| inline
|
||||
{ $$ = std::make_unique<ast::program>(@$); }
|
||||
| include
|
||||
{ $$ = std::make_unique<ast::program>(@$); $$->includes.push_back(std::move($1)); }
|
||||
| declaration
|
||||
{ $$ = std::make_unique<ast::program>(@$); $$->declarations.push_back(std::move($1)); }
|
||||
;
|
||||
|
||||
inline
|
||||
: INLINE expr_path SEMICOLON { lexer.push_header($2->value); }
|
||||
;
|
||||
|
||||
include
|
||||
: INCLUDE expr_path SEMICOLON
|
||||
{ $$ = std::make_unique<ast::include>(@$, std::move($2)); }
|
||||
;
|
||||
|
||||
declaration
|
||||
: DEVBEGIN { $$.as_dev_begin = std::make_unique<ast::decl_dev_begin>(@$); }
|
||||
| DEVEND { $$.as_dev_end = std::make_unique<ast::decl_dev_end>(@$); }
|
||||
| decl_usingtree { $$.as_usingtree = std::move($1); }
|
||||
| decl_constant { $$.as_constant = std::move($1); }
|
||||
| decl_thread { $$.as_thread = std::move($1); }
|
||||
;
|
||||
|
||||
decl_usingtree
|
||||
: USINGTREE LPAREN expr_string RPAREN SEMICOLON
|
||||
{ lexer.ban_header(@$); $$ = std::make_unique<ast::decl_usingtree>(@$, std::move($3)); }
|
||||
;
|
||||
|
||||
decl_constant
|
||||
: expr_identifier ASSIGN expr SEMICOLON
|
||||
{ $$ = std::make_unique<ast::decl_constant>(@$, std::move($1), std::move($3)); }
|
||||
;
|
||||
|
||||
decl_thread
|
||||
: expr_identifier LPAREN expr_parameters RPAREN stmt_block
|
||||
{ lexer.ban_header(@$); $$ = std::make_unique<ast::decl_thread>(@$, std::move($1), std::move($3), std::move($5)); }
|
||||
;
|
||||
|
||||
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_dowhile { $$.as_dowhile = 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_breakpoint { $$.as_breakpoint = std::move($1); }
|
||||
| stmt_prof_begin { $$.as_prof_begin = std::move($1); }
|
||||
| stmt_prof_end { $$.as_prof_end = std::move($1); }
|
||||
;
|
||||
|
||||
stmt_or_dev
|
||||
: stmt { $$ = std::move($1); }
|
||||
| stmt_dev { $$.as_dev = std::move($1); }
|
||||
;
|
||||
|
||||
stmt_list
|
||||
: stmt_list stmt
|
||||
{ $$ = std::move($1); $$->list.push_back(std::move($2)); }
|
||||
| stmt
|
||||
{ $$ = std::make_unique<ast::stmt_list>(@$); $$->list.push_back(std::move($1)); }
|
||||
;
|
||||
|
||||
stmt_or_dev_list
|
||||
: stmt_or_dev_list stmt_or_dev
|
||||
{ $$ = std::move($1); $$->list.push_back(std::move($2)); }
|
||||
| stmt_or_dev
|
||||
{ $$ = std::make_unique<ast::stmt_list>(@$); $$->list.push_back(std::move($1)); }
|
||||
;
|
||||
|
||||
stmt_dev
|
||||
: DEVBEGIN stmt_list DEVEND { $$ = std::make_unique<ast::stmt_dev>(@$, std::move($2)); }
|
||||
| DEVBEGIN DEVEND { $$ = std::make_unique<ast::stmt_dev>(@$, std::make_unique<ast::stmt_list>(@$)); }
|
||||
;
|
||||
|
||||
stmt_block
|
||||
: LBRACE stmt_or_dev_list RBRACE { $$ = std::move($2); }
|
||||
| LBRACE RBRACE { $$ = std::make_unique<ast::stmt_list>(@$); }
|
||||
;
|
||||
|
||||
stmt_expr
|
||||
: expr_assign
|
||||
{ $$ = std::make_unique<ast::stmt_expr>(@$, std::move($1)); }
|
||||
| expr_increment
|
||||
{ $$ = std::make_unique<ast::stmt_expr>(@$, std::move($1)); }
|
||||
| expr_decrement
|
||||
{ $$ = std::make_unique<ast::stmt_expr>(@$, std::move($1)); }
|
||||
|
|
||||
{ $$ = std::make_unique<ast::stmt_expr>(@$, std::make_unique<ast::node>(@$)); }
|
||||
;
|
||||
|
||||
stmt_call
|
||||
: expr_call SEMICOLON
|
||||
{ $$ = std::make_unique<ast::stmt_call>(@$, ast::expr(std::move($1))); }
|
||||
| expr_method SEMICOLON
|
||||
{ $$ = std::make_unique<ast::stmt_call>(@$, ast::expr(std::move($1))); }
|
||||
;
|
||||
|
||||
stmt_assign
|
||||
: expr_assign SEMICOLON
|
||||
{ $$ = std::make_unique<ast::stmt_assign>(@$, std::move($1)); }
|
||||
| expr_increment SEMICOLON
|
||||
{ $$ = std::make_unique<ast::stmt_assign>(@$, std::move($1)); }
|
||||
| expr_decrement SEMICOLON
|
||||
{ $$ = std::make_unique<ast::stmt_assign>(@$, std::move($1)); }
|
||||
;
|
||||
|
||||
stmt_endon
|
||||
: expr_object ENDON LPAREN expr RPAREN SEMICOLON
|
||||
{ $$ = std::make_unique<ast::stmt_endon>(@$, std::move($1), std::move($4)); }
|
||||
;
|
||||
|
||||
stmt_notify
|
||||
: expr_object NOTIFY LPAREN expr COMMA expr_arguments_no_empty RPAREN SEMICOLON
|
||||
{ $$ = std::make_unique<ast::stmt_notify>(@$, std::move($1), std::move($4), std::move($6)); }
|
||||
| expr_object NOTIFY LPAREN expr RPAREN SEMICOLON
|
||||
{ $$ = std::make_unique<ast::stmt_notify>(@$, std::move($1), std::move($4), std::make_unique<ast::expr_arguments>(@$)); }
|
||||
;
|
||||
|
||||
stmt_wait
|
||||
: WAIT expr SEMICOLON
|
||||
{ $$ = std::make_unique<ast::stmt_wait>(@$, std::move($2)); }
|
||||
;
|
||||
|
||||
stmt_waittill
|
||||
: expr_object WAITTILL LPAREN expr COMMA expr_arguments_no_empty RPAREN SEMICOLON
|
||||
{ $$ = std::make_unique<ast::stmt_waittill>(@$, std::move($1), std::move($4), std::move($6)); }
|
||||
| expr_object WAITTILL LPAREN expr RPAREN SEMICOLON
|
||||
{ $$ = std::make_unique<ast::stmt_waittill>(@$, std::move($1), std::move($4), std::make_unique<ast::expr_arguments>(@$)); }
|
||||
;
|
||||
|
||||
stmt_waittillmatch
|
||||
: expr_object WAITTILLMATCH LPAREN expr COMMA expr_arguments_no_empty RPAREN SEMICOLON
|
||||
{ $$ = std::make_unique<ast::stmt_waittillmatch>(@$, std::move($1), std::move($4), std::move($6)); }
|
||||
| expr_object WAITTILLMATCH LPAREN expr RPAREN SEMICOLON
|
||||
{ $$ = std::make_unique<ast::stmt_waittillmatch>(@$, std::move($1), std::move($4), std::make_unique<ast::expr_arguments>(@$)); }
|
||||
;
|
||||
|
||||
stmt_waittillframeend
|
||||
: WAITTILLFRAMEEND SEMICOLON
|
||||
{ $$ = std::make_unique<ast::stmt_waittillframeend>(@$); }
|
||||
;
|
||||
|
||||
stmt_waitframe
|
||||
: WAITFRAME SEMICOLON
|
||||
{ $$ = std::make_unique<ast::stmt_waitframe>(@$); }
|
||||
| WAITFRAME LPAREN RPAREN SEMICOLON
|
||||
{ $$ = std::make_unique<ast::stmt_waitframe>(@$); }
|
||||
;
|
||||
|
||||
stmt_if
|
||||
: IF LPAREN expr RPAREN stmt %prec THEN
|
||||
{ $$ = std::make_unique<ast::stmt_if>(@$, std::move($3), std::move($5)); }
|
||||
;
|
||||
|
||||
stmt_ifelse
|
||||
: IF LPAREN expr RPAREN stmt ELSE stmt
|
||||
{ $$ = std::make_unique<ast::stmt_ifelse>(@$, std::move($3), std::move($5), std::move($7)); }
|
||||
;
|
||||
|
||||
stmt_while
|
||||
: WHILE LPAREN expr RPAREN stmt
|
||||
{ $$ = std::make_unique<ast::stmt_while>(@$, std::move($3), std::move($5)); }
|
||||
;
|
||||
|
||||
stmt_dowhile
|
||||
: DO stmt WHILE LPAREN expr RPAREN SEMICOLON
|
||||
{ $$ = std::make_unique<ast::stmt_dowhile>(@$, std::move($5), std::move($2)); }
|
||||
;
|
||||
|
||||
stmt_for
|
||||
: FOR LPAREN stmt_expr SEMICOLON expr_or_empty SEMICOLON stmt_expr RPAREN stmt
|
||||
{ $$ = std::make_unique<ast::stmt_for>(@$, ast::stmt(std::move($3)), std::move($5), ast::stmt(std::move($7)), std::move($9)); }
|
||||
;
|
||||
|
||||
stmt_foreach
|
||||
: FOREACH LPAREN expr_identifier IN expr RPAREN stmt
|
||||
{ $$ = std::make_unique<ast::stmt_foreach>(@$, ast::expr(std::move($3)), std::move($5), std::move($7)); }
|
||||
| FOREACH LPAREN expr_identifier COMMA expr_identifier IN expr RPAREN stmt
|
||||
{ $$ = std::make_unique<ast::stmt_foreach>(@$, ast::expr(std::move($3)), ast::expr(std::move($5)), std::move($7), std::move($9)); }
|
||||
;
|
||||
|
||||
stmt_switch
|
||||
: SWITCH LPAREN expr RPAREN stmt_block
|
||||
{ $$ = std::make_unique<ast::stmt_switch>(@$, std::move($3), std::move($5)); }
|
||||
;
|
||||
|
||||
stmt_case
|
||||
: CASE expr_integer COLON
|
||||
{ $$ = std::make_unique<ast::stmt_case>(@$, ast::expr(std::move($2)), std::make_unique<ast::stmt_list>(@$)); }
|
||||
| CASE expr_string COLON
|
||||
{ $$ = std::make_unique<ast::stmt_case>(@$, ast::expr(std::move($2)), std::make_unique<ast::stmt_list>(@$)); }
|
||||
;
|
||||
|
||||
stmt_default
|
||||
: DEFAULT COLON
|
||||
{ $$ = std::make_unique<ast::stmt_default>(@$, std::make_unique<ast::stmt_list>(@$)); }
|
||||
;
|
||||
|
||||
stmt_break
|
||||
: BREAK SEMICOLON
|
||||
{ $$ = std::make_unique<ast::stmt_break>(@$); }
|
||||
;
|
||||
|
||||
stmt_continue
|
||||
: CONTINUE SEMICOLON
|
||||
{ $$ = std::make_unique<ast::stmt_continue>(@$); }
|
||||
;
|
||||
|
||||
stmt_return
|
||||
: RETURN expr SEMICOLON
|
||||
{ $$ = std::make_unique<ast::stmt_return>(@$, std::move($2)); }
|
||||
| RETURN SEMICOLON
|
||||
{ $$ = std::make_unique<ast::stmt_return>(@$, std::make_unique<ast::node>(@$)); }
|
||||
;
|
||||
|
||||
stmt_breakpoint
|
||||
: BREAKPOINT SEMICOLON
|
||||
{ $$ = std::make_unique<ast::stmt_breakpoint>(@$); }
|
||||
;
|
||||
|
||||
stmt_prof_begin
|
||||
: PROFBEGIN LPAREN expr_arguments RPAREN SEMICOLON
|
||||
{ $$ = std::make_unique<ast::stmt_prof_begin>(@$, std::move($3)); }
|
||||
;
|
||||
|
||||
stmt_prof_end
|
||||
: PROFEND LPAREN expr_arguments RPAREN SEMICOLON
|
||||
{ $$ = std::make_unique<ast::stmt_prof_end>(@$, std::move($3)); }
|
||||
;
|
||||
|
||||
expr
|
||||
: expr_ternary { $$ = std::move($1); }
|
||||
| expr_binary { $$ = std::move($1); }
|
||||
| expr_primitive { $$ = std::move($1); }
|
||||
;
|
||||
|
||||
expr_or_empty
|
||||
: expr { $$ = std::move($1); }
|
||||
| { $$.as_node = std::make_unique<ast::node>(@$); }
|
||||
;
|
||||
|
||||
expr_assign
|
||||
: expr_tuple ASSIGN expr
|
||||
{ $$.as_node = std::make_unique<ast::expr_assign_equal>(@$, std::move($1), std::move($3)); }
|
||||
| expr_object ASSIGN expr
|
||||
{ $$.as_node = std::make_unique<ast::expr_assign_equal>(@$, std::move($1), std::move($3)); }
|
||||
| expr_object ASSIGN_BW_OR expr
|
||||
{ $$.as_node = std::make_unique<ast::expr_assign_bitwise_or>(@$, std::move($1), std::move($3)); }
|
||||
| expr_object ASSIGN_BW_AND expr
|
||||
{ $$.as_node = std::make_unique<ast::expr_assign_bitwise_and>(@$, std::move($1), std::move($3)); }
|
||||
| expr_object ASSIGN_BW_EXOR expr
|
||||
{ $$.as_node = std::make_unique<ast::expr_assign_bitwise_exor>(@$, std::move($1), std::move($3)); }
|
||||
| expr_object ASSIGN_LSHIFT expr
|
||||
{ $$.as_node = std::make_unique<ast::expr_assign_shift_left>(@$, std::move($1),std::move( $3)); }
|
||||
| expr_object ASSIGN_RSHIFT expr
|
||||
{ $$.as_node = std::make_unique<ast::expr_assign_shift_right>(@$, std::move($1), std::move($3)); }
|
||||
| expr_object ASSIGN_ADD expr
|
||||
{ $$.as_node = std::make_unique<ast::expr_assign_add>(@$, std::move($1), std::move($3)); }
|
||||
| expr_object ASSIGN_SUB expr
|
||||
{ $$.as_node = std::make_unique<ast::expr_assign_sub>(@$, std::move($1), std::move($3)); }
|
||||
| expr_object ASSIGN_MUL expr
|
||||
{ $$.as_node = std::make_unique<ast::expr_assign_mul>(@$, std::move($1), std::move($3)); }
|
||||
| expr_object ASSIGN_DIV expr
|
||||
{ $$.as_node = std::make_unique<ast::expr_assign_div>(@$, std::move($1), std::move($3)); }
|
||||
| expr_object ASSIGN_MOD expr
|
||||
{ $$.as_node = std::make_unique<ast::expr_assign_mod>(@$, std::move($1), std::move($3)); }
|
||||
;
|
||||
|
||||
expr_increment
|
||||
: INCREMENT expr_object %prec PREINC
|
||||
{ $$.as_node = std::make_unique<ast::expr_increment>(@$, std::move($2), true); }
|
||||
| expr_object INCREMENT %prec POSTINC
|
||||
{ $$.as_node = std::make_unique<ast::expr_increment>(@$, std::move($1), false); }
|
||||
;
|
||||
|
||||
expr_decrement
|
||||
: DECREMENT expr_object %prec PREDEC
|
||||
{ $$.as_node = std::make_unique<ast::expr_decrement>(@$, std::move($2), true); }
|
||||
| expr_object DECREMENT %prec POSTDEC
|
||||
{ $$.as_node = std::make_unique<ast::expr_decrement>(@$, std::move($1), false); }
|
||||
;
|
||||
|
||||
expr_ternary
|
||||
: expr QMARK expr COLON expr %prec TERN
|
||||
{ $$.as_node = std::make_unique<ast::expr_ternary>(@$, std::move($1), std::move($3), std::move($5)); }
|
||||
;
|
||||
|
||||
expr_binary
|
||||
: expr OR expr
|
||||
{ $$.as_node = std::make_unique<ast::expr_or>(@$, std::move($1), std::move($3)); }
|
||||
| expr AND expr
|
||||
{ $$.as_node = std::make_unique<ast::expr_and>(@$, std::move($1), std::move($3)); }
|
||||
| expr EQUALITY expr
|
||||
{ $$.as_node = std::make_unique<ast::expr_equality>(@$, std::move($1), std::move($3)); }
|
||||
| expr INEQUALITY expr
|
||||
{ $$.as_node = std::make_unique<ast::expr_inequality>(@$, std::move($1), std::move($3)); }
|
||||
| expr LESS_EQUAL expr
|
||||
{ $$.as_node = std::make_unique<ast::expr_less_equal>(@$, std::move($1), std::move($3)); }
|
||||
| expr GREATER_EQUAL expr
|
||||
{ $$.as_node = std::make_unique<ast::expr_greater_equal>(@$, std::move($1), std::move($3)); }
|
||||
| expr LESS expr
|
||||
{ $$.as_node = std::make_unique<ast::expr_less>(@$, std::move($1), std::move($3)); }
|
||||
| expr GREATER expr
|
||||
{ $$.as_node = std::make_unique<ast::expr_greater>(@$, std::move($1), std::move($3)); }
|
||||
| expr BITWISE_OR expr
|
||||
{ $$.as_node = std::make_unique<ast::expr_bitwise_or>(@$, std::move($1), std::move($3)); }
|
||||
| expr BITWISE_AND expr
|
||||
{ $$.as_node = std::make_unique<ast::expr_bitwise_and>(@$, std::move($1), std::move($3)); }
|
||||
| expr BITWISE_EXOR expr
|
||||
{ $$.as_node = std::make_unique<ast::expr_bitwise_exor>(@$, std::move($1), std::move($3)); }
|
||||
| expr LSHIFT expr
|
||||
{ $$.as_node = std::make_unique<ast::expr_shift_left>(@$, std::move($1), std::move($3)); }
|
||||
| expr RSHIFT expr
|
||||
{ $$.as_node = std::make_unique<ast::expr_shift_right>(@$, std::move($1), std::move($3)); }
|
||||
| expr ADD expr
|
||||
{ $$.as_node = std::make_unique<ast::expr_add>(@$, std::move($1), std::move($3)); }
|
||||
| expr SUB expr
|
||||
{ $$.as_node = std::make_unique<ast::expr_sub>(@$, std::move($1), std::move($3)); }
|
||||
| expr MUL expr
|
||||
{ $$.as_node = std::make_unique<ast::expr_mul>(@$, std::move($1), std::move($3)); }
|
||||
| expr DIV expr
|
||||
{ $$.as_node = std::make_unique<ast::expr_div>(@$, std::move($1), std::move($3)); }
|
||||
| expr MOD expr
|
||||
{ $$.as_node = std::make_unique<ast::expr_mod>(@$, std::move($1), std::move($3)); }
|
||||
;
|
||||
|
||||
expr_primitive
|
||||
: expr_complement { $$.as_node = std::move($1); }
|
||||
| expr_negate { $$.as_node = std::move($1); }
|
||||
| expr_not { $$.as_node = std::move($1); }
|
||||
| expr_call { $$.as_node = std::move($1); }
|
||||
| expr_method { $$.as_node = std::move($1); }
|
||||
| expr_add_array { $$.as_node = std::move($1); }
|
||||
| expr_reference { $$.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); }
|
||||
| expr_paren { $$.as_node = std::move($1); }
|
||||
| expr_thisthread { $$.as_node = std::move($1); }
|
||||
| expr_empty_array { $$.as_node = std::move($1); }
|
||||
| expr_undefined { $$.as_node = std::move($1); }
|
||||
| expr_game { $$.as_node = std::move($1); }
|
||||
| expr_self { $$.as_node = std::move($1); }
|
||||
| expr_anim { $$.as_node = std::move($1); }
|
||||
| expr_level { $$.as_node = std::move($1); }
|
||||
| expr_animation { $$.as_node = std::move($1); }
|
||||
| expr_animtree { $$.as_node = std::move($1); }
|
||||
| expr_identifier { $$.as_node = std::move($1); }
|
||||
| expr_istring { $$.as_node = std::move($1); }
|
||||
| expr_string { $$.as_node = std::move($1); }
|
||||
| expr_vector { $$.as_node = std::move($1); }
|
||||
| expr_float { $$.as_node = std::move($1); }
|
||||
| expr_integer { $$.as_node = std::move($1); }
|
||||
| expr_false { $$.as_node = std::move($1); }
|
||||
| expr_true { $$.as_node = std::move($1); }
|
||||
;
|
||||
|
||||
expr_complement
|
||||
: COMPLEMENT expr
|
||||
{ $$ = std::make_unique<ast::expr_complement>(@$, std::move($2)); }
|
||||
;
|
||||
|
||||
expr_negate
|
||||
: SUB expr_identifier %prec NEG
|
||||
{ $$ = std::make_unique<ast::expr_negate>(@$, ast::expr(std::move($2))); }
|
||||
| SUB expr_paren %prec NEG
|
||||
{ $$ = std::make_unique<ast::expr_negate>(@$, ast::expr(std::move($2))); }
|
||||
| SUB expr_array %prec NEG
|
||||
{ $$ = std::make_unique<ast::expr_negate>(@$, ast::expr(std::move($2))); }
|
||||
| SUB expr_field %prec NEG
|
||||
{ $$ = std::make_unique<ast::expr_negate>(@$, ast::expr(std::move($2))); }
|
||||
;
|
||||
|
||||
expr_not
|
||||
: NOT expr
|
||||
{ $$ = std::make_unique<ast::expr_not>(@$, std::move($2)); }
|
||||
;
|
||||
|
||||
expr_call
|
||||
: expr_function { $$ = std::make_unique<ast::expr_call>(@$, std::move($1)); }
|
||||
| expr_pointer { $$ = std::make_unique<ast::expr_call>(@$, std::move($1)); }
|
||||
;
|
||||
expr_method
|
||||
: expr_object expr_function { $$ = std::make_unique<ast::expr_method>(@$, std::move($1), std::move($2)); }
|
||||
| expr_object expr_pointer { $$ = std::make_unique<ast::expr_method>(@$, std::move($1), std::move($2)); }
|
||||
;
|
||||
|
||||
expr_function
|
||||
: expr_identifier LPAREN expr_arguments RPAREN
|
||||
{ $$.as_function = std::make_unique<ast::expr_function>(@$, std::make_unique<ast::expr_path>(@$), std::move($1), std::move($3), ast::call::mode::normal); }
|
||||
| expr_path DOUBLECOLON expr_identifier LPAREN expr_arguments RPAREN
|
||||
{ $$.as_function = std::make_unique<ast::expr_function>(@$, std::move($1), std::move($3), std::move($5), ast::call::mode::normal); }
|
||||
| THREAD expr_identifier LPAREN expr_arguments RPAREN
|
||||
{ $$.as_function = std::make_unique<ast::expr_function>(@$, std::make_unique<ast::expr_path>(@$), std::move($2), std::move($4), ast::call::mode::thread); }
|
||||
| THREAD expr_path DOUBLECOLON expr_identifier LPAREN expr_arguments RPAREN
|
||||
{ $$.as_function = std::make_unique<ast::expr_function>(@$, std::move($2), std::move($4), std::move($6), ast::call::mode::thread); }
|
||||
| CHILDTHREAD expr_identifier LPAREN expr_arguments RPAREN
|
||||
{ $$.as_function = std::make_unique<ast::expr_function>(@$, std::make_unique<ast::expr_path>(@$), std::move($2), std::move($4), ast::call::mode::childthread); }
|
||||
| CHILDTHREAD expr_path DOUBLECOLON expr_identifier LPAREN expr_arguments RPAREN
|
||||
{ $$.as_function = std::make_unique<ast::expr_function>(@$, std::move($2), std::move($4), std::move($6), ast::call::mode::childthread); }
|
||||
;
|
||||
|
||||
expr_pointer
|
||||
: LBRACKET LBRACKET expr RBRACKET RBRACKET LPAREN expr_arguments RPAREN
|
||||
{ $$.as_pointer = std::make_unique<ast::expr_pointer>(@$, std::move($3), std::move($7), ast::call::mode::normal); }
|
||||
| THREAD LBRACKET LBRACKET expr RBRACKET RBRACKET LPAREN expr_arguments RPAREN
|
||||
{ $$.as_pointer = std::make_unique<ast::expr_pointer>(@$, std::move($4), std::move($8), ast::call::mode::thread); }
|
||||
| CHILDTHREAD LBRACKET LBRACKET expr RBRACKET RBRACKET LPAREN expr_arguments RPAREN
|
||||
{ $$.as_pointer = std::make_unique<ast::expr_pointer>(@$, std::move($4), std::move($8), ast::call::mode::childthread); }
|
||||
| CALL LBRACKET LBRACKET expr RBRACKET RBRACKET LPAREN expr_arguments RPAREN
|
||||
{ $$.as_pointer = std::make_unique<ast::expr_pointer>(@$, std::move($4), std::move($8), ast::call::mode::builtin); }
|
||||
;
|
||||
|
||||
expr_add_array
|
||||
: LBRACKET expr_arguments_no_empty RBRACKET
|
||||
{ $$ = std::make_unique<ast::expr_add_array>(@$, std::move($2)); }
|
||||
;
|
||||
|
||||
expr_parameters
|
||||
: expr_parameters COMMA expr_identifier
|
||||
{ $$ = std::move($1); $$->list.push_back(std::move($3)); }
|
||||
| expr_identifier
|
||||
{ $$ = std::make_unique<ast::expr_parameters>(@$); $$->list.push_back(std::move($1)); }
|
||||
|
|
||||
{ $$ = std::make_unique<ast::expr_parameters>(@$); }
|
||||
;
|
||||
|
||||
expr_arguments
|
||||
: expr_arguments_no_empty
|
||||
{ $$ = std::move($1); }
|
||||
|
|
||||
{ $$ = std::make_unique<ast::expr_arguments>(@$); }
|
||||
;
|
||||
|
||||
expr_arguments_no_empty
|
||||
: expr_arguments COMMA expr
|
||||
{ $$ = std::move($1); $$->list.push_back(std::move($3)); }
|
||||
| expr %prec ADD_ARRAY
|
||||
{ $$ = std::make_unique<ast::expr_arguments>(@$); $$->list.push_back(std::move($1)); }
|
||||
;
|
||||
|
||||
expr_reference
|
||||
: DOUBLECOLON expr_identifier
|
||||
{ $$ = std::make_unique<ast::expr_reference>(@$, std::make_unique<ast::expr_path>(@$), std::move($2)); }
|
||||
| expr_path DOUBLECOLON expr_identifier
|
||||
{ $$ = std::make_unique<ast::expr_reference>(@$, std::move($1), std::move($3)); }
|
||||
;
|
||||
|
||||
expr_tuple
|
||||
: LBRACKET expr_tuple_arguments RBRACKET
|
||||
{ $$.as_node = std::move($2); }
|
||||
;
|
||||
|
||||
expr_tuple_arguments
|
||||
: expr_tuple_arguments COMMA expr_tuple_types
|
||||
{ $$ = std::move($1); $$->list.push_back(std::move($3)); }
|
||||
| expr_tuple_types
|
||||
{ $$ = std::make_unique<ast::expr_tuple>(@$); $$->list.push_back(std::move($1)); }
|
||||
;
|
||||
|
||||
expr_tuple_types
|
||||
: expr_array { $$.as_node = std::move($1); }
|
||||
| expr_field { $$.as_node = std::move($1); }
|
||||
| expr_identifier { $$.as_node = std::move($1); }
|
||||
;
|
||||
|
||||
expr_array
|
||||
: expr_object LBRACKET expr RBRACKET
|
||||
{ $$ = std::make_unique<ast::expr_array>(@$, std::move($1), std::move($3)); }
|
||||
;
|
||||
|
||||
expr_field
|
||||
: expr_object DOT expr_identifier_nosize
|
||||
{ $$ = std::make_unique<ast::expr_field>(@$, std::move($1), std::move($3)); }
|
||||
;
|
||||
|
||||
expr_size
|
||||
: expr_object DOT SIZE %prec SIZEOF
|
||||
{ $$ = std::make_unique<ast::expr_size>(@$, std::move($1)); }
|
||||
;
|
||||
|
||||
expr_paren
|
||||
: LPAREN expr RPAREN
|
||||
{ $$ = std::make_unique<ast::expr_paren>(@$, std::move($2)); }
|
||||
;
|
||||
|
||||
expr_object
|
||||
: expr_call { $$.as_node = std::move($1); }
|
||||
| expr_method { $$.as_node = std::move($1); }
|
||||
| expr_array { $$.as_node = std::move($1); }
|
||||
| expr_field { $$.as_node = std::move($1); }
|
||||
| expr_game { $$.as_node = std::move($1); }
|
||||
| expr_self { $$.as_node = std::move($1); }
|
||||
| expr_anim { $$.as_node = std::move($1); }
|
||||
| expr_level { $$.as_node = std::move($1); }
|
||||
| expr_identifier { $$.as_node = std::move($1); }
|
||||
;
|
||||
|
||||
expr_thisthread
|
||||
: THISTHREAD
|
||||
{ $$ = std::make_unique<ast::expr_thisthread>(@$); };
|
||||
;
|
||||
|
||||
expr_empty_array
|
||||
: LBRACKET RBRACKET
|
||||
{ $$ = std::make_unique<ast::expr_empty_array>(@$); };
|
||||
;
|
||||
|
||||
expr_undefined
|
||||
: UNDEFINED
|
||||
{ $$ = std::make_unique<ast::expr_undefined>(@$); };
|
||||
;
|
||||
|
||||
expr_game
|
||||
: GAME
|
||||
{ $$ = std::make_unique<ast::expr_game>(@$); };
|
||||
;
|
||||
|
||||
expr_self
|
||||
: SELF
|
||||
{ $$ = std::make_unique<ast::expr_self>(@$); };
|
||||
;
|
||||
|
||||
expr_anim
|
||||
: ANIM
|
||||
{ $$ = std::make_unique<ast::expr_anim>(@$); };
|
||||
;
|
||||
|
||||
expr_level
|
||||
: LEVEL
|
||||
{ $$ = std::make_unique<ast::expr_level>(@$); };
|
||||
;
|
||||
|
||||
expr_animation
|
||||
: MOD IDENTIFIER %prec ANIMREF
|
||||
{ $$ = std::make_unique<ast::expr_animation>(@$, $2); };
|
||||
;
|
||||
|
||||
expr_animtree
|
||||
: ANIMTREE
|
||||
{ $$ = std::make_unique<ast::expr_animtree>(@$); };
|
||||
;
|
||||
|
||||
expr_identifier_nosize
|
||||
: IDENTIFIER
|
||||
{ $$ = std::make_unique<ast::expr_identifier>(@$, $1); };
|
||||
;
|
||||
|
||||
expr_identifier
|
||||
: IDENTIFIER
|
||||
{ $$ = std::make_unique<ast::expr_identifier>(@$, $1); };
|
||||
| SIZE
|
||||
{ $$ = std::make_unique<ast::expr_identifier>(@$, "size"); };
|
||||
;
|
||||
|
||||
expr_path
|
||||
: IDENTIFIER
|
||||
{ $$ = std::make_unique<ast::expr_path>(@$, $1); };
|
||||
| PATH
|
||||
{ $$ = std::make_unique<ast::expr_path>(@$, $1); };
|
||||
;
|
||||
|
||||
expr_istring
|
||||
: ISTRING
|
||||
{ $$ = std::make_unique<ast::expr_istring>(@$, $1); };
|
||||
;
|
||||
|
||||
expr_string
|
||||
: STRING
|
||||
{ $$ = std::make_unique<ast::expr_string>(@$, $1); };
|
||||
;
|
||||
|
||||
expr_vector
|
||||
: LPAREN expr COMMA expr COMMA expr RPAREN
|
||||
{ $$ = std::make_unique<ast::expr_vector>(@$, std::move($2), std::move($4), std::move($6)); };
|
||||
;
|
||||
|
||||
expr_float
|
||||
: SUB FLOAT %prec NEG
|
||||
{ $$ = std::make_unique<ast::expr_float>(@$, "-" + $2); };
|
||||
| FLOAT
|
||||
{ $$ = std::make_unique<ast::expr_float>(@$, $1); };
|
||||
;
|
||||
|
||||
expr_integer
|
||||
: SUB INTEGER %prec NEG
|
||||
{ $$ = std::make_unique<ast::expr_integer>(@$, "-" + $2); };
|
||||
| INTEGER
|
||||
{ $$ = std::make_unique<ast::expr_integer>(@$, $1); };
|
||||
;
|
||||
|
||||
expr_false
|
||||
: FALSE
|
||||
{ $$ = std::make_unique<ast::expr_false>(@$); };
|
||||
;
|
||||
|
||||
expr_true
|
||||
: TRUE
|
||||
{ $$ = std::make_unique<ast::expr_true>(@$); };
|
||||
;
|
||||
|
||||
%%
|
||||
|
||||
void xsk::gsc::h1::parser::error(const xsk::gsc::location& loc, const std::string& msg)
|
||||
{
|
||||
throw xsk::gsc::comp_error(loc, msg);
|
||||
}
|
@ -1,898 +0,0 @@
|
||||
/* Copyright 2022 xensik. All rights reserved.
|
||||
//
|
||||
// Use of this source code is governed by a GNU GPLv3 license
|
||||
// that can be found in the LICENSE file.
|
||||
*/
|
||||
|
||||
%require "3.7"
|
||||
%skeleton "lalr1.cc"
|
||||
%language "c++"
|
||||
%output "parser.cpp"
|
||||
%defines "parser.hpp"
|
||||
%define api.prefix {H2}
|
||||
%define api.namespace {xsk::gsc::h2}
|
||||
%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 { xsk::gsc::h2::lexer& lexer }
|
||||
%parse-param { xsk::gsc::h2::lexer& lexer }
|
||||
%parse-param { xsk::gsc::ast::program::ptr& ast }
|
||||
|
||||
%code requires
|
||||
{
|
||||
#ifdef _MSC_VER
|
||||
#pragma warning(disable:4065)
|
||||
#pragma warning(disable:4127)
|
||||
#endif
|
||||
#include "h2.hpp"
|
||||
namespace xsk::gsc::h2 { class lexer; }
|
||||
}
|
||||
|
||||
%code top
|
||||
{
|
||||
#include "stdafx.hpp"
|
||||
#include "parser.hpp"
|
||||
#include "lexer.hpp"
|
||||
using namespace xsk::gsc;
|
||||
xsk::gsc::h2::parser::symbol_type H2lex(xsk::gsc::h2::lexer& lexer);
|
||||
}
|
||||
|
||||
%token SH_DEFINE "#define"
|
||||
%token SH_UNDEF "#undef"
|
||||
%token SH_IFDEF "#ifdef"
|
||||
%token SH_IFNDEF "#ifndef"
|
||||
%token SH_IF "#if"
|
||||
%token SH_ELIF "#elif"
|
||||
%token SH_ELSE "#else"
|
||||
%token SH_ENDIF "#endif"
|
||||
%token DEVBEGIN "/#"
|
||||
%token DEVEND "#/"
|
||||
%token INLINE "#inline"
|
||||
%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 DO "do"
|
||||
%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 BREAKPOINT "breakpoint"
|
||||
%token PROFBEGIN "prof_begin"
|
||||
%token PROFEND "prof_end"
|
||||
%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_MUL "*="
|
||||
%token ASSIGN_DIV "/="
|
||||
%token ASSIGN_MOD "%="
|
||||
%token ASSIGN_BW_OR "|="
|
||||
%token ASSIGN_BW_AND "&="
|
||||
%token ASSIGN_BW_EXOR "^="
|
||||
%token ASSIGN_RSHIFT ">>="
|
||||
%token ASSIGN_LSHIFT "<<="
|
||||
%token BITWISE_OR "|"
|
||||
%token BITWISE_AND "&"
|
||||
%token BITWISE_EXOR "^"
|
||||
%token ADD "+"
|
||||
%token SUB "-"
|
||||
%token MUL "*"
|
||||
%token DIV "/"
|
||||
%token MOD "%"
|
||||
%token <std::string> PATH "path"
|
||||
%token <std::string> IDENTIFIER "identifier"
|
||||
%token <std::string> STRING "string literal"
|
||||
%token <std::string> ISTRING "localized string"
|
||||
%token <std::string> FLOAT "float"
|
||||
%token <std::string> INTEGER "integer"
|
||||
|
||||
%type <ast::program::ptr> program
|
||||
%type <ast::include::ptr> include
|
||||
%type <ast::decl> declaration
|
||||
%type <ast::decl_usingtree::ptr> decl_usingtree
|
||||
%type <ast::decl_constant::ptr> decl_constant
|
||||
%type <ast::decl_thread::ptr> decl_thread
|
||||
%type <ast::stmt> stmt
|
||||
%type <ast::stmt> stmt_or_dev
|
||||
%type <ast::stmt_list::ptr> stmt_list
|
||||
%type <ast::stmt_list::ptr> stmt_or_dev_list
|
||||
%type <ast::stmt_dev::ptr> stmt_dev
|
||||
%type <ast::stmt_list::ptr> stmt_block
|
||||
%type <ast::stmt_expr::ptr> stmt_expr
|
||||
%type <ast::stmt_call::ptr> stmt_call
|
||||
%type <ast::stmt_assign::ptr> stmt_assign
|
||||
%type <ast::stmt_endon::ptr> stmt_endon
|
||||
%type <ast::stmt_notify::ptr> stmt_notify
|
||||
%type <ast::stmt_wait::ptr> stmt_wait
|
||||
%type <ast::stmt_waittill::ptr> stmt_waittill
|
||||
%type <ast::stmt_waittillmatch::ptr> stmt_waittillmatch
|
||||
%type <ast::stmt_waittillframeend::ptr> stmt_waittillframeend
|
||||
%type <ast::stmt_waitframe::ptr> stmt_waitframe
|
||||
%type <ast::stmt_if::ptr> stmt_if
|
||||
%type <ast::stmt_ifelse::ptr> stmt_ifelse
|
||||
%type <ast::stmt_while::ptr> stmt_while
|
||||
%type <ast::stmt_dowhile::ptr> stmt_dowhile
|
||||
%type <ast::stmt_for::ptr> stmt_for
|
||||
%type <ast::stmt_foreach::ptr> stmt_foreach
|
||||
%type <ast::stmt_switch::ptr> stmt_switch
|
||||
%type <ast::stmt_case::ptr> stmt_case
|
||||
%type <ast::stmt_default::ptr> stmt_default
|
||||
%type <ast::stmt_break::ptr> stmt_break
|
||||
%type <ast::stmt_continue::ptr> stmt_continue
|
||||
%type <ast::stmt_return::ptr> stmt_return
|
||||
%type <ast::stmt_breakpoint::ptr> stmt_breakpoint
|
||||
%type <ast::stmt_prof_begin::ptr> stmt_prof_begin
|
||||
%type <ast::stmt_prof_end::ptr> stmt_prof_end
|
||||
%type <ast::expr> expr
|
||||
%type <ast::expr> expr_or_empty
|
||||
%type <ast::expr> expr_assign
|
||||
%type <ast::expr> expr_increment
|
||||
%type <ast::expr> expr_decrement
|
||||
%type <ast::expr> expr_ternary
|
||||
%type <ast::expr> expr_binary
|
||||
%type <ast::expr> expr_primitive
|
||||
%type <ast::expr_complement::ptr> expr_complement
|
||||
%type <ast::expr_negate::ptr> expr_negate
|
||||
%type <ast::expr_not::ptr> expr_not
|
||||
%type <ast::expr_call::ptr> expr_call
|
||||
%type <ast::expr_method::ptr> expr_method
|
||||
%type <ast::call> expr_function
|
||||
%type <ast::call> expr_pointer
|
||||
%type <ast::expr_add_array::ptr> expr_add_array
|
||||
%type <ast::expr_parameters::ptr> expr_parameters
|
||||
%type <ast::expr_arguments::ptr> expr_arguments
|
||||
%type <ast::expr_arguments::ptr> expr_arguments_no_empty
|
||||
%type <ast::expr_reference::ptr> expr_reference
|
||||
%type <ast::expr> expr_tuple
|
||||
%type <ast::expr_tuple::ptr> expr_tuple_arguments
|
||||
%type <ast::expr> expr_tuple_types
|
||||
%type <ast::expr_array::ptr> expr_array
|
||||
%type <ast::expr_field::ptr> expr_field
|
||||
%type <ast::expr_size::ptr> expr_size
|
||||
%type <ast::expr_paren::ptr> expr_paren
|
||||
%type <ast::expr> expr_object
|
||||
%type <ast::expr_thisthread::ptr> expr_thisthread
|
||||
%type <ast::expr_empty_array::ptr> expr_empty_array
|
||||
%type <ast::expr_undefined::ptr> expr_undefined
|
||||
%type <ast::expr_game::ptr> expr_game
|
||||
%type <ast::expr_self::ptr> expr_self
|
||||
%type <ast::expr_anim::ptr> expr_anim
|
||||
%type <ast::expr_level::ptr> expr_level
|
||||
%type <ast::expr_animation::ptr> expr_animation
|
||||
%type <ast::expr_animtree::ptr> expr_animtree
|
||||
%type <ast::expr_identifier::ptr> expr_identifier_nosize
|
||||
%type <ast::expr_identifier::ptr> expr_identifier
|
||||
%type <ast::expr_path::ptr> expr_path
|
||||
%type <ast::expr_istring::ptr> expr_istring
|
||||
%type <ast::expr_string::ptr> expr_string
|
||||
%type <ast::expr_vector::ptr> expr_vector
|
||||
%type <ast::expr_float::ptr> expr_float
|
||||
%type <ast::expr_integer::ptr> expr_integer
|
||||
%type <ast::expr_false::ptr> expr_false
|
||||
%type <ast::expr_true::ptr> expr_true
|
||||
|
||||
%nonassoc SIZEOF
|
||||
%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_EXOR
|
||||
%left BITWISE_AND
|
||||
%left EQUALITY INEQUALITY
|
||||
%left LESS GREATER LESS_EQUAL GREATER_EQUAL
|
||||
%left LSHIFT RSHIFT
|
||||
%left ADD SUB
|
||||
%left MUL 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<ast::program>(@$); }
|
||||
;
|
||||
|
||||
program
|
||||
: program inline
|
||||
{ $$ = std::move($1); }
|
||||
| program include
|
||||
{ $$ = std::move($1); $$->includes.push_back(std::move($2)); }
|
||||
| program declaration
|
||||
{ $$ = std::move($1); $$->declarations.push_back(std::move($2)); }
|
||||
| inline
|
||||
{ $$ = std::make_unique<ast::program>(@$); }
|
||||
| include
|
||||
{ $$ = std::make_unique<ast::program>(@$); $$->includes.push_back(std::move($1)); }
|
||||
| declaration
|
||||
{ $$ = std::make_unique<ast::program>(@$); $$->declarations.push_back(std::move($1)); }
|
||||
;
|
||||
|
||||
inline
|
||||
: INLINE expr_path SEMICOLON { lexer.push_header($2->value); }
|
||||
;
|
||||
|
||||
include
|
||||
: INCLUDE expr_path SEMICOLON
|
||||
{ $$ = std::make_unique<ast::include>(@$, std::move($2)); }
|
||||
;
|
||||
|
||||
declaration
|
||||
: DEVBEGIN { $$.as_dev_begin = std::make_unique<ast::decl_dev_begin>(@$); }
|
||||
| DEVEND { $$.as_dev_end = std::make_unique<ast::decl_dev_end>(@$); }
|
||||
| decl_usingtree { $$.as_usingtree = std::move($1); }
|
||||
| decl_constant { $$.as_constant = std::move($1); }
|
||||
| decl_thread { $$.as_thread = std::move($1); }
|
||||
;
|
||||
|
||||
decl_usingtree
|
||||
: USINGTREE LPAREN expr_string RPAREN SEMICOLON
|
||||
{ lexer.ban_header(@$); $$ = std::make_unique<ast::decl_usingtree>(@$, std::move($3)); }
|
||||
;
|
||||
|
||||
decl_constant
|
||||
: expr_identifier ASSIGN expr SEMICOLON
|
||||
{ $$ = std::make_unique<ast::decl_constant>(@$, std::move($1), std::move($3)); }
|
||||
;
|
||||
|
||||
decl_thread
|
||||
: expr_identifier LPAREN expr_parameters RPAREN stmt_block
|
||||
{ lexer.ban_header(@$); $$ = std::make_unique<ast::decl_thread>(@$, std::move($1), std::move($3), std::move($5)); }
|
||||
;
|
||||
|
||||
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_dowhile { $$.as_dowhile = 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_breakpoint { $$.as_breakpoint = std::move($1); }
|
||||
| stmt_prof_begin { $$.as_prof_begin = std::move($1); }
|
||||
| stmt_prof_end { $$.as_prof_end = std::move($1); }
|
||||
;
|
||||
|
||||
stmt_or_dev
|
||||
: stmt { $$ = std::move($1); }
|
||||
| stmt_dev { $$.as_dev = std::move($1); }
|
||||
;
|
||||
|
||||
stmt_list
|
||||
: stmt_list stmt
|
||||
{ $$ = std::move($1); $$->list.push_back(std::move($2)); }
|
||||
| stmt
|
||||
{ $$ = std::make_unique<ast::stmt_list>(@$); $$->list.push_back(std::move($1)); }
|
||||
;
|
||||
|
||||
stmt_or_dev_list
|
||||
: stmt_or_dev_list stmt_or_dev
|
||||
{ $$ = std::move($1); $$->list.push_back(std::move($2)); }
|
||||
| stmt_or_dev
|
||||
{ $$ = std::make_unique<ast::stmt_list>(@$); $$->list.push_back(std::move($1)); }
|
||||
;
|
||||
|
||||
stmt_dev
|
||||
: DEVBEGIN stmt_list DEVEND { $$ = std::make_unique<ast::stmt_dev>(@$, std::move($2)); }
|
||||
| DEVBEGIN DEVEND { $$ = std::make_unique<ast::stmt_dev>(@$, std::make_unique<ast::stmt_list>(@$)); }
|
||||
;
|
||||
|
||||
stmt_block
|
||||
: LBRACE stmt_or_dev_list RBRACE { $$ = std::move($2); }
|
||||
| LBRACE RBRACE { $$ = std::make_unique<ast::stmt_list>(@$); }
|
||||
;
|
||||
|
||||
stmt_expr
|
||||
: expr_assign
|
||||
{ $$ = std::make_unique<ast::stmt_expr>(@$, std::move($1)); }
|
||||
| expr_increment
|
||||
{ $$ = std::make_unique<ast::stmt_expr>(@$, std::move($1)); }
|
||||
| expr_decrement
|
||||
{ $$ = std::make_unique<ast::stmt_expr>(@$, std::move($1)); }
|
||||
|
|
||||
{ $$ = std::make_unique<ast::stmt_expr>(@$, std::make_unique<ast::node>(@$)); }
|
||||
;
|
||||
|
||||
stmt_call
|
||||
: expr_call SEMICOLON
|
||||
{ $$ = std::make_unique<ast::stmt_call>(@$, ast::expr(std::move($1))); }
|
||||
| expr_method SEMICOLON
|
||||
{ $$ = std::make_unique<ast::stmt_call>(@$, ast::expr(std::move($1))); }
|
||||
;
|
||||
|
||||
stmt_assign
|
||||
: expr_assign SEMICOLON
|
||||
{ $$ = std::make_unique<ast::stmt_assign>(@$, std::move($1)); }
|
||||
| expr_increment SEMICOLON
|
||||
{ $$ = std::make_unique<ast::stmt_assign>(@$, std::move($1)); }
|
||||
| expr_decrement SEMICOLON
|
||||
{ $$ = std::make_unique<ast::stmt_assign>(@$, std::move($1)); }
|
||||
;
|
||||
|
||||
stmt_endon
|
||||
: expr_object ENDON LPAREN expr RPAREN SEMICOLON
|
||||
{ $$ = std::make_unique<ast::stmt_endon>(@$, std::move($1), std::move($4)); }
|
||||
;
|
||||
|
||||
stmt_notify
|
||||
: expr_object NOTIFY LPAREN expr COMMA expr_arguments_no_empty RPAREN SEMICOLON
|
||||
{ $$ = std::make_unique<ast::stmt_notify>(@$, std::move($1), std::move($4), std::move($6)); }
|
||||
| expr_object NOTIFY LPAREN expr RPAREN SEMICOLON
|
||||
{ $$ = std::make_unique<ast::stmt_notify>(@$, std::move($1), std::move($4), std::make_unique<ast::expr_arguments>(@$)); }
|
||||
;
|
||||
|
||||
stmt_wait
|
||||
: WAIT expr SEMICOLON
|
||||
{ $$ = std::make_unique<ast::stmt_wait>(@$, std::move($2)); }
|
||||
;
|
||||
|
||||
stmt_waittill
|
||||
: expr_object WAITTILL LPAREN expr COMMA expr_arguments_no_empty RPAREN SEMICOLON
|
||||
{ $$ = std::make_unique<ast::stmt_waittill>(@$, std::move($1), std::move($4), std::move($6)); }
|
||||
| expr_object WAITTILL LPAREN expr RPAREN SEMICOLON
|
||||
{ $$ = std::make_unique<ast::stmt_waittill>(@$, std::move($1), std::move($4), std::make_unique<ast::expr_arguments>(@$)); }
|
||||
;
|
||||
|
||||
stmt_waittillmatch
|
||||
: expr_object WAITTILLMATCH LPAREN expr COMMA expr_arguments_no_empty RPAREN SEMICOLON
|
||||
{ $$ = std::make_unique<ast::stmt_waittillmatch>(@$, std::move($1), std::move($4), std::move($6)); }
|
||||
| expr_object WAITTILLMATCH LPAREN expr RPAREN SEMICOLON
|
||||
{ $$ = std::make_unique<ast::stmt_waittillmatch>(@$, std::move($1), std::move($4), std::make_unique<ast::expr_arguments>(@$)); }
|
||||
;
|
||||
|
||||
stmt_waittillframeend
|
||||
: WAITTILLFRAMEEND SEMICOLON
|
||||
{ $$ = std::make_unique<ast::stmt_waittillframeend>(@$); }
|
||||
;
|
||||
|
||||
stmt_waitframe
|
||||
: WAITFRAME SEMICOLON
|
||||
{ $$ = std::make_unique<ast::stmt_waitframe>(@$); }
|
||||
| WAITFRAME LPAREN RPAREN SEMICOLON
|
||||
{ $$ = std::make_unique<ast::stmt_waitframe>(@$); }
|
||||
;
|
||||
|
||||
stmt_if
|
||||
: IF LPAREN expr RPAREN stmt %prec THEN
|
||||
{ $$ = std::make_unique<ast::stmt_if>(@$, std::move($3), std::move($5)); }
|
||||
;
|
||||
|
||||
stmt_ifelse
|
||||
: IF LPAREN expr RPAREN stmt ELSE stmt
|
||||
{ $$ = std::make_unique<ast::stmt_ifelse>(@$, std::move($3), std::move($5), std::move($7)); }
|
||||
;
|
||||
|
||||
stmt_while
|
||||
: WHILE LPAREN expr RPAREN stmt
|
||||
{ $$ = std::make_unique<ast::stmt_while>(@$, std::move($3), std::move($5)); }
|
||||
;
|
||||
|
||||
stmt_dowhile
|
||||
: DO stmt WHILE LPAREN expr RPAREN SEMICOLON
|
||||
{ $$ = std::make_unique<ast::stmt_dowhile>(@$, std::move($5), std::move($2)); }
|
||||
;
|
||||
|
||||
stmt_for
|
||||
: FOR LPAREN stmt_expr SEMICOLON expr_or_empty SEMICOLON stmt_expr RPAREN stmt
|
||||
{ $$ = std::make_unique<ast::stmt_for>(@$, ast::stmt(std::move($3)), std::move($5), ast::stmt(std::move($7)), std::move($9)); }
|
||||
;
|
||||
|
||||
stmt_foreach
|
||||
: FOREACH LPAREN expr_identifier IN expr RPAREN stmt
|
||||
{ $$ = std::make_unique<ast::stmt_foreach>(@$, ast::expr(std::move($3)), std::move($5), std::move($7)); }
|
||||
| FOREACH LPAREN expr_identifier COMMA expr_identifier IN expr RPAREN stmt
|
||||
{ $$ = std::make_unique<ast::stmt_foreach>(@$, ast::expr(std::move($3)), ast::expr(std::move($5)), std::move($7), std::move($9)); }
|
||||
;
|
||||
|
||||
stmt_switch
|
||||
: SWITCH LPAREN expr RPAREN stmt_block
|
||||
{ $$ = std::make_unique<ast::stmt_switch>(@$, std::move($3), std::move($5)); }
|
||||
;
|
||||
|
||||
stmt_case
|
||||
: CASE expr_integer COLON
|
||||
{ $$ = std::make_unique<ast::stmt_case>(@$, ast::expr(std::move($2)), std::make_unique<ast::stmt_list>(@$)); }
|
||||
| CASE expr_string COLON
|
||||
{ $$ = std::make_unique<ast::stmt_case>(@$, ast::expr(std::move($2)), std::make_unique<ast::stmt_list>(@$)); }
|
||||
;
|
||||
|
||||
stmt_default
|
||||
: DEFAULT COLON
|
||||
{ $$ = std::make_unique<ast::stmt_default>(@$, std::make_unique<ast::stmt_list>(@$)); }
|
||||
;
|
||||
|
||||
stmt_break
|
||||
: BREAK SEMICOLON
|
||||
{ $$ = std::make_unique<ast::stmt_break>(@$); }
|
||||
;
|
||||
|
||||
stmt_continue
|
||||
: CONTINUE SEMICOLON
|
||||
{ $$ = std::make_unique<ast::stmt_continue>(@$); }
|
||||
;
|
||||
|
||||
stmt_return
|
||||
: RETURN expr SEMICOLON
|
||||
{ $$ = std::make_unique<ast::stmt_return>(@$, std::move($2)); }
|
||||
| RETURN SEMICOLON
|
||||
{ $$ = std::make_unique<ast::stmt_return>(@$, std::make_unique<ast::node>(@$)); }
|
||||
;
|
||||
|
||||
stmt_breakpoint
|
||||
: BREAKPOINT SEMICOLON
|
||||
{ $$ = std::make_unique<ast::stmt_breakpoint>(@$); }
|
||||
;
|
||||
|
||||
stmt_prof_begin
|
||||
: PROFBEGIN LPAREN expr_arguments RPAREN SEMICOLON
|
||||
{ $$ = std::make_unique<ast::stmt_prof_begin>(@$, std::move($3)); }
|
||||
;
|
||||
|
||||
stmt_prof_end
|
||||
: PROFEND LPAREN expr_arguments RPAREN SEMICOLON
|
||||
{ $$ = std::make_unique<ast::stmt_prof_end>(@$, std::move($3)); }
|
||||
;
|
||||
|
||||
expr
|
||||
: expr_ternary { $$ = std::move($1); }
|
||||
| expr_binary { $$ = std::move($1); }
|
||||
| expr_primitive { $$ = std::move($1); }
|
||||
;
|
||||
|
||||
expr_or_empty
|
||||
: expr { $$ = std::move($1); }
|
||||
| { $$.as_node = std::make_unique<ast::node>(@$); }
|
||||
;
|
||||
|
||||
expr_assign
|
||||
: expr_tuple ASSIGN expr
|
||||
{ $$.as_node = std::make_unique<ast::expr_assign_equal>(@$, std::move($1), std::move($3)); }
|
||||
| expr_object ASSIGN expr
|
||||
{ $$.as_node = std::make_unique<ast::expr_assign_equal>(@$, std::move($1), std::move($3)); }
|
||||
| expr_object ASSIGN_BW_OR expr
|
||||
{ $$.as_node = std::make_unique<ast::expr_assign_bitwise_or>(@$, std::move($1), std::move($3)); }
|
||||
| expr_object ASSIGN_BW_AND expr
|
||||
{ $$.as_node = std::make_unique<ast::expr_assign_bitwise_and>(@$, std::move($1), std::move($3)); }
|
||||
| expr_object ASSIGN_BW_EXOR expr
|
||||
{ $$.as_node = std::make_unique<ast::expr_assign_bitwise_exor>(@$, std::move($1), std::move($3)); }
|
||||
| expr_object ASSIGN_LSHIFT expr
|
||||
{ $$.as_node = std::make_unique<ast::expr_assign_shift_left>(@$, std::move($1),std::move( $3)); }
|
||||
| expr_object ASSIGN_RSHIFT expr
|
||||
{ $$.as_node = std::make_unique<ast::expr_assign_shift_right>(@$, std::move($1), std::move($3)); }
|
||||
| expr_object ASSIGN_ADD expr
|
||||
{ $$.as_node = std::make_unique<ast::expr_assign_add>(@$, std::move($1), std::move($3)); }
|
||||
| expr_object ASSIGN_SUB expr
|
||||
{ $$.as_node = std::make_unique<ast::expr_assign_sub>(@$, std::move($1), std::move($3)); }
|
||||
| expr_object ASSIGN_MUL expr
|
||||
{ $$.as_node = std::make_unique<ast::expr_assign_mul>(@$, std::move($1), std::move($3)); }
|
||||
| expr_object ASSIGN_DIV expr
|
||||
{ $$.as_node = std::make_unique<ast::expr_assign_div>(@$, std::move($1), std::move($3)); }
|
||||
| expr_object ASSIGN_MOD expr
|
||||
{ $$.as_node = std::make_unique<ast::expr_assign_mod>(@$, std::move($1), std::move($3)); }
|
||||
;
|
||||
|
||||
expr_increment
|
||||
: INCREMENT expr_object %prec PREINC
|
||||
{ $$.as_node = std::make_unique<ast::expr_increment>(@$, std::move($2), true); }
|
||||
| expr_object INCREMENT %prec POSTINC
|
||||
{ $$.as_node = std::make_unique<ast::expr_increment>(@$, std::move($1), false); }
|
||||
;
|
||||
|
||||
expr_decrement
|
||||
: DECREMENT expr_object %prec PREDEC
|
||||
{ $$.as_node = std::make_unique<ast::expr_decrement>(@$, std::move($2), true); }
|
||||
| expr_object DECREMENT %prec POSTDEC
|
||||
{ $$.as_node = std::make_unique<ast::expr_decrement>(@$, std::move($1), false); }
|
||||
;
|
||||
|
||||
expr_ternary
|
||||
: expr QMARK expr COLON expr %prec TERN
|
||||
{ $$.as_node = std::make_unique<ast::expr_ternary>(@$, std::move($1), std::move($3), std::move($5)); }
|
||||
;
|
||||
|
||||
expr_binary
|
||||
: expr OR expr
|
||||
{ $$.as_node = std::make_unique<ast::expr_or>(@$, std::move($1), std::move($3)); }
|
||||
| expr AND expr
|
||||
{ $$.as_node = std::make_unique<ast::expr_and>(@$, std::move($1), std::move($3)); }
|
||||
| expr EQUALITY expr
|
||||
{ $$.as_node = std::make_unique<ast::expr_equality>(@$, std::move($1), std::move($3)); }
|
||||
| expr INEQUALITY expr
|
||||
{ $$.as_node = std::make_unique<ast::expr_inequality>(@$, std::move($1), std::move($3)); }
|
||||
| expr LESS_EQUAL expr
|
||||
{ $$.as_node = std::make_unique<ast::expr_less_equal>(@$, std::move($1), std::move($3)); }
|
||||
| expr GREATER_EQUAL expr
|
||||
{ $$.as_node = std::make_unique<ast::expr_greater_equal>(@$, std::move($1), std::move($3)); }
|
||||
| expr LESS expr
|
||||
{ $$.as_node = std::make_unique<ast::expr_less>(@$, std::move($1), std::move($3)); }
|
||||
| expr GREATER expr
|
||||
{ $$.as_node = std::make_unique<ast::expr_greater>(@$, std::move($1), std::move($3)); }
|
||||
| expr BITWISE_OR expr
|
||||
{ $$.as_node = std::make_unique<ast::expr_bitwise_or>(@$, std::move($1), std::move($3)); }
|
||||
| expr BITWISE_AND expr
|
||||
{ $$.as_node = std::make_unique<ast::expr_bitwise_and>(@$, std::move($1), std::move($3)); }
|
||||
| expr BITWISE_EXOR expr
|
||||
{ $$.as_node = std::make_unique<ast::expr_bitwise_exor>(@$, std::move($1), std::move($3)); }
|
||||
| expr LSHIFT expr
|
||||
{ $$.as_node = std::make_unique<ast::expr_shift_left>(@$, std::move($1), std::move($3)); }
|
||||
| expr RSHIFT expr
|
||||
{ $$.as_node = std::make_unique<ast::expr_shift_right>(@$, std::move($1), std::move($3)); }
|
||||
| expr ADD expr
|
||||
{ $$.as_node = std::make_unique<ast::expr_add>(@$, std::move($1), std::move($3)); }
|
||||
| expr SUB expr
|
||||
{ $$.as_node = std::make_unique<ast::expr_sub>(@$, std::move($1), std::move($3)); }
|
||||
| expr MUL expr
|
||||
{ $$.as_node = std::make_unique<ast::expr_mul>(@$, std::move($1), std::move($3)); }
|
||||
| expr DIV expr
|
||||
{ $$.as_node = std::make_unique<ast::expr_div>(@$, std::move($1), std::move($3)); }
|
||||
| expr MOD expr
|
||||
{ $$.as_node = std::make_unique<ast::expr_mod>(@$, std::move($1), std::move($3)); }
|
||||
;
|
||||
|
||||
expr_primitive
|
||||
: expr_complement { $$.as_node = std::move($1); }
|
||||
| expr_negate { $$.as_node = std::move($1); }
|
||||
| expr_not { $$.as_node = std::move($1); }
|
||||
| expr_call { $$.as_node = std::move($1); }
|
||||
| expr_method { $$.as_node = std::move($1); }
|
||||
| expr_add_array { $$.as_node = std::move($1); }
|
||||
| expr_reference { $$.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); }
|
||||
| expr_paren { $$.as_node = std::move($1); }
|
||||
| expr_thisthread { $$.as_node = std::move($1); }
|
||||
| expr_empty_array { $$.as_node = std::move($1); }
|
||||
| expr_undefined { $$.as_node = std::move($1); }
|
||||
| expr_game { $$.as_node = std::move($1); }
|
||||
| expr_self { $$.as_node = std::move($1); }
|
||||
| expr_anim { $$.as_node = std::move($1); }
|
||||
| expr_level { $$.as_node = std::move($1); }
|
||||
| expr_animation { $$.as_node = std::move($1); }
|
||||
| expr_animtree { $$.as_node = std::move($1); }
|
||||
| expr_identifier { $$.as_node = std::move($1); }
|
||||
| expr_istring { $$.as_node = std::move($1); }
|
||||
| expr_string { $$.as_node = std::move($1); }
|
||||
| expr_vector { $$.as_node = std::move($1); }
|
||||
| expr_float { $$.as_node = std::move($1); }
|
||||
| expr_integer { $$.as_node = std::move($1); }
|
||||
| expr_false { $$.as_node = std::move($1); }
|
||||
| expr_true { $$.as_node = std::move($1); }
|
||||
;
|
||||
|
||||
expr_complement
|
||||
: COMPLEMENT expr
|
||||
{ $$ = std::make_unique<ast::expr_complement>(@$, std::move($2)); }
|
||||
;
|
||||
|
||||
expr_negate
|
||||
: SUB expr_identifier %prec NEG
|
||||
{ $$ = std::make_unique<ast::expr_negate>(@$, ast::expr(std::move($2))); }
|
||||
| SUB expr_paren %prec NEG
|
||||
{ $$ = std::make_unique<ast::expr_negate>(@$, ast::expr(std::move($2))); }
|
||||
| SUB expr_array %prec NEG
|
||||
{ $$ = std::make_unique<ast::expr_negate>(@$, ast::expr(std::move($2))); }
|
||||
| SUB expr_field %prec NEG
|
||||
{ $$ = std::make_unique<ast::expr_negate>(@$, ast::expr(std::move($2))); }
|
||||
;
|
||||
|
||||
expr_not
|
||||
: NOT expr
|
||||
{ $$ = std::make_unique<ast::expr_not>(@$, std::move($2)); }
|
||||
;
|
||||
|
||||
expr_call
|
||||
: expr_function { $$ = std::make_unique<ast::expr_call>(@$, std::move($1)); }
|
||||
| expr_pointer { $$ = std::make_unique<ast::expr_call>(@$, std::move($1)); }
|
||||
;
|
||||
expr_method
|
||||
: expr_object expr_function { $$ = std::make_unique<ast::expr_method>(@$, std::move($1), std::move($2)); }
|
||||
| expr_object expr_pointer { $$ = std::make_unique<ast::expr_method>(@$, std::move($1), std::move($2)); }
|
||||
;
|
||||
|
||||
expr_function
|
||||
: expr_identifier LPAREN expr_arguments RPAREN
|
||||
{ $$.as_function = std::make_unique<ast::expr_function>(@$, std::make_unique<ast::expr_path>(@$), std::move($1), std::move($3), ast::call::mode::normal); }
|
||||
| expr_path DOUBLECOLON expr_identifier LPAREN expr_arguments RPAREN
|
||||
{ $$.as_function = std::make_unique<ast::expr_function>(@$, std::move($1), std::move($3), std::move($5), ast::call::mode::normal); }
|
||||
| THREAD expr_identifier LPAREN expr_arguments RPAREN
|
||||
{ $$.as_function = std::make_unique<ast::expr_function>(@$, std::make_unique<ast::expr_path>(@$), std::move($2), std::move($4), ast::call::mode::thread); }
|
||||
| THREAD expr_path DOUBLECOLON expr_identifier LPAREN expr_arguments RPAREN
|
||||
{ $$.as_function = std::make_unique<ast::expr_function>(@$, std::move($2), std::move($4), std::move($6), ast::call::mode::thread); }
|
||||
| CHILDTHREAD expr_identifier LPAREN expr_arguments RPAREN
|
||||
{ $$.as_function = std::make_unique<ast::expr_function>(@$, std::make_unique<ast::expr_path>(@$), std::move($2), std::move($4), ast::call::mode::childthread); }
|
||||
| CHILDTHREAD expr_path DOUBLECOLON expr_identifier LPAREN expr_arguments RPAREN
|
||||
{ $$.as_function = std::make_unique<ast::expr_function>(@$, std::move($2), std::move($4), std::move($6), ast::call::mode::childthread); }
|
||||
;
|
||||
|
||||
expr_pointer
|
||||
: LBRACKET LBRACKET expr RBRACKET RBRACKET LPAREN expr_arguments RPAREN
|
||||
{ $$.as_pointer = std::make_unique<ast::expr_pointer>(@$, std::move($3), std::move($7), ast::call::mode::normal); }
|
||||
| THREAD LBRACKET LBRACKET expr RBRACKET RBRACKET LPAREN expr_arguments RPAREN
|
||||
{ $$.as_pointer = std::make_unique<ast::expr_pointer>(@$, std::move($4), std::move($8), ast::call::mode::thread); }
|
||||
| CHILDTHREAD LBRACKET LBRACKET expr RBRACKET RBRACKET LPAREN expr_arguments RPAREN
|
||||
{ $$.as_pointer = std::make_unique<ast::expr_pointer>(@$, std::move($4), std::move($8), ast::call::mode::childthread); }
|
||||
| CALL LBRACKET LBRACKET expr RBRACKET RBRACKET LPAREN expr_arguments RPAREN
|
||||
{ $$.as_pointer = std::make_unique<ast::expr_pointer>(@$, std::move($4), std::move($8), ast::call::mode::builtin); }
|
||||
;
|
||||
|
||||
expr_add_array
|
||||
: LBRACKET expr_arguments_no_empty RBRACKET
|
||||
{ $$ = std::make_unique<ast::expr_add_array>(@$, std::move($2)); }
|
||||
;
|
||||
|
||||
expr_parameters
|
||||
: expr_parameters COMMA expr_identifier
|
||||
{ $$ = std::move($1); $$->list.push_back(std::move($3)); }
|
||||
| expr_identifier
|
||||
{ $$ = std::make_unique<ast::expr_parameters>(@$); $$->list.push_back(std::move($1)); }
|
||||
|
|
||||
{ $$ = std::make_unique<ast::expr_parameters>(@$); }
|
||||
;
|
||||
|
||||
expr_arguments
|
||||
: expr_arguments_no_empty
|
||||
{ $$ = std::move($1); }
|
||||
|
|
||||
{ $$ = std::make_unique<ast::expr_arguments>(@$); }
|
||||
;
|
||||
|
||||
expr_arguments_no_empty
|
||||
: expr_arguments COMMA expr
|
||||
{ $$ = std::move($1); $$->list.push_back(std::move($3)); }
|
||||
| expr %prec ADD_ARRAY
|
||||
{ $$ = std::make_unique<ast::expr_arguments>(@$); $$->list.push_back(std::move($1)); }
|
||||
;
|
||||
|
||||
expr_reference
|
||||
: DOUBLECOLON expr_identifier
|
||||
{ $$ = std::make_unique<ast::expr_reference>(@$, std::make_unique<ast::expr_path>(@$), std::move($2)); }
|
||||
| expr_path DOUBLECOLON expr_identifier
|
||||
{ $$ = std::make_unique<ast::expr_reference>(@$, std::move($1), std::move($3)); }
|
||||
;
|
||||
|
||||
expr_tuple
|
||||
: LBRACKET expr_tuple_arguments RBRACKET
|
||||
{ $$.as_node = std::move($2); }
|
||||
;
|
||||
|
||||
expr_tuple_arguments
|
||||
: expr_tuple_arguments COMMA expr_tuple_types
|
||||
{ $$ = std::move($1); $$->list.push_back(std::move($3)); }
|
||||
| expr_tuple_types
|
||||
{ $$ = std::make_unique<ast::expr_tuple>(@$); $$->list.push_back(std::move($1)); }
|
||||
;
|
||||
|
||||
expr_tuple_types
|
||||
: expr_array { $$.as_node = std::move($1); }
|
||||
| expr_field { $$.as_node = std::move($1); }
|
||||
| expr_identifier { $$.as_node = std::move($1); }
|
||||
;
|
||||
|
||||
expr_array
|
||||
: expr_object LBRACKET expr RBRACKET
|
||||
{ $$ = std::make_unique<ast::expr_array>(@$, std::move($1), std::move($3)); }
|
||||
;
|
||||
|
||||
expr_field
|
||||
: expr_object DOT expr_identifier_nosize
|
||||
{ $$ = std::make_unique<ast::expr_field>(@$, std::move($1), std::move($3)); }
|
||||
;
|
||||
|
||||
expr_size
|
||||
: expr_object DOT SIZE %prec SIZEOF
|
||||
{ $$ = std::make_unique<ast::expr_size>(@$, std::move($1)); }
|
||||
;
|
||||
|
||||
expr_paren
|
||||
: LPAREN expr RPAREN
|
||||
{ $$ = std::make_unique<ast::expr_paren>(@$, std::move($2)); }
|
||||
;
|
||||
|
||||
expr_object
|
||||
: expr_call { $$.as_node = std::move($1); }
|
||||
| expr_method { $$.as_node = std::move($1); }
|
||||
| expr_array { $$.as_node = std::move($1); }
|
||||
| expr_field { $$.as_node = std::move($1); }
|
||||
| expr_game { $$.as_node = std::move($1); }
|
||||
| expr_self { $$.as_node = std::move($1); }
|
||||
| expr_anim { $$.as_node = std::move($1); }
|
||||
| expr_level { $$.as_node = std::move($1); }
|
||||
| expr_identifier { $$.as_node = std::move($1); }
|
||||
;
|
||||
|
||||
expr_thisthread
|
||||
: THISTHREAD
|
||||
{ $$ = std::make_unique<ast::expr_thisthread>(@$); };
|
||||
;
|
||||
|
||||
expr_empty_array
|
||||
: LBRACKET RBRACKET
|
||||
{ $$ = std::make_unique<ast::expr_empty_array>(@$); };
|
||||
;
|
||||
|
||||
expr_undefined
|
||||
: UNDEFINED
|
||||
{ $$ = std::make_unique<ast::expr_undefined>(@$); };
|
||||
;
|
||||
|
||||
expr_game
|
||||
: GAME
|
||||
{ $$ = std::make_unique<ast::expr_game>(@$); };
|
||||
;
|
||||
|
||||
expr_self
|
||||
: SELF
|
||||
{ $$ = std::make_unique<ast::expr_self>(@$); };
|
||||
;
|
||||
|
||||
expr_anim
|
||||
: ANIM
|
||||
{ $$ = std::make_unique<ast::expr_anim>(@$); };
|
||||
;
|
||||
|
||||
expr_level
|
||||
: LEVEL
|
||||
{ $$ = std::make_unique<ast::expr_level>(@$); };
|
||||
;
|
||||
|
||||
expr_animation
|
||||
: MOD IDENTIFIER %prec ANIMREF
|
||||
{ $$ = std::make_unique<ast::expr_animation>(@$, $2); };
|
||||
;
|
||||
|
||||
expr_animtree
|
||||
: ANIMTREE
|
||||
{ $$ = std::make_unique<ast::expr_animtree>(@$); };
|
||||
;
|
||||
|
||||
expr_identifier_nosize
|
||||
: IDENTIFIER
|
||||
{ $$ = std::make_unique<ast::expr_identifier>(@$, $1); };
|
||||
;
|
||||
|
||||
expr_identifier
|
||||
: IDENTIFIER
|
||||
{ $$ = std::make_unique<ast::expr_identifier>(@$, $1); };
|
||||
| SIZE
|
||||
{ $$ = std::make_unique<ast::expr_identifier>(@$, "size"); };
|
||||
;
|
||||
|
||||
expr_path
|
||||
: IDENTIFIER
|
||||
{ $$ = std::make_unique<ast::expr_path>(@$, $1); };
|
||||
| PATH
|
||||
{ $$ = std::make_unique<ast::expr_path>(@$, $1); };
|
||||
;
|
||||
|
||||
expr_istring
|
||||
: ISTRING
|
||||
{ $$ = std::make_unique<ast::expr_istring>(@$, $1); };
|
||||
;
|
||||
|
||||
expr_string
|
||||
: STRING
|
||||
{ $$ = std::make_unique<ast::expr_string>(@$, $1); };
|
||||
;
|
||||
|
||||
expr_vector
|
||||
: LPAREN expr COMMA expr COMMA expr RPAREN
|
||||
{ $$ = std::make_unique<ast::expr_vector>(@$, std::move($2), std::move($4), std::move($6)); };
|
||||
;
|
||||
|
||||
expr_float
|
||||
: SUB FLOAT %prec NEG
|
||||
{ $$ = std::make_unique<ast::expr_float>(@$, "-" + $2); };
|
||||
| FLOAT
|
||||
{ $$ = std::make_unique<ast::expr_float>(@$, $1); };
|
||||
;
|
||||
|
||||
expr_integer
|
||||
: SUB INTEGER %prec NEG
|
||||
{ $$ = std::make_unique<ast::expr_integer>(@$, "-" + $2); };
|
||||
| INTEGER
|
||||
{ $$ = std::make_unique<ast::expr_integer>(@$, $1); };
|
||||
;
|
||||
|
||||
expr_false
|
||||
: FALSE
|
||||
{ $$ = std::make_unique<ast::expr_false>(@$); };
|
||||
;
|
||||
|
||||
expr_true
|
||||
: TRUE
|
||||
{ $$ = std::make_unique<ast::expr_true>(@$); };
|
||||
;
|
||||
|
||||
%%
|
||||
|
||||
void xsk::gsc::h2::parser::error(const xsk::gsc::location& loc, const std::string& msg)
|
||||
{
|
||||
throw xsk::gsc::comp_error(loc, msg);
|
||||
}
|
@ -1,9 +0,0 @@
|
||||
generate: iw5
|
||||
|
||||
clean:
|
||||
rm -rf ./parser.hpp
|
||||
rm -rf ./parser.cpp
|
||||
|
||||
iw5: parser.ypp
|
||||
bison parser.ypp -Wcounterexamples
|
||||
mv parser.hpp parser.cpp ../../src/iw5/xsk/
|
@ -1,888 +0,0 @@
|
||||
/* Copyright 2022 xensik. All rights reserved.
|
||||
//
|
||||
// Use of this source code is governed by a GNU GPLv3 license
|
||||
// that can be found in the LICENSE file.
|
||||
*/
|
||||
|
||||
%require "3.7"
|
||||
%skeleton "lalr1.cc"
|
||||
%language "c++"
|
||||
%output "parser.cpp"
|
||||
%defines "parser.hpp"
|
||||
%define api.prefix {IW5}
|
||||
%define api.namespace {xsk::gsc::iw5}
|
||||
%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 { xsk::gsc::iw5::lexer& lexer }
|
||||
%parse-param { xsk::gsc::iw5::lexer& lexer }
|
||||
%parse-param { xsk::gsc::ast::program::ptr& ast }
|
||||
|
||||
%code requires
|
||||
{
|
||||
#ifdef _MSC_VER
|
||||
#pragma warning(disable:4065)
|
||||
#pragma warning(disable:4127)
|
||||
#endif
|
||||
#include "iw5.hpp"
|
||||
namespace xsk::gsc::iw5 { class lexer; }
|
||||
}
|
||||
|
||||
%code top
|
||||
{
|
||||
#include "stdafx.hpp"
|
||||
#include "parser.hpp"
|
||||
#include "lexer.hpp"
|
||||
using namespace xsk::gsc;
|
||||
xsk::gsc::iw5::parser::symbol_type IW5lex(xsk::gsc::iw5::lexer& lexer);
|
||||
}
|
||||
|
||||
%token SH_DEFINE "#define"
|
||||
%token SH_UNDEF "#undef"
|
||||
%token SH_IFDEF "#ifdef"
|
||||
%token SH_IFNDEF "#ifndef"
|
||||
%token SH_IF "#if"
|
||||
%token SH_ELIF "#elif"
|
||||
%token SH_ELSE "#else"
|
||||
%token SH_ENDIF "#endif"
|
||||
%token DEVBEGIN "/#"
|
||||
%token DEVEND "#/"
|
||||
%token INLINE "#inline"
|
||||
%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 IF "if"
|
||||
%token ELSE "else"
|
||||
%token DO "do"
|
||||
%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 BREAKPOINT "breakpoint"
|
||||
%token PROFBEGIN "prof_begin"
|
||||
%token PROFEND "prof_end"
|
||||
%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_MUL "*="
|
||||
%token ASSIGN_DIV "/="
|
||||
%token ASSIGN_MOD "%="
|
||||
%token ASSIGN_BW_OR "|="
|
||||
%token ASSIGN_BW_AND "&="
|
||||
%token ASSIGN_BW_EXOR "^="
|
||||
%token ASSIGN_RSHIFT ">>="
|
||||
%token ASSIGN_LSHIFT "<<="
|
||||
%token BITWISE_OR "|"
|
||||
%token BITWISE_AND "&"
|
||||
%token BITWISE_EXOR "^"
|
||||
%token ADD "+"
|
||||
%token SUB "-"
|
||||
%token MUL "*"
|
||||
%token DIV "/"
|
||||
%token MOD "%"
|
||||
%token <std::string> PATH "path"
|
||||
%token <std::string> IDENTIFIER "identifier"
|
||||
%token <std::string> STRING "string literal"
|
||||
%token <std::string> ISTRING "localized string"
|
||||
%token <std::string> FLOAT "float"
|
||||
%token <std::string> INTEGER "integer"
|
||||
|
||||
%type <ast::program::ptr> program
|
||||
%type <ast::include::ptr> include
|
||||
%type <ast::decl> declaration
|
||||
%type <ast::decl_usingtree::ptr> decl_usingtree
|
||||
%type <ast::decl_constant::ptr> decl_constant
|
||||
%type <ast::decl_thread::ptr> decl_thread
|
||||
%type <ast::stmt> stmt
|
||||
%type <ast::stmt> stmt_or_dev
|
||||
%type <ast::stmt_list::ptr> stmt_list
|
||||
%type <ast::stmt_list::ptr> stmt_or_dev_list
|
||||
%type <ast::stmt_dev::ptr> stmt_dev
|
||||
%type <ast::stmt_list::ptr> stmt_block
|
||||
%type <ast::stmt_expr::ptr> stmt_expr
|
||||
%type <ast::stmt_call::ptr> stmt_call
|
||||
%type <ast::stmt_assign::ptr> stmt_assign
|
||||
%type <ast::stmt_endon::ptr> stmt_endon
|
||||
%type <ast::stmt_notify::ptr> stmt_notify
|
||||
%type <ast::stmt_wait::ptr> stmt_wait
|
||||
%type <ast::stmt_waittill::ptr> stmt_waittill
|
||||
%type <ast::stmt_waittillmatch::ptr> stmt_waittillmatch
|
||||
%type <ast::stmt_waittillframeend::ptr> stmt_waittillframeend
|
||||
%type <ast::stmt_if::ptr> stmt_if
|
||||
%type <ast::stmt_ifelse::ptr> stmt_ifelse
|
||||
%type <ast::stmt_while::ptr> stmt_while
|
||||
%type <ast::stmt_dowhile::ptr> stmt_dowhile
|
||||
%type <ast::stmt_for::ptr> stmt_for
|
||||
%type <ast::stmt_foreach::ptr> stmt_foreach
|
||||
%type <ast::stmt_switch::ptr> stmt_switch
|
||||
%type <ast::stmt_case::ptr> stmt_case
|
||||
%type <ast::stmt_default::ptr> stmt_default
|
||||
%type <ast::stmt_break::ptr> stmt_break
|
||||
%type <ast::stmt_continue::ptr> stmt_continue
|
||||
%type <ast::stmt_return::ptr> stmt_return
|
||||
%type <ast::stmt_breakpoint::ptr> stmt_breakpoint
|
||||
%type <ast::stmt_prof_begin::ptr> stmt_prof_begin
|
||||
%type <ast::stmt_prof_end::ptr> stmt_prof_end
|
||||
%type <ast::expr> expr
|
||||
%type <ast::expr> expr_or_empty
|
||||
%type <ast::expr> expr_assign
|
||||
%type <ast::expr> expr_increment
|
||||
%type <ast::expr> expr_decrement
|
||||
%type <ast::expr> expr_ternary
|
||||
%type <ast::expr> expr_binary
|
||||
%type <ast::expr> expr_primitive
|
||||
%type <ast::expr_complement::ptr> expr_complement
|
||||
%type <ast::expr_negate::ptr> expr_negate
|
||||
%type <ast::expr_not::ptr> expr_not
|
||||
%type <ast::expr_call::ptr> expr_call
|
||||
%type <ast::expr_method::ptr> expr_method
|
||||
%type <ast::call> expr_function
|
||||
%type <ast::call> expr_pointer
|
||||
%type <ast::expr_add_array::ptr> expr_add_array
|
||||
%type <ast::expr_parameters::ptr> expr_parameters
|
||||
%type <ast::expr_arguments::ptr> expr_arguments
|
||||
%type <ast::expr_arguments::ptr> expr_arguments_no_empty
|
||||
%type <ast::expr_reference::ptr> expr_reference
|
||||
%type <ast::expr> expr_tuple
|
||||
%type <ast::expr_tuple::ptr> expr_tuple_arguments
|
||||
%type <ast::expr> expr_tuple_types
|
||||
%type <ast::expr_array::ptr> expr_array
|
||||
%type <ast::expr_field::ptr> expr_field
|
||||
%type <ast::expr_size::ptr> expr_size
|
||||
%type <ast::expr_paren::ptr> expr_paren
|
||||
%type <ast::expr> expr_object
|
||||
%type <ast::expr_thisthread::ptr> expr_thisthread
|
||||
%type <ast::expr_empty_array::ptr> expr_empty_array
|
||||
%type <ast::expr_undefined::ptr> expr_undefined
|
||||
%type <ast::expr_game::ptr> expr_game
|
||||
%type <ast::expr_self::ptr> expr_self
|
||||
%type <ast::expr_anim::ptr> expr_anim
|
||||
%type <ast::expr_level::ptr> expr_level
|
||||
%type <ast::expr_animation::ptr> expr_animation
|
||||
%type <ast::expr_animtree::ptr> expr_animtree
|
||||
%type <ast::expr_identifier::ptr> expr_identifier_nosize
|
||||
%type <ast::expr_identifier::ptr> expr_identifier
|
||||
%type <ast::expr_path::ptr> expr_path
|
||||
%type <ast::expr_istring::ptr> expr_istring
|
||||
%type <ast::expr_string::ptr> expr_string
|
||||
%type <ast::expr_vector::ptr> expr_vector
|
||||
%type <ast::expr_float::ptr> expr_float
|
||||
%type <ast::expr_integer::ptr> expr_integer
|
||||
%type <ast::expr_false::ptr> expr_false
|
||||
%type <ast::expr_true::ptr> expr_true
|
||||
|
||||
%nonassoc SIZEOF
|
||||
%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_EXOR
|
||||
%left BITWISE_AND
|
||||
%left EQUALITY INEQUALITY
|
||||
%left LESS GREATER LESS_EQUAL GREATER_EQUAL
|
||||
%left LSHIFT RSHIFT
|
||||
%left ADD SUB
|
||||
%left MUL 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<ast::program>(@$); }
|
||||
;
|
||||
|
||||
program
|
||||
: program inline
|
||||
{ $$ = std::move($1); }
|
||||
| program include
|
||||
{ $$ = std::move($1); $$->includes.push_back(std::move($2)); }
|
||||
| program declaration
|
||||
{ $$ = std::move($1); $$->declarations.push_back(std::move($2)); }
|
||||
| inline
|
||||
{ $$ = std::make_unique<ast::program>(@$); }
|
||||
| include
|
||||
{ $$ = std::make_unique<ast::program>(@$); $$->includes.push_back(std::move($1)); }
|
||||
| declaration
|
||||
{ $$ = std::make_unique<ast::program>(@$); $$->declarations.push_back(std::move($1)); }
|
||||
;
|
||||
|
||||
inline
|
||||
: INLINE expr_path SEMICOLON { lexer.push_header($2->value); }
|
||||
;
|
||||
|
||||
include
|
||||
: INCLUDE expr_path SEMICOLON
|
||||
{ $$ = std::make_unique<ast::include>(@$, std::move($2)); }
|
||||
;
|
||||
|
||||
declaration
|
||||
: DEVBEGIN { $$.as_dev_begin = std::make_unique<ast::decl_dev_begin>(@$); }
|
||||
| DEVEND { $$.as_dev_end = std::make_unique<ast::decl_dev_end>(@$); }
|
||||
| decl_usingtree { $$.as_usingtree = std::move($1); }
|
||||
| decl_constant { $$.as_constant = std::move($1); }
|
||||
| decl_thread { $$.as_thread = std::move($1); }
|
||||
;
|
||||
|
||||
decl_usingtree
|
||||
: USINGTREE LPAREN expr_string RPAREN SEMICOLON
|
||||
{ lexer.ban_header(@$); $$ = std::make_unique<ast::decl_usingtree>(@$, std::move($3)); }
|
||||
;
|
||||
|
||||
decl_constant
|
||||
: expr_identifier ASSIGN expr SEMICOLON
|
||||
{ $$ = std::make_unique<ast::decl_constant>(@$, std::move($1), std::move($3)); }
|
||||
;
|
||||
|
||||
decl_thread
|
||||
: expr_identifier LPAREN expr_parameters RPAREN stmt_block
|
||||
{ lexer.ban_header(@$); $$ = std::make_unique<ast::decl_thread>(@$, std::move($1), std::move($3), std::move($5)); }
|
||||
;
|
||||
|
||||
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_if { $$.as_if = std::move($1); }
|
||||
| stmt_ifelse { $$.as_ifelse = std::move($1); }
|
||||
| stmt_while { $$.as_while = std::move($1); }
|
||||
| stmt_dowhile { $$.as_dowhile = 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_breakpoint { $$.as_breakpoint = std::move($1); }
|
||||
| stmt_prof_begin { $$.as_prof_begin = std::move($1); }
|
||||
| stmt_prof_end { $$.as_prof_end = std::move($1); }
|
||||
;
|
||||
|
||||
stmt_or_dev
|
||||
: stmt { $$ = std::move($1); }
|
||||
| stmt_dev { $$.as_dev = std::move($1); }
|
||||
;
|
||||
|
||||
stmt_list
|
||||
: stmt_list stmt
|
||||
{ $$ = std::move($1); $$->list.push_back(std::move($2)); }
|
||||
| stmt
|
||||
{ $$ = std::make_unique<ast::stmt_list>(@$); $$->list.push_back(std::move($1)); }
|
||||
;
|
||||
|
||||
stmt_or_dev_list
|
||||
: stmt_or_dev_list stmt_or_dev
|
||||
{ $$ = std::move($1); $$->list.push_back(std::move($2)); }
|
||||
| stmt_or_dev
|
||||
{ $$ = std::make_unique<ast::stmt_list>(@$); $$->list.push_back(std::move($1)); }
|
||||
;
|
||||
|
||||
stmt_dev
|
||||
: DEVBEGIN stmt_list DEVEND { $$ = std::make_unique<ast::stmt_dev>(@$, std::move($2)); }
|
||||
| DEVBEGIN DEVEND { $$ = std::make_unique<ast::stmt_dev>(@$, std::make_unique<ast::stmt_list>(@$)); }
|
||||
;
|
||||
|
||||
stmt_block
|
||||
: LBRACE stmt_or_dev_list RBRACE { $$ = std::move($2); }
|
||||
| LBRACE RBRACE { $$ = std::make_unique<ast::stmt_list>(@$); }
|
||||
;
|
||||
|
||||
stmt_expr
|
||||
: expr_assign
|
||||
{ $$ = std::make_unique<ast::stmt_expr>(@$, std::move($1)); }
|
||||
| expr_increment
|
||||
{ $$ = std::make_unique<ast::stmt_expr>(@$, std::move($1)); }
|
||||
| expr_decrement
|
||||
{ $$ = std::make_unique<ast::stmt_expr>(@$, std::move($1)); }
|
||||
|
|
||||
{ $$ = std::make_unique<ast::stmt_expr>(@$, std::make_unique<ast::node>(@$)); }
|
||||
;
|
||||
|
||||
stmt_call
|
||||
: expr_call SEMICOLON
|
||||
{ $$ = std::make_unique<ast::stmt_call>(@$, ast::expr(std::move($1))); }
|
||||
| expr_method SEMICOLON
|
||||
{ $$ = std::make_unique<ast::stmt_call>(@$, ast::expr(std::move($1))); }
|
||||
;
|
||||
|
||||
stmt_assign
|
||||
: expr_assign SEMICOLON
|
||||
{ $$ = std::make_unique<ast::stmt_assign>(@$, std::move($1)); }
|
||||
| expr_increment SEMICOLON
|
||||
{ $$ = std::make_unique<ast::stmt_assign>(@$, std::move($1)); }
|
||||
| expr_decrement SEMICOLON
|
||||
{ $$ = std::make_unique<ast::stmt_assign>(@$, std::move($1)); }
|
||||
;
|
||||
|
||||
stmt_endon
|
||||
: expr_object ENDON LPAREN expr RPAREN SEMICOLON
|
||||
{ $$ = std::make_unique<ast::stmt_endon>(@$, std::move($1), std::move($4)); }
|
||||
;
|
||||
|
||||
stmt_notify
|
||||
: expr_object NOTIFY LPAREN expr COMMA expr_arguments_no_empty RPAREN SEMICOLON
|
||||
{ $$ = std::make_unique<ast::stmt_notify>(@$, std::move($1), std::move($4), std::move($6)); }
|
||||
| expr_object NOTIFY LPAREN expr RPAREN SEMICOLON
|
||||
{ $$ = std::make_unique<ast::stmt_notify>(@$, std::move($1), std::move($4), std::make_unique<ast::expr_arguments>(@$)); }
|
||||
;
|
||||
|
||||
stmt_wait
|
||||
: WAIT expr SEMICOLON
|
||||
{ $$ = std::make_unique<ast::stmt_wait>(@$, std::move($2)); }
|
||||
;
|
||||
|
||||
stmt_waittill
|
||||
: expr_object WAITTILL LPAREN expr COMMA expr_arguments_no_empty RPAREN SEMICOLON
|
||||
{ $$ = std::make_unique<ast::stmt_waittill>(@$, std::move($1), std::move($4), std::move($6)); }
|
||||
| expr_object WAITTILL LPAREN expr RPAREN SEMICOLON
|
||||
{ $$ = std::make_unique<ast::stmt_waittill>(@$, std::move($1), std::move($4), std::make_unique<ast::expr_arguments>(@$)); }
|
||||
;
|
||||
|
||||
stmt_waittillmatch
|
||||
: expr_object WAITTILLMATCH LPAREN expr COMMA expr_arguments_no_empty RPAREN SEMICOLON
|
||||
{ $$ = std::make_unique<ast::stmt_waittillmatch>(@$, std::move($1), std::move($4), std::move($6)); }
|
||||
| expr_object WAITTILLMATCH LPAREN expr RPAREN SEMICOLON
|
||||
{ $$ = std::make_unique<ast::stmt_waittillmatch>(@$, std::move($1), std::move($4), std::make_unique<ast::expr_arguments>(@$)); }
|
||||
;
|
||||
|
||||
stmt_waittillframeend
|
||||
: WAITTILLFRAMEEND SEMICOLON
|
||||
{ $$ = std::make_unique<ast::stmt_waittillframeend>(@$); }
|
||||
;
|
||||
|
||||
stmt_if
|
||||
: IF LPAREN expr RPAREN stmt %prec THEN
|
||||
{ $$ = std::make_unique<ast::stmt_if>(@$, std::move($3), std::move($5)); }
|
||||
;
|
||||
|
||||
stmt_ifelse
|
||||
: IF LPAREN expr RPAREN stmt ELSE stmt
|
||||
{ $$ = std::make_unique<ast::stmt_ifelse>(@$, std::move($3), std::move($5), std::move($7)); }
|
||||
;
|
||||
|
||||
stmt_while
|
||||
: WHILE LPAREN expr RPAREN stmt
|
||||
{ $$ = std::make_unique<ast::stmt_while>(@$, std::move($3), std::move($5)); }
|
||||
;
|
||||
|
||||
stmt_dowhile
|
||||
: DO stmt WHILE LPAREN expr RPAREN SEMICOLON
|
||||
{ $$ = std::make_unique<ast::stmt_dowhile>(@$, std::move($5), std::move($2)); }
|
||||
;
|
||||
|
||||
stmt_for
|
||||
: FOR LPAREN stmt_expr SEMICOLON expr_or_empty SEMICOLON stmt_expr RPAREN stmt
|
||||
{ $$ = std::make_unique<ast::stmt_for>(@$, ast::stmt(std::move($3)), std::move($5), ast::stmt(std::move($7)), std::move($9)); }
|
||||
;
|
||||
|
||||
stmt_foreach
|
||||
: FOREACH LPAREN expr_identifier IN expr RPAREN stmt
|
||||
{ $$ = std::make_unique<ast::stmt_foreach>(@$, ast::expr(std::move($3)), std::move($5), std::move($7)); }
|
||||
| FOREACH LPAREN expr_identifier COMMA expr_identifier IN expr RPAREN stmt
|
||||
{ $$ = std::make_unique<ast::stmt_foreach>(@$, ast::expr(std::move($3)), ast::expr(std::move($5)), std::move($7), std::move($9)); }
|
||||
;
|
||||
|
||||
stmt_switch
|
||||
: SWITCH LPAREN expr RPAREN stmt_block
|
||||
{ $$ = std::make_unique<ast::stmt_switch>(@$, std::move($3), std::move($5)); }
|
||||
;
|
||||
|
||||
stmt_case
|
||||
: CASE expr_integer COLON
|
||||
{ $$ = std::make_unique<ast::stmt_case>(@$, ast::expr(std::move($2)), std::make_unique<ast::stmt_list>(@$)); }
|
||||
| CASE expr_string COLON
|
||||
{ $$ = std::make_unique<ast::stmt_case>(@$, ast::expr(std::move($2)), std::make_unique<ast::stmt_list>(@$)); }
|
||||
;
|
||||
|
||||
stmt_default
|
||||
: DEFAULT COLON
|
||||
{ $$ = std::make_unique<ast::stmt_default>(@$, std::make_unique<ast::stmt_list>(@$)); }
|
||||
;
|
||||
|
||||
stmt_break
|
||||
: BREAK SEMICOLON
|
||||
{ $$ = std::make_unique<ast::stmt_break>(@$); }
|
||||
;
|
||||
|
||||
stmt_continue
|
||||
: CONTINUE SEMICOLON
|
||||
{ $$ = std::make_unique<ast::stmt_continue>(@$); }
|
||||
;
|
||||
|
||||
stmt_return
|
||||
: RETURN expr SEMICOLON
|
||||
{ $$ = std::make_unique<ast::stmt_return>(@$, std::move($2)); }
|
||||
| RETURN SEMICOLON
|
||||
{ $$ = std::make_unique<ast::stmt_return>(@$, std::make_unique<ast::node>(@$)); }
|
||||
;
|
||||
|
||||
stmt_breakpoint
|
||||
: BREAKPOINT SEMICOLON
|
||||
{ $$ = std::make_unique<ast::stmt_breakpoint>(@$); }
|
||||
;
|
||||
|
||||
stmt_prof_begin
|
||||
: PROFBEGIN LPAREN expr_arguments RPAREN SEMICOLON
|
||||
{ $$ = std::make_unique<ast::stmt_prof_begin>(@$, std::move($3)); }
|
||||
;
|
||||
|
||||
stmt_prof_end
|
||||
: PROFEND LPAREN expr_arguments RPAREN SEMICOLON
|
||||
{ $$ = std::make_unique<ast::stmt_prof_end>(@$, std::move($3)); }
|
||||
;
|
||||
|
||||
expr
|
||||
: expr_ternary { $$ = std::move($1); }
|
||||
| expr_binary { $$ = std::move($1); }
|
||||
| expr_primitive { $$ = std::move($1); }
|
||||
;
|
||||
|
||||
expr_or_empty
|
||||
: expr { $$ = std::move($1); }
|
||||
| { $$.as_node = std::make_unique<ast::node>(@$); }
|
||||
;
|
||||
|
||||
expr_assign
|
||||
: expr_tuple ASSIGN expr
|
||||
{ $$.as_node = std::make_unique<ast::expr_assign_equal>(@$, std::move($1), std::move($3)); }
|
||||
| expr_object ASSIGN expr
|
||||
{ $$.as_node = std::make_unique<ast::expr_assign_equal>(@$, std::move($1), std::move($3)); }
|
||||
| expr_object ASSIGN_BW_OR expr
|
||||
{ $$.as_node = std::make_unique<ast::expr_assign_bitwise_or>(@$, std::move($1), std::move($3)); }
|
||||
| expr_object ASSIGN_BW_AND expr
|
||||
{ $$.as_node = std::make_unique<ast::expr_assign_bitwise_and>(@$, std::move($1), std::move($3)); }
|
||||
| expr_object ASSIGN_BW_EXOR expr
|
||||
{ $$.as_node = std::make_unique<ast::expr_assign_bitwise_exor>(@$, std::move($1), std::move($3)); }
|
||||
| expr_object ASSIGN_LSHIFT expr
|
||||
{ $$.as_node = std::make_unique<ast::expr_assign_shift_left>(@$, std::move($1),std::move( $3)); }
|
||||
| expr_object ASSIGN_RSHIFT expr
|
||||
{ $$.as_node = std::make_unique<ast::expr_assign_shift_right>(@$, std::move($1), std::move($3)); }
|
||||
| expr_object ASSIGN_ADD expr
|
||||
{ $$.as_node = std::make_unique<ast::expr_assign_add>(@$, std::move($1), std::move($3)); }
|
||||
| expr_object ASSIGN_SUB expr
|
||||
{ $$.as_node = std::make_unique<ast::expr_assign_sub>(@$, std::move($1), std::move($3)); }
|
||||
| expr_object ASSIGN_MUL expr
|
||||
{ $$.as_node = std::make_unique<ast::expr_assign_mul>(@$, std::move($1), std::move($3)); }
|
||||
| expr_object ASSIGN_DIV expr
|
||||
{ $$.as_node = std::make_unique<ast::expr_assign_div>(@$, std::move($1), std::move($3)); }
|
||||
| expr_object ASSIGN_MOD expr
|
||||
{ $$.as_node = std::make_unique<ast::expr_assign_mod>(@$, std::move($1), std::move($3)); }
|
||||
;
|
||||
|
||||
expr_increment
|
||||
: INCREMENT expr_object %prec PREINC
|
||||
{ $$.as_node = std::make_unique<ast::expr_increment>(@$, std::move($2), true); }
|
||||
| expr_object INCREMENT %prec POSTINC
|
||||
{ $$.as_node = std::make_unique<ast::expr_increment>(@$, std::move($1), false); }
|
||||
;
|
||||
|
||||
expr_decrement
|
||||
: DECREMENT expr_object %prec PREDEC
|
||||
{ $$.as_node = std::make_unique<ast::expr_decrement>(@$, std::move($2), true); }
|
||||
| expr_object DECREMENT %prec POSTDEC
|
||||
{ $$.as_node = std::make_unique<ast::expr_decrement>(@$, std::move($1), false); }
|
||||
;
|
||||
|
||||
expr_ternary
|
||||
: expr QMARK expr COLON expr %prec TERN
|
||||
{ $$.as_node = std::make_unique<ast::expr_ternary>(@$, std::move($1), std::move($3), std::move($5)); }
|
||||
;
|
||||
|
||||
expr_binary
|
||||
: expr OR expr
|
||||
{ $$.as_node = std::make_unique<ast::expr_or>(@$, std::move($1), std::move($3)); }
|
||||
| expr AND expr
|
||||
{ $$.as_node = std::make_unique<ast::expr_and>(@$, std::move($1), std::move($3)); }
|
||||
| expr EQUALITY expr
|
||||
{ $$.as_node = std::make_unique<ast::expr_equality>(@$, std::move($1), std::move($3)); }
|
||||
| expr INEQUALITY expr
|
||||
{ $$.as_node = std::make_unique<ast::expr_inequality>(@$, std::move($1), std::move($3)); }
|
||||
| expr LESS_EQUAL expr
|
||||
{ $$.as_node = std::make_unique<ast::expr_less_equal>(@$, std::move($1), std::move($3)); }
|
||||
| expr GREATER_EQUAL expr
|
||||
{ $$.as_node = std::make_unique<ast::expr_greater_equal>(@$, std::move($1), std::move($3)); }
|
||||
| expr LESS expr
|
||||
{ $$.as_node = std::make_unique<ast::expr_less>(@$, std::move($1), std::move($3)); }
|
||||
| expr GREATER expr
|
||||
{ $$.as_node = std::make_unique<ast::expr_greater>(@$, std::move($1), std::move($3)); }
|
||||
| expr BITWISE_OR expr
|
||||
{ $$.as_node = std::make_unique<ast::expr_bitwise_or>(@$, std::move($1), std::move($3)); }
|
||||
| expr BITWISE_AND expr
|
||||
{ $$.as_node = std::make_unique<ast::expr_bitwise_and>(@$, std::move($1), std::move($3)); }
|
||||
| expr BITWISE_EXOR expr
|
||||
{ $$.as_node = std::make_unique<ast::expr_bitwise_exor>(@$, std::move($1), std::move($3)); }
|
||||
| expr LSHIFT expr
|
||||
{ $$.as_node = std::make_unique<ast::expr_shift_left>(@$, std::move($1), std::move($3)); }
|
||||
| expr RSHIFT expr
|
||||
{ $$.as_node = std::make_unique<ast::expr_shift_right>(@$, std::move($1), std::move($3)); }
|
||||
| expr ADD expr
|
||||
{ $$.as_node = std::make_unique<ast::expr_add>(@$, std::move($1), std::move($3)); }
|
||||
| expr SUB expr
|
||||
{ $$.as_node = std::make_unique<ast::expr_sub>(@$, std::move($1), std::move($3)); }
|
||||
| expr MUL expr
|
||||
{ $$.as_node = std::make_unique<ast::expr_mul>(@$, std::move($1), std::move($3)); }
|
||||
| expr DIV expr
|
||||
{ $$.as_node = std::make_unique<ast::expr_div>(@$, std::move($1), std::move($3)); }
|
||||
| expr MOD expr
|
||||
{ $$.as_node = std::make_unique<ast::expr_mod>(@$, std::move($1), std::move($3)); }
|
||||
;
|
||||
|
||||
expr_primitive
|
||||
: expr_complement { $$.as_node = std::move($1); }
|
||||
| expr_negate { $$.as_node = std::move($1); }
|
||||
| expr_not { $$.as_node = std::move($1); }
|
||||
| expr_call { $$.as_node = std::move($1); }
|
||||
| expr_method { $$.as_node = std::move($1); }
|
||||
| expr_add_array { $$.as_node = std::move($1); }
|
||||
| expr_reference { $$.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); }
|
||||
| expr_paren { $$.as_node = std::move($1); }
|
||||
| expr_thisthread { $$.as_node = std::move($1); }
|
||||
| expr_empty_array { $$.as_node = std::move($1); }
|
||||
| expr_undefined { $$.as_node = std::move($1); }
|
||||
| expr_game { $$.as_node = std::move($1); }
|
||||
| expr_self { $$.as_node = std::move($1); }
|
||||
| expr_anim { $$.as_node = std::move($1); }
|
||||
| expr_level { $$.as_node = std::move($1); }
|
||||
| expr_animation { $$.as_node = std::move($1); }
|
||||
| expr_animtree { $$.as_node = std::move($1); }
|
||||
| expr_identifier { $$.as_node = std::move($1); }
|
||||
| expr_istring { $$.as_node = std::move($1); }
|
||||
| expr_string { $$.as_node = std::move($1); }
|
||||
| expr_vector { $$.as_node = std::move($1); }
|
||||
| expr_float { $$.as_node = std::move($1); }
|
||||
| expr_integer { $$.as_node = std::move($1); }
|
||||
| expr_false { $$.as_node = std::move($1); }
|
||||
| expr_true { $$.as_node = std::move($1); }
|
||||
;
|
||||
|
||||
expr_complement
|
||||
: COMPLEMENT expr
|
||||
{ $$ = std::make_unique<ast::expr_complement>(@$, std::move($2)); }
|
||||
;
|
||||
|
||||
expr_negate
|
||||
: SUB expr_identifier %prec NEG
|
||||
{ $$ = std::make_unique<ast::expr_negate>(@$, ast::expr(std::move($2))); }
|
||||
| SUB expr_paren %prec NEG
|
||||
{ $$ = std::make_unique<ast::expr_negate>(@$, ast::expr(std::move($2))); }
|
||||
| SUB expr_array %prec NEG
|
||||
{ $$ = std::make_unique<ast::expr_negate>(@$, ast::expr(std::move($2))); }
|
||||
| SUB expr_field %prec NEG
|
||||
{ $$ = std::make_unique<ast::expr_negate>(@$, ast::expr(std::move($2))); }
|
||||
;
|
||||
|
||||
expr_not
|
||||
: NOT expr
|
||||
{ $$ = std::make_unique<ast::expr_not>(@$, std::move($2)); }
|
||||
;
|
||||
|
||||
expr_call
|
||||
: expr_function { $$ = std::make_unique<ast::expr_call>(@$, std::move($1)); }
|
||||
| expr_pointer { $$ = std::make_unique<ast::expr_call>(@$, std::move($1)); }
|
||||
;
|
||||
expr_method
|
||||
: expr_object expr_function { $$ = std::make_unique<ast::expr_method>(@$, std::move($1), std::move($2)); }
|
||||
| expr_object expr_pointer { $$ = std::make_unique<ast::expr_method>(@$, std::move($1), std::move($2)); }
|
||||
;
|
||||
|
||||
expr_function
|
||||
: expr_identifier LPAREN expr_arguments RPAREN
|
||||
{ $$.as_function = std::make_unique<ast::expr_function>(@$, std::make_unique<ast::expr_path>(@$), std::move($1), std::move($3), ast::call::mode::normal); }
|
||||
| expr_path DOUBLECOLON expr_identifier LPAREN expr_arguments RPAREN
|
||||
{ $$.as_function = std::make_unique<ast::expr_function>(@$, std::move($1), std::move($3), std::move($5), ast::call::mode::normal); }
|
||||
| THREAD expr_identifier LPAREN expr_arguments RPAREN
|
||||
{ $$.as_function = std::make_unique<ast::expr_function>(@$, std::make_unique<ast::expr_path>(@$), std::move($2), std::move($4), ast::call::mode::thread); }
|
||||
| THREAD expr_path DOUBLECOLON expr_identifier LPAREN expr_arguments RPAREN
|
||||
{ $$.as_function = std::make_unique<ast::expr_function>(@$, std::move($2), std::move($4), std::move($6), ast::call::mode::thread); }
|
||||
| CHILDTHREAD expr_identifier LPAREN expr_arguments RPAREN
|
||||
{ $$.as_function = std::make_unique<ast::expr_function>(@$, std::make_unique<ast::expr_path>(@$), std::move($2), std::move($4), ast::call::mode::childthread); }
|
||||
| CHILDTHREAD expr_path DOUBLECOLON expr_identifier LPAREN expr_arguments RPAREN
|
||||
{ $$.as_function = std::make_unique<ast::expr_function>(@$, std::move($2), std::move($4), std::move($6), ast::call::mode::childthread); }
|
||||
;
|
||||
|
||||
expr_pointer
|
||||
: LBRACKET LBRACKET expr RBRACKET RBRACKET LPAREN expr_arguments RPAREN
|
||||
{ $$.as_pointer = std::make_unique<ast::expr_pointer>(@$, std::move($3), std::move($7), ast::call::mode::normal); }
|
||||
| THREAD LBRACKET LBRACKET expr RBRACKET RBRACKET LPAREN expr_arguments RPAREN
|
||||
{ $$.as_pointer = std::make_unique<ast::expr_pointer>(@$, std::move($4), std::move($8), ast::call::mode::thread); }
|
||||
| CHILDTHREAD LBRACKET LBRACKET expr RBRACKET RBRACKET LPAREN expr_arguments RPAREN
|
||||
{ $$.as_pointer = std::make_unique<ast::expr_pointer>(@$, std::move($4), std::move($8), ast::call::mode::childthread); }
|
||||
| CALL LBRACKET LBRACKET expr RBRACKET RBRACKET LPAREN expr_arguments RPAREN
|
||||
{ $$.as_pointer = std::make_unique<ast::expr_pointer>(@$, std::move($4), std::move($8), ast::call::mode::builtin); }
|
||||
;
|
||||
|
||||
expr_add_array
|
||||
: LBRACKET expr_arguments_no_empty RBRACKET
|
||||
{ $$ = std::make_unique<ast::expr_add_array>(@$, std::move($2)); }
|
||||
;
|
||||
|
||||
expr_parameters
|
||||
: expr_parameters COMMA expr_identifier
|
||||
{ $$ = std::move($1); $$->list.push_back(std::move($3)); }
|
||||
| expr_identifier
|
||||
{ $$ = std::make_unique<ast::expr_parameters>(@$); $$->list.push_back(std::move($1)); }
|
||||
|
|
||||
{ $$ = std::make_unique<ast::expr_parameters>(@$); }
|
||||
;
|
||||
|
||||
expr_arguments
|
||||
: expr_arguments_no_empty
|
||||
{ $$ = std::move($1); }
|
||||
|
|
||||
{ $$ = std::make_unique<ast::expr_arguments>(@$); }
|
||||
;
|
||||
|
||||
expr_arguments_no_empty
|
||||
: expr_arguments COMMA expr
|
||||
{ $$ = std::move($1); $$->list.push_back(std::move($3)); }
|
||||
| expr %prec ADD_ARRAY
|
||||
{ $$ = std::make_unique<ast::expr_arguments>(@$); $$->list.push_back(std::move($1)); }
|
||||
;
|
||||
|
||||
expr_reference
|
||||
: DOUBLECOLON expr_identifier
|
||||
{ $$ = std::make_unique<ast::expr_reference>(@$, std::make_unique<ast::expr_path>(@$), std::move($2)); }
|
||||
| expr_path DOUBLECOLON expr_identifier
|
||||
{ $$ = std::make_unique<ast::expr_reference>(@$, std::move($1), std::move($3)); }
|
||||
;
|
||||
|
||||
expr_tuple
|
||||
: LBRACKET expr_tuple_arguments RBRACKET
|
||||
{ $$.as_node = std::move($2); }
|
||||
;
|
||||
|
||||
expr_tuple_arguments
|
||||
: expr_tuple_arguments COMMA expr_tuple_types
|
||||
{ $$ = std::move($1); $$->list.push_back(std::move($3)); }
|
||||
| expr_tuple_types
|
||||
{ $$ = std::make_unique<ast::expr_tuple>(@$); $$->list.push_back(std::move($1)); }
|
||||
;
|
||||
|
||||
expr_tuple_types
|
||||
: expr_array { $$.as_node = std::move($1); }
|
||||
| expr_field { $$.as_node = std::move($1); }
|
||||
| expr_identifier { $$.as_node = std::move($1); }
|
||||
;
|
||||
|
||||
expr_array
|
||||
: expr_object LBRACKET expr RBRACKET
|
||||
{ $$ = std::make_unique<ast::expr_array>(@$, std::move($1), std::move($3)); }
|
||||
;
|
||||
|
||||
expr_field
|
||||
: expr_object DOT expr_identifier_nosize
|
||||
{ $$ = std::make_unique<ast::expr_field>(@$, std::move($1), std::move($3)); }
|
||||
;
|
||||
|
||||
expr_size
|
||||
: expr_object DOT SIZE %prec SIZEOF
|
||||
{ $$ = std::make_unique<ast::expr_size>(@$, std::move($1)); }
|
||||
;
|
||||
|
||||
expr_paren
|
||||
: LPAREN expr RPAREN
|
||||
{ $$ = std::make_unique<ast::expr_paren>(@$, std::move($2)); }
|
||||
;
|
||||
|
||||
expr_object
|
||||
: expr_call { $$.as_node = std::move($1); }
|
||||
| expr_method { $$.as_node = std::move($1); }
|
||||
| expr_array { $$.as_node = std::move($1); }
|
||||
| expr_field { $$.as_node = std::move($1); }
|
||||
| expr_game { $$.as_node = std::move($1); }
|
||||
| expr_self { $$.as_node = std::move($1); }
|
||||
| expr_anim { $$.as_node = std::move($1); }
|
||||
| expr_level { $$.as_node = std::move($1); }
|
||||
| expr_identifier { $$.as_node = std::move($1); }
|
||||
;
|
||||
|
||||
expr_thisthread
|
||||
: THISTHREAD
|
||||
{ $$ = std::make_unique<ast::expr_thisthread>(@$); };
|
||||
;
|
||||
|
||||
expr_empty_array
|
||||
: LBRACKET RBRACKET
|
||||
{ $$ = std::make_unique<ast::expr_empty_array>(@$); };
|
||||
;
|
||||
|
||||
expr_undefined
|
||||
: UNDEFINED
|
||||
{ $$ = std::make_unique<ast::expr_undefined>(@$); };
|
||||
;
|
||||
|
||||
expr_game
|
||||
: GAME
|
||||
{ $$ = std::make_unique<ast::expr_game>(@$); };
|
||||
;
|
||||
|
||||
expr_self
|
||||
: SELF
|
||||
{ $$ = std::make_unique<ast::expr_self>(@$); };
|
||||
;
|
||||
|
||||
expr_anim
|
||||
: ANIM
|
||||
{ $$ = std::make_unique<ast::expr_anim>(@$); };
|
||||
;
|
||||
|
||||
expr_level
|
||||
: LEVEL
|
||||
{ $$ = std::make_unique<ast::expr_level>(@$); };
|
||||
;
|
||||
|
||||
expr_animation
|
||||
: MOD IDENTIFIER %prec ANIMREF
|
||||
{ $$ = std::make_unique<ast::expr_animation>(@$, $2); };
|
||||
;
|
||||
|
||||
expr_animtree
|
||||
: ANIMTREE
|
||||
{ $$ = std::make_unique<ast::expr_animtree>(@$); };
|
||||
;
|
||||
|
||||
expr_identifier_nosize
|
||||
: IDENTIFIER
|
||||
{ $$ = std::make_unique<ast::expr_identifier>(@$, $1); };
|
||||
;
|
||||
|
||||
expr_identifier
|
||||
: IDENTIFIER
|
||||
{ $$ = std::make_unique<ast::expr_identifier>(@$, $1); };
|
||||
| SIZE
|
||||
{ $$ = std::make_unique<ast::expr_identifier>(@$, "size"); };
|
||||
;
|
||||
|
||||
expr_path
|
||||
: IDENTIFIER
|
||||
{ $$ = std::make_unique<ast::expr_path>(@$, $1); };
|
||||
| PATH
|
||||
{ $$ = std::make_unique<ast::expr_path>(@$, $1); };
|
||||
;
|
||||
|
||||
expr_istring
|
||||
: ISTRING
|
||||
{ $$ = std::make_unique<ast::expr_istring>(@$, $1); };
|
||||
;
|
||||
|
||||
expr_string
|
||||
: STRING
|
||||
{ $$ = std::make_unique<ast::expr_string>(@$, $1); };
|
||||
;
|
||||
|
||||
expr_vector
|
||||
: LPAREN expr COMMA expr COMMA expr RPAREN
|
||||
{ $$ = std::make_unique<ast::expr_vector>(@$, std::move($2), std::move($4), std::move($6)); };
|
||||
;
|
||||
|
||||
expr_float
|
||||
: SUB FLOAT %prec NEG
|
||||
{ $$ = std::make_unique<ast::expr_float>(@$, "-" + $2); };
|
||||
| FLOAT
|
||||
{ $$ = std::make_unique<ast::expr_float>(@$, $1); };
|
||||
;
|
||||
|
||||
expr_integer
|
||||
: SUB INTEGER %prec NEG
|
||||
{ $$ = std::make_unique<ast::expr_integer>(@$, "-" + $2); };
|
||||
| INTEGER
|
||||
{ $$ = std::make_unique<ast::expr_integer>(@$, $1); };
|
||||
;
|
||||
|
||||
expr_false
|
||||
: FALSE
|
||||
{ $$ = std::make_unique<ast::expr_false>(@$); };
|
||||
;
|
||||
|
||||
expr_true
|
||||
: TRUE
|
||||
{ $$ = std::make_unique<ast::expr_true>(@$); };
|
||||
;
|
||||
|
||||
%%
|
||||
|
||||
void xsk::gsc::iw5::parser::error(const xsk::gsc::location& loc, const std::string& msg)
|
||||
{
|
||||
throw xsk::gsc::comp_error(loc, msg);
|
||||
}
|
@ -1,9 +0,0 @@
|
||||
generate: iw6
|
||||
|
||||
clean:
|
||||
rm -rf ./parser.hpp
|
||||
rm -rf ./parser.cpp
|
||||
|
||||
iw6: parser.ypp
|
||||
bison parser.ypp -Wcounterexamples
|
||||
mv parser.hpp parser.cpp ../../src/iw6/xsk/
|
@ -1,888 +0,0 @@
|
||||
/* Copyright 2022 xensik. All rights reserved.
|
||||
//
|
||||
// Use of this source code is governed by a GNU GPLv3 license
|
||||
// that can be found in the LICENSE file.
|
||||
*/
|
||||
|
||||
%require "3.7"
|
||||
%skeleton "lalr1.cc"
|
||||
%language "c++"
|
||||
%output "parser.cpp"
|
||||
%defines "parser.hpp"
|
||||
%define api.prefix {IW6}
|
||||
%define api.namespace {xsk::gsc::iw6}
|
||||
%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 { xsk::gsc::iw6::lexer& lexer }
|
||||
%parse-param { xsk::gsc::iw6::lexer& lexer }
|
||||
%parse-param { xsk::gsc::ast::program::ptr& ast }
|
||||
|
||||
%code requires
|
||||
{
|
||||
#ifdef _MSC_VER
|
||||
#pragma warning(disable:4065)
|
||||
#pragma warning(disable:4127)
|
||||
#endif
|
||||
#include "iw6.hpp"
|
||||
namespace xsk::gsc::iw6 { class lexer; }
|
||||
}
|
||||
|
||||
%code top
|
||||
{
|
||||
#include "stdafx.hpp"
|
||||
#include "parser.hpp"
|
||||
#include "lexer.hpp"
|
||||
using namespace xsk::gsc;
|
||||
xsk::gsc::iw6::parser::symbol_type IW6lex(xsk::gsc::iw6::lexer& lexer);
|
||||
}
|
||||
|
||||
%token SH_DEFINE "#define"
|
||||
%token SH_UNDEF "#undef"
|
||||
%token SH_IFDEF "#ifdef"
|
||||
%token SH_IFNDEF "#ifndef"
|
||||
%token SH_IF "#if"
|
||||
%token SH_ELIF "#elif"
|
||||
%token SH_ELSE "#else"
|
||||
%token SH_ENDIF "#endif"
|
||||
%token DEVBEGIN "/#"
|
||||
%token DEVEND "#/"
|
||||
%token INLINE "#inline"
|
||||
%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 IF "if"
|
||||
%token ELSE "else"
|
||||
%token DO "do"
|
||||
%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 BREAKPOINT "breakpoint"
|
||||
%token PROFBEGIN "prof_begin"
|
||||
%token PROFEND "prof_end"
|
||||
%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_MUL "*="
|
||||
%token ASSIGN_DIV "/="
|
||||
%token ASSIGN_MOD "%="
|
||||
%token ASSIGN_BW_OR "|="
|
||||
%token ASSIGN_BW_AND "&="
|
||||
%token ASSIGN_BW_EXOR "^="
|
||||
%token ASSIGN_RSHIFT ">>="
|
||||
%token ASSIGN_LSHIFT "<<="
|
||||
%token BITWISE_OR "|"
|
||||
%token BITWISE_AND "&"
|
||||
%token BITWISE_EXOR "^"
|
||||
%token ADD "+"
|
||||
%token SUB "-"
|
||||
%token MUL "*"
|
||||
%token DIV "/"
|
||||
%token MOD "%"
|
||||
%token <std::string> PATH "path"
|
||||
%token <std::string> IDENTIFIER "identifier"
|
||||
%token <std::string> STRING "string literal"
|
||||
%token <std::string> ISTRING "localized string"
|
||||
%token <std::string> FLOAT "float"
|
||||
%token <std::string> INTEGER "integer"
|
||||
|
||||
%type <ast::program::ptr> program
|
||||
%type <ast::include::ptr> include
|
||||
%type <ast::decl> declaration
|
||||
%type <ast::decl_usingtree::ptr> decl_usingtree
|
||||
%type <ast::decl_constant::ptr> decl_constant
|
||||
%type <ast::decl_thread::ptr> decl_thread
|
||||
%type <ast::stmt> stmt
|
||||
%type <ast::stmt> stmt_or_dev
|
||||
%type <ast::stmt_list::ptr> stmt_list
|
||||
%type <ast::stmt_list::ptr> stmt_or_dev_list
|
||||
%type <ast::stmt_dev::ptr> stmt_dev
|
||||
%type <ast::stmt_list::ptr> stmt_block
|
||||
%type <ast::stmt_expr::ptr> stmt_expr
|
||||
%type <ast::stmt_call::ptr> stmt_call
|
||||
%type <ast::stmt_assign::ptr> stmt_assign
|
||||
%type <ast::stmt_endon::ptr> stmt_endon
|
||||
%type <ast::stmt_notify::ptr> stmt_notify
|
||||
%type <ast::stmt_wait::ptr> stmt_wait
|
||||
%type <ast::stmt_waittill::ptr> stmt_waittill
|
||||
%type <ast::stmt_waittillmatch::ptr> stmt_waittillmatch
|
||||
%type <ast::stmt_waittillframeend::ptr> stmt_waittillframeend
|
||||
%type <ast::stmt_if::ptr> stmt_if
|
||||
%type <ast::stmt_ifelse::ptr> stmt_ifelse
|
||||
%type <ast::stmt_while::ptr> stmt_while
|
||||
%type <ast::stmt_dowhile::ptr> stmt_dowhile
|
||||
%type <ast::stmt_for::ptr> stmt_for
|
||||
%type <ast::stmt_foreach::ptr> stmt_foreach
|
||||
%type <ast::stmt_switch::ptr> stmt_switch
|
||||
%type <ast::stmt_case::ptr> stmt_case
|
||||
%type <ast::stmt_default::ptr> stmt_default
|
||||
%type <ast::stmt_break::ptr> stmt_break
|
||||
%type <ast::stmt_continue::ptr> stmt_continue
|
||||
%type <ast::stmt_return::ptr> stmt_return
|
||||
%type <ast::stmt_breakpoint::ptr> stmt_breakpoint
|
||||
%type <ast::stmt_prof_begin::ptr> stmt_prof_begin
|
||||
%type <ast::stmt_prof_end::ptr> stmt_prof_end
|
||||
%type <ast::expr> expr
|
||||
%type <ast::expr> expr_or_empty
|
||||
%type <ast::expr> expr_assign
|
||||
%type <ast::expr> expr_increment
|
||||
%type <ast::expr> expr_decrement
|
||||
%type <ast::expr> expr_ternary
|
||||
%type <ast::expr> expr_binary
|
||||
%type <ast::expr> expr_primitive
|
||||
%type <ast::expr_complement::ptr> expr_complement
|
||||
%type <ast::expr_negate::ptr> expr_negate
|
||||
%type <ast::expr_not::ptr> expr_not
|
||||
%type <ast::expr_call::ptr> expr_call
|
||||
%type <ast::expr_method::ptr> expr_method
|
||||
%type <ast::call> expr_function
|
||||
%type <ast::call> expr_pointer
|
||||
%type <ast::expr_add_array::ptr> expr_add_array
|
||||
%type <ast::expr_parameters::ptr> expr_parameters
|
||||
%type <ast::expr_arguments::ptr> expr_arguments
|
||||
%type <ast::expr_arguments::ptr> expr_arguments_no_empty
|
||||
%type <ast::expr_reference::ptr> expr_reference
|
||||
%type <ast::expr> expr_tuple
|
||||
%type <ast::expr_tuple::ptr> expr_tuple_arguments
|
||||
%type <ast::expr> expr_tuple_types
|
||||
%type <ast::expr_array::ptr> expr_array
|
||||
%type <ast::expr_field::ptr> expr_field
|
||||
%type <ast::expr_size::ptr> expr_size
|
||||
%type <ast::expr_paren::ptr> expr_paren
|
||||
%type <ast::expr> expr_object
|
||||
%type <ast::expr_thisthread::ptr> expr_thisthread
|
||||
%type <ast::expr_empty_array::ptr> expr_empty_array
|
||||
%type <ast::expr_undefined::ptr> expr_undefined
|
||||
%type <ast::expr_game::ptr> expr_game
|
||||
%type <ast::expr_self::ptr> expr_self
|
||||
%type <ast::expr_anim::ptr> expr_anim
|
||||
%type <ast::expr_level::ptr> expr_level
|
||||
%type <ast::expr_animation::ptr> expr_animation
|
||||
%type <ast::expr_animtree::ptr> expr_animtree
|
||||
%type <ast::expr_identifier::ptr> expr_identifier_nosize
|
||||
%type <ast::expr_identifier::ptr> expr_identifier
|
||||
%type <ast::expr_path::ptr> expr_path
|
||||
%type <ast::expr_istring::ptr> expr_istring
|
||||
%type <ast::expr_string::ptr> expr_string
|
||||
%type <ast::expr_vector::ptr> expr_vector
|
||||
%type <ast::expr_float::ptr> expr_float
|
||||
%type <ast::expr_integer::ptr> expr_integer
|
||||
%type <ast::expr_false::ptr> expr_false
|
||||
%type <ast::expr_true::ptr> expr_true
|
||||
|
||||
%nonassoc SIZEOF
|
||||
%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_EXOR
|
||||
%left BITWISE_AND
|
||||
%left EQUALITY INEQUALITY
|
||||
%left LESS GREATER LESS_EQUAL GREATER_EQUAL
|
||||
%left LSHIFT RSHIFT
|
||||
%left ADD SUB
|
||||
%left MUL 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<ast::program>(@$); }
|
||||
;
|
||||
|
||||
program
|
||||
: program inline
|
||||
{ $$ = std::move($1); }
|
||||
| program include
|
||||
{ $$ = std::move($1); $$->includes.push_back(std::move($2)); }
|
||||
| program declaration
|
||||
{ $$ = std::move($1); $$->declarations.push_back(std::move($2)); }
|
||||
| inline
|
||||
{ $$ = std::make_unique<ast::program>(@$); }
|
||||
| include
|
||||
{ $$ = std::make_unique<ast::program>(@$); $$->includes.push_back(std::move($1)); }
|
||||
| declaration
|
||||
{ $$ = std::make_unique<ast::program>(@$); $$->declarations.push_back(std::move($1)); }
|
||||
;
|
||||
|
||||
inline
|
||||
: INLINE expr_path SEMICOLON { lexer.push_header($2->value); }
|
||||
;
|
||||
|
||||
include
|
||||
: INCLUDE expr_path SEMICOLON
|
||||
{ $$ = std::make_unique<ast::include>(@$, std::move($2)); }
|
||||
;
|
||||
|
||||
declaration
|
||||
: DEVBEGIN { $$.as_dev_begin = std::make_unique<ast::decl_dev_begin>(@$); }
|
||||
| DEVEND { $$.as_dev_end = std::make_unique<ast::decl_dev_end>(@$); }
|
||||
| decl_usingtree { $$.as_usingtree = std::move($1); }
|
||||
| decl_constant { $$.as_constant = std::move($1); }
|
||||
| decl_thread { $$.as_thread = std::move($1); }
|
||||
;
|
||||
|
||||
decl_usingtree
|
||||
: USINGTREE LPAREN expr_string RPAREN SEMICOLON
|
||||
{ lexer.ban_header(@$); $$ = std::make_unique<ast::decl_usingtree>(@$, std::move($3)); }
|
||||
;
|
||||
|
||||
decl_constant
|
||||
: expr_identifier ASSIGN expr SEMICOLON
|
||||
{ $$ = std::make_unique<ast::decl_constant>(@$, std::move($1), std::move($3)); }
|
||||
;
|
||||
|
||||
decl_thread
|
||||
: expr_identifier LPAREN expr_parameters RPAREN stmt_block
|
||||
{ lexer.ban_header(@$); $$ = std::make_unique<ast::decl_thread>(@$, std::move($1), std::move($3), std::move($5)); }
|
||||
;
|
||||
|
||||
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_if { $$.as_if = std::move($1); }
|
||||
| stmt_ifelse { $$.as_ifelse = std::move($1); }
|
||||
| stmt_while { $$.as_while = std::move($1); }
|
||||
| stmt_dowhile { $$.as_dowhile = 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_breakpoint { $$.as_breakpoint = std::move($1); }
|
||||
| stmt_prof_begin { $$.as_prof_begin = std::move($1); }
|
||||
| stmt_prof_end { $$.as_prof_end = std::move($1); }
|
||||
;
|
||||
|
||||
stmt_or_dev
|
||||
: stmt { $$ = std::move($1); }
|
||||
| stmt_dev { $$.as_dev = std::move($1); }
|
||||
;
|
||||
|
||||
stmt_list
|
||||
: stmt_list stmt
|
||||
{ $$ = std::move($1); $$->list.push_back(std::move($2)); }
|
||||
| stmt
|
||||
{ $$ = std::make_unique<ast::stmt_list>(@$); $$->list.push_back(std::move($1)); }
|
||||
;
|
||||
|
||||
stmt_or_dev_list
|
||||
: stmt_or_dev_list stmt_or_dev
|
||||
{ $$ = std::move($1); $$->list.push_back(std::move($2)); }
|
||||
| stmt_or_dev
|
||||
{ $$ = std::make_unique<ast::stmt_list>(@$); $$->list.push_back(std::move($1)); }
|
||||
;
|
||||
|
||||
stmt_dev
|
||||
: DEVBEGIN stmt_list DEVEND { $$ = std::make_unique<ast::stmt_dev>(@$, std::move($2)); }
|
||||
| DEVBEGIN DEVEND { $$ = std::make_unique<ast::stmt_dev>(@$, std::make_unique<ast::stmt_list>(@$)); }
|
||||
;
|
||||
|
||||
stmt_block
|
||||
: LBRACE stmt_or_dev_list RBRACE { $$ = std::move($2); }
|
||||
| LBRACE RBRACE { $$ = std::make_unique<ast::stmt_list>(@$); }
|
||||
;
|
||||
|
||||
stmt_expr
|
||||
: expr_assign
|
||||
{ $$ = std::make_unique<ast::stmt_expr>(@$, std::move($1)); }
|
||||
| expr_increment
|
||||
{ $$ = std::make_unique<ast::stmt_expr>(@$, std::move($1)); }
|
||||
| expr_decrement
|
||||
{ $$ = std::make_unique<ast::stmt_expr>(@$, std::move($1)); }
|
||||
|
|
||||
{ $$ = std::make_unique<ast::stmt_expr>(@$, std::make_unique<ast::node>(@$)); }
|
||||
;
|
||||
|
||||
stmt_call
|
||||
: expr_call SEMICOLON
|
||||
{ $$ = std::make_unique<ast::stmt_call>(@$, ast::expr(std::move($1))); }
|
||||
| expr_method SEMICOLON
|
||||
{ $$ = std::make_unique<ast::stmt_call>(@$, ast::expr(std::move($1))); }
|
||||
;
|
||||
|
||||
stmt_assign
|
||||
: expr_assign SEMICOLON
|
||||
{ $$ = std::make_unique<ast::stmt_assign>(@$, std::move($1)); }
|
||||
| expr_increment SEMICOLON
|
||||
{ $$ = std::make_unique<ast::stmt_assign>(@$, std::move($1)); }
|
||||
| expr_decrement SEMICOLON
|
||||
{ $$ = std::make_unique<ast::stmt_assign>(@$, std::move($1)); }
|
||||
;
|
||||
|
||||
stmt_endon
|
||||
: expr_object ENDON LPAREN expr RPAREN SEMICOLON
|
||||
{ $$ = std::make_unique<ast::stmt_endon>(@$, std::move($1), std::move($4)); }
|
||||
;
|
||||
|
||||
stmt_notify
|
||||
: expr_object NOTIFY LPAREN expr COMMA expr_arguments_no_empty RPAREN SEMICOLON
|
||||
{ $$ = std::make_unique<ast::stmt_notify>(@$, std::move($1), std::move($4), std::move($6)); }
|
||||
| expr_object NOTIFY LPAREN expr RPAREN SEMICOLON
|
||||
{ $$ = std::make_unique<ast::stmt_notify>(@$, std::move($1), std::move($4), std::make_unique<ast::expr_arguments>(@$)); }
|
||||
;
|
||||
|
||||
stmt_wait
|
||||
: WAIT expr SEMICOLON
|
||||
{ $$ = std::make_unique<ast::stmt_wait>(@$, std::move($2)); }
|
||||
;
|
||||
|
||||
stmt_waittill
|
||||
: expr_object WAITTILL LPAREN expr COMMA expr_arguments_no_empty RPAREN SEMICOLON
|
||||
{ $$ = std::make_unique<ast::stmt_waittill>(@$, std::move($1), std::move($4), std::move($6)); }
|
||||
| expr_object WAITTILL LPAREN expr RPAREN SEMICOLON
|
||||
{ $$ = std::make_unique<ast::stmt_waittill>(@$, std::move($1), std::move($4), std::make_unique<ast::expr_arguments>(@$)); }
|
||||
;
|
||||
|
||||
stmt_waittillmatch
|
||||
: expr_object WAITTILLMATCH LPAREN expr COMMA expr_arguments_no_empty RPAREN SEMICOLON
|
||||
{ $$ = std::make_unique<ast::stmt_waittillmatch>(@$, std::move($1), std::move($4), std::move($6)); }
|
||||
| expr_object WAITTILLMATCH LPAREN expr RPAREN SEMICOLON
|
||||
{ $$ = std::make_unique<ast::stmt_waittillmatch>(@$, std::move($1), std::move($4), std::make_unique<ast::expr_arguments>(@$)); }
|
||||
;
|
||||
|
||||
stmt_waittillframeend
|
||||
: WAITTILLFRAMEEND SEMICOLON
|
||||
{ $$ = std::make_unique<ast::stmt_waittillframeend>(@$); }
|
||||
;
|
||||
|
||||
stmt_if
|
||||
: IF LPAREN expr RPAREN stmt %prec THEN
|
||||
{ $$ = std::make_unique<ast::stmt_if>(@$, std::move($3), std::move($5)); }
|
||||
;
|
||||
|
||||
stmt_ifelse
|
||||
: IF LPAREN expr RPAREN stmt ELSE stmt
|
||||
{ $$ = std::make_unique<ast::stmt_ifelse>(@$, std::move($3), std::move($5), std::move($7)); }
|
||||
;
|
||||
|
||||
stmt_while
|
||||
: WHILE LPAREN expr RPAREN stmt
|
||||
{ $$ = std::make_unique<ast::stmt_while>(@$, std::move($3), std::move($5)); }
|
||||
;
|
||||
|
||||
stmt_dowhile
|
||||
: DO stmt WHILE LPAREN expr RPAREN SEMICOLON
|
||||
{ $$ = std::make_unique<ast::stmt_dowhile>(@$, std::move($5), std::move($2)); }
|
||||
;
|
||||
|
||||
stmt_for
|
||||
: FOR LPAREN stmt_expr SEMICOLON expr_or_empty SEMICOLON stmt_expr RPAREN stmt
|
||||
{ $$ = std::make_unique<ast::stmt_for>(@$, ast::stmt(std::move($3)), std::move($5), ast::stmt(std::move($7)), std::move($9)); }
|
||||
;
|
||||
|
||||
stmt_foreach
|
||||
: FOREACH LPAREN expr_identifier IN expr RPAREN stmt
|
||||
{ $$ = std::make_unique<ast::stmt_foreach>(@$, ast::expr(std::move($3)), std::move($5), std::move($7)); }
|
||||
| FOREACH LPAREN expr_identifier COMMA expr_identifier IN expr RPAREN stmt
|
||||
{ $$ = std::make_unique<ast::stmt_foreach>(@$, ast::expr(std::move($3)), ast::expr(std::move($5)), std::move($7), std::move($9)); }
|
||||
;
|
||||
|
||||
stmt_switch
|
||||
: SWITCH LPAREN expr RPAREN stmt_block
|
||||
{ $$ = std::make_unique<ast::stmt_switch>(@$, std::move($3), std::move($5)); }
|
||||
;
|
||||
|
||||
stmt_case
|
||||
: CASE expr_integer COLON
|
||||
{ $$ = std::make_unique<ast::stmt_case>(@$, ast::expr(std::move($2)), std::make_unique<ast::stmt_list>(@$)); }
|
||||
| CASE expr_string COLON
|
||||
{ $$ = std::make_unique<ast::stmt_case>(@$, ast::expr(std::move($2)), std::make_unique<ast::stmt_list>(@$)); }
|
||||
;
|
||||
|
||||
stmt_default
|
||||
: DEFAULT COLON
|
||||
{ $$ = std::make_unique<ast::stmt_default>(@$, std::make_unique<ast::stmt_list>(@$)); }
|
||||
;
|
||||
|
||||
stmt_break
|
||||
: BREAK SEMICOLON
|
||||
{ $$ = std::make_unique<ast::stmt_break>(@$); }
|
||||
;
|
||||
|
||||
stmt_continue
|
||||
: CONTINUE SEMICOLON
|
||||
{ $$ = std::make_unique<ast::stmt_continue>(@$); }
|
||||
;
|
||||
|
||||
stmt_return
|
||||
: RETURN expr SEMICOLON
|
||||
{ $$ = std::make_unique<ast::stmt_return>(@$, std::move($2)); }
|
||||
| RETURN SEMICOLON
|
||||
{ $$ = std::make_unique<ast::stmt_return>(@$, std::make_unique<ast::node>(@$)); }
|
||||
;
|
||||
|
||||
stmt_breakpoint
|
||||
: BREAKPOINT SEMICOLON
|
||||
{ $$ = std::make_unique<ast::stmt_breakpoint>(@$); }
|
||||
;
|
||||
|
||||
stmt_prof_begin
|
||||
: PROFBEGIN LPAREN expr_arguments RPAREN SEMICOLON
|
||||
{ $$ = std::make_unique<ast::stmt_prof_begin>(@$, std::move($3)); }
|
||||
;
|
||||
|
||||
stmt_prof_end
|
||||
: PROFEND LPAREN expr_arguments RPAREN SEMICOLON
|
||||
{ $$ = std::make_unique<ast::stmt_prof_end>(@$, std::move($3)); }
|
||||
;
|
||||
|
||||
expr
|
||||
: expr_ternary { $$ = std::move($1); }
|
||||
| expr_binary { $$ = std::move($1); }
|
||||
| expr_primitive { $$ = std::move($1); }
|
||||
;
|
||||
|
||||
expr_or_empty
|
||||
: expr { $$ = std::move($1); }
|
||||
| { $$.as_node = std::make_unique<ast::node>(@$); }
|
||||
;
|
||||
|
||||
expr_assign
|
||||
: expr_tuple ASSIGN expr
|
||||
{ $$.as_node = std::make_unique<ast::expr_assign_equal>(@$, std::move($1), std::move($3)); }
|
||||
| expr_object ASSIGN expr
|
||||
{ $$.as_node = std::make_unique<ast::expr_assign_equal>(@$, std::move($1), std::move($3)); }
|
||||
| expr_object ASSIGN_BW_OR expr
|
||||
{ $$.as_node = std::make_unique<ast::expr_assign_bitwise_or>(@$, std::move($1), std::move($3)); }
|
||||
| expr_object ASSIGN_BW_AND expr
|
||||
{ $$.as_node = std::make_unique<ast::expr_assign_bitwise_and>(@$, std::move($1), std::move($3)); }
|
||||
| expr_object ASSIGN_BW_EXOR expr
|
||||
{ $$.as_node = std::make_unique<ast::expr_assign_bitwise_exor>(@$, std::move($1), std::move($3)); }
|
||||
| expr_object ASSIGN_LSHIFT expr
|
||||
{ $$.as_node = std::make_unique<ast::expr_assign_shift_left>(@$, std::move($1),std::move( $3)); }
|
||||
| expr_object ASSIGN_RSHIFT expr
|
||||
{ $$.as_node = std::make_unique<ast::expr_assign_shift_right>(@$, std::move($1), std::move($3)); }
|
||||
| expr_object ASSIGN_ADD expr
|
||||
{ $$.as_node = std::make_unique<ast::expr_assign_add>(@$, std::move($1), std::move($3)); }
|
||||
| expr_object ASSIGN_SUB expr
|
||||
{ $$.as_node = std::make_unique<ast::expr_assign_sub>(@$, std::move($1), std::move($3)); }
|
||||
| expr_object ASSIGN_MUL expr
|
||||
{ $$.as_node = std::make_unique<ast::expr_assign_mul>(@$, std::move($1), std::move($3)); }
|
||||
| expr_object ASSIGN_DIV expr
|
||||
{ $$.as_node = std::make_unique<ast::expr_assign_div>(@$, std::move($1), std::move($3)); }
|
||||
| expr_object ASSIGN_MOD expr
|
||||
{ $$.as_node = std::make_unique<ast::expr_assign_mod>(@$, std::move($1), std::move($3)); }
|
||||
;
|
||||
|
||||
expr_increment
|
||||
: INCREMENT expr_object %prec PREINC
|
||||
{ $$.as_node = std::make_unique<ast::expr_increment>(@$, std::move($2), true); }
|
||||
| expr_object INCREMENT %prec POSTINC
|
||||
{ $$.as_node = std::make_unique<ast::expr_increment>(@$, std::move($1), false); }
|
||||
;
|
||||
|
||||
expr_decrement
|
||||
: DECREMENT expr_object %prec PREDEC
|
||||
{ $$.as_node = std::make_unique<ast::expr_decrement>(@$, std::move($2), true); }
|
||||
| expr_object DECREMENT %prec POSTDEC
|
||||
{ $$.as_node = std::make_unique<ast::expr_decrement>(@$, std::move($1), false); }
|
||||
;
|
||||
|
||||
expr_ternary
|
||||
: expr QMARK expr COLON expr %prec TERN
|
||||
{ $$.as_node = std::make_unique<ast::expr_ternary>(@$, std::move($1), std::move($3), std::move($5)); }
|
||||
;
|
||||
|
||||
expr_binary
|
||||
: expr OR expr
|
||||
{ $$.as_node = std::make_unique<ast::expr_or>(@$, std::move($1), std::move($3)); }
|
||||
| expr AND expr
|
||||
{ $$.as_node = std::make_unique<ast::expr_and>(@$, std::move($1), std::move($3)); }
|
||||
| expr EQUALITY expr
|
||||
{ $$.as_node = std::make_unique<ast::expr_equality>(@$, std::move($1), std::move($3)); }
|
||||
| expr INEQUALITY expr
|
||||
{ $$.as_node = std::make_unique<ast::expr_inequality>(@$, std::move($1), std::move($3)); }
|
||||
| expr LESS_EQUAL expr
|
||||
{ $$.as_node = std::make_unique<ast::expr_less_equal>(@$, std::move($1), std::move($3)); }
|
||||
| expr GREATER_EQUAL expr
|
||||
{ $$.as_node = std::make_unique<ast::expr_greater_equal>(@$, std::move($1), std::move($3)); }
|
||||
| expr LESS expr
|
||||
{ $$.as_node = std::make_unique<ast::expr_less>(@$, std::move($1), std::move($3)); }
|
||||
| expr GREATER expr
|
||||
{ $$.as_node = std::make_unique<ast::expr_greater>(@$, std::move($1), std::move($3)); }
|
||||
| expr BITWISE_OR expr
|
||||
{ $$.as_node = std::make_unique<ast::expr_bitwise_or>(@$, std::move($1), std::move($3)); }
|
||||
| expr BITWISE_AND expr
|
||||
{ $$.as_node = std::make_unique<ast::expr_bitwise_and>(@$, std::move($1), std::move($3)); }
|
||||
| expr BITWISE_EXOR expr
|
||||
{ $$.as_node = std::make_unique<ast::expr_bitwise_exor>(@$, std::move($1), std::move($3)); }
|
||||
| expr LSHIFT expr
|
||||
{ $$.as_node = std::make_unique<ast::expr_shift_left>(@$, std::move($1), std::move($3)); }
|
||||
| expr RSHIFT expr
|
||||
{ $$.as_node = std::make_unique<ast::expr_shift_right>(@$, std::move($1), std::move($3)); }
|
||||
| expr ADD expr
|
||||
{ $$.as_node = std::make_unique<ast::expr_add>(@$, std::move($1), std::move($3)); }
|
||||
| expr SUB expr
|
||||
{ $$.as_node = std::make_unique<ast::expr_sub>(@$, std::move($1), std::move($3)); }
|
||||
| expr MUL expr
|
||||
{ $$.as_node = std::make_unique<ast::expr_mul>(@$, std::move($1), std::move($3)); }
|
||||
| expr DIV expr
|
||||
{ $$.as_node = std::make_unique<ast::expr_div>(@$, std::move($1), std::move($3)); }
|
||||
| expr MOD expr
|
||||
{ $$.as_node = std::make_unique<ast::expr_mod>(@$, std::move($1), std::move($3)); }
|
||||
;
|
||||
|
||||
expr_primitive
|
||||
: expr_complement { $$.as_node = std::move($1); }
|
||||
| expr_negate { $$.as_node = std::move($1); }
|
||||
| expr_not { $$.as_node = std::move($1); }
|
||||
| expr_call { $$.as_node = std::move($1); }
|
||||
| expr_method { $$.as_node = std::move($1); }
|
||||
| expr_add_array { $$.as_node = std::move($1); }
|
||||
| expr_reference { $$.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); }
|
||||
| expr_paren { $$.as_node = std::move($1); }
|
||||
| expr_thisthread { $$.as_node = std::move($1); }
|
||||
| expr_empty_array { $$.as_node = std::move($1); }
|
||||
| expr_undefined { $$.as_node = std::move($1); }
|
||||
| expr_game { $$.as_node = std::move($1); }
|
||||
| expr_self { $$.as_node = std::move($1); }
|
||||
| expr_anim { $$.as_node = std::move($1); }
|
||||
| expr_level { $$.as_node = std::move($1); }
|
||||
| expr_animation { $$.as_node = std::move($1); }
|
||||
| expr_animtree { $$.as_node = std::move($1); }
|
||||
| expr_identifier { $$.as_node = std::move($1); }
|
||||
| expr_istring { $$.as_node = std::move($1); }
|
||||
| expr_string { $$.as_node = std::move($1); }
|
||||
| expr_vector { $$.as_node = std::move($1); }
|
||||
| expr_float { $$.as_node = std::move($1); }
|
||||
| expr_integer { $$.as_node = std::move($1); }
|
||||
| expr_false { $$.as_node = std::move($1); }
|
||||
| expr_true { $$.as_node = std::move($1); }
|
||||
;
|
||||
|
||||
expr_complement
|
||||
: COMPLEMENT expr
|
||||
{ $$ = std::make_unique<ast::expr_complement>(@$, std::move($2)); }
|
||||
;
|
||||
|
||||
expr_negate
|
||||
: SUB expr_identifier %prec NEG
|
||||
{ $$ = std::make_unique<ast::expr_negate>(@$, ast::expr(std::move($2))); }
|
||||
| SUB expr_paren %prec NEG
|
||||
{ $$ = std::make_unique<ast::expr_negate>(@$, ast::expr(std::move($2))); }
|
||||
| SUB expr_array %prec NEG
|
||||
{ $$ = std::make_unique<ast::expr_negate>(@$, ast::expr(std::move($2))); }
|
||||
| SUB expr_field %prec NEG
|
||||
{ $$ = std::make_unique<ast::expr_negate>(@$, ast::expr(std::move($2))); }
|
||||
;
|
||||
|
||||
expr_not
|
||||
: NOT expr
|
||||
{ $$ = std::make_unique<ast::expr_not>(@$, std::move($2)); }
|
||||
;
|
||||
|
||||
expr_call
|
||||
: expr_function { $$ = std::make_unique<ast::expr_call>(@$, std::move($1)); }
|
||||
| expr_pointer { $$ = std::make_unique<ast::expr_call>(@$, std::move($1)); }
|
||||
;
|
||||
expr_method
|
||||
: expr_object expr_function { $$ = std::make_unique<ast::expr_method>(@$, std::move($1), std::move($2)); }
|
||||
| expr_object expr_pointer { $$ = std::make_unique<ast::expr_method>(@$, std::move($1), std::move($2)); }
|
||||
;
|
||||
|
||||
expr_function
|
||||
: expr_identifier LPAREN expr_arguments RPAREN
|
||||
{ $$.as_function = std::make_unique<ast::expr_function>(@$, std::make_unique<ast::expr_path>(@$), std::move($1), std::move($3), ast::call::mode::normal); }
|
||||
| expr_path DOUBLECOLON expr_identifier LPAREN expr_arguments RPAREN
|
||||
{ $$.as_function = std::make_unique<ast::expr_function>(@$, std::move($1), std::move($3), std::move($5), ast::call::mode::normal); }
|
||||
| THREAD expr_identifier LPAREN expr_arguments RPAREN
|
||||
{ $$.as_function = std::make_unique<ast::expr_function>(@$, std::make_unique<ast::expr_path>(@$), std::move($2), std::move($4), ast::call::mode::thread); }
|
||||
| THREAD expr_path DOUBLECOLON expr_identifier LPAREN expr_arguments RPAREN
|
||||
{ $$.as_function = std::make_unique<ast::expr_function>(@$, std::move($2), std::move($4), std::move($6), ast::call::mode::thread); }
|
||||
| CHILDTHREAD expr_identifier LPAREN expr_arguments RPAREN
|
||||
{ $$.as_function = std::make_unique<ast::expr_function>(@$, std::make_unique<ast::expr_path>(@$), std::move($2), std::move($4), ast::call::mode::childthread); }
|
||||
| CHILDTHREAD expr_path DOUBLECOLON expr_identifier LPAREN expr_arguments RPAREN
|
||||
{ $$.as_function = std::make_unique<ast::expr_function>(@$, std::move($2), std::move($4), std::move($6), ast::call::mode::childthread); }
|
||||
;
|
||||
|
||||
expr_pointer
|
||||
: LBRACKET LBRACKET expr RBRACKET RBRACKET LPAREN expr_arguments RPAREN
|
||||
{ $$.as_pointer = std::make_unique<ast::expr_pointer>(@$, std::move($3), std::move($7), ast::call::mode::normal); }
|
||||
| THREAD LBRACKET LBRACKET expr RBRACKET RBRACKET LPAREN expr_arguments RPAREN
|
||||
{ $$.as_pointer = std::make_unique<ast::expr_pointer>(@$, std::move($4), std::move($8), ast::call::mode::thread); }
|
||||
| CHILDTHREAD LBRACKET LBRACKET expr RBRACKET RBRACKET LPAREN expr_arguments RPAREN
|
||||
{ $$.as_pointer = std::make_unique<ast::expr_pointer>(@$, std::move($4), std::move($8), ast::call::mode::childthread); }
|
||||
| CALL LBRACKET LBRACKET expr RBRACKET RBRACKET LPAREN expr_arguments RPAREN
|
||||
{ $$.as_pointer = std::make_unique<ast::expr_pointer>(@$, std::move($4), std::move($8), ast::call::mode::builtin); }
|
||||
;
|
||||
|
||||
expr_add_array
|
||||
: LBRACKET expr_arguments_no_empty RBRACKET
|
||||
{ $$ = std::make_unique<ast::expr_add_array>(@$, std::move($2)); }
|
||||
;
|
||||
|
||||
expr_parameters
|
||||
: expr_parameters COMMA expr_identifier
|
||||
{ $$ = std::move($1); $$->list.push_back(std::move($3)); }
|
||||
| expr_identifier
|
||||
{ $$ = std::make_unique<ast::expr_parameters>(@$); $$->list.push_back(std::move($1)); }
|
||||
|
|
||||
{ $$ = std::make_unique<ast::expr_parameters>(@$); }
|
||||
;
|
||||
|
||||
expr_arguments
|
||||
: expr_arguments_no_empty
|
||||
{ $$ = std::move($1); }
|
||||
|
|
||||
{ $$ = std::make_unique<ast::expr_arguments>(@$); }
|
||||
;
|
||||
|
||||
expr_arguments_no_empty
|
||||
: expr_arguments COMMA expr
|
||||
{ $$ = std::move($1); $$->list.push_back(std::move($3)); }
|
||||
| expr %prec ADD_ARRAY
|
||||
{ $$ = std::make_unique<ast::expr_arguments>(@$); $$->list.push_back(std::move($1)); }
|
||||
;
|
||||
|
||||
expr_reference
|
||||
: DOUBLECOLON expr_identifier
|
||||
{ $$ = std::make_unique<ast::expr_reference>(@$, std::make_unique<ast::expr_path>(@$), std::move($2)); }
|
||||
| expr_path DOUBLECOLON expr_identifier
|
||||
{ $$ = std::make_unique<ast::expr_reference>(@$, std::move($1), std::move($3)); }
|
||||
;
|
||||
|
||||
expr_tuple
|
||||
: LBRACKET expr_tuple_arguments RBRACKET
|
||||
{ $$.as_node = std::move($2); }
|
||||
;
|
||||
|
||||
expr_tuple_arguments
|
||||
: expr_tuple_arguments COMMA expr_tuple_types
|
||||
{ $$ = std::move($1); $$->list.push_back(std::move($3)); }
|
||||
| expr_tuple_types
|
||||
{ $$ = std::make_unique<ast::expr_tuple>(@$); $$->list.push_back(std::move($1)); }
|
||||
;
|
||||
|
||||
expr_tuple_types
|
||||
: expr_array { $$.as_node = std::move($1); }
|
||||
| expr_field { $$.as_node = std::move($1); }
|
||||
| expr_identifier { $$.as_node = std::move($1); }
|
||||
;
|
||||
|
||||
expr_array
|
||||
: expr_object LBRACKET expr RBRACKET
|
||||
{ $$ = std::make_unique<ast::expr_array>(@$, std::move($1), std::move($3)); }
|
||||
;
|
||||
|
||||
expr_field
|
||||
: expr_object DOT expr_identifier_nosize
|
||||
{ $$ = std::make_unique<ast::expr_field>(@$, std::move($1), std::move($3)); }
|
||||
;
|
||||
|
||||
expr_size
|
||||
: expr_object DOT SIZE %prec SIZEOF
|
||||
{ $$ = std::make_unique<ast::expr_size>(@$, std::move($1)); }
|
||||
;
|
||||
|
||||
expr_paren
|
||||
: LPAREN expr RPAREN
|
||||
{ $$ = std::make_unique<ast::expr_paren>(@$, std::move($2)); }
|
||||
;
|
||||
|
||||
expr_object
|
||||
: expr_call { $$.as_node = std::move($1); }
|
||||
| expr_method { $$.as_node = std::move($1); }
|
||||
| expr_array { $$.as_node = std::move($1); }
|
||||
| expr_field { $$.as_node = std::move($1); }
|
||||
| expr_game { $$.as_node = std::move($1); }
|
||||
| expr_self { $$.as_node = std::move($1); }
|
||||
| expr_anim { $$.as_node = std::move($1); }
|
||||
| expr_level { $$.as_node = std::move($1); }
|
||||
| expr_identifier { $$.as_node = std::move($1); }
|
||||
;
|
||||
|
||||
expr_thisthread
|
||||
: THISTHREAD
|
||||
{ $$ = std::make_unique<ast::expr_thisthread>(@$); };
|
||||
;
|
||||
|
||||
expr_empty_array
|
||||
: LBRACKET RBRACKET
|
||||
{ $$ = std::make_unique<ast::expr_empty_array>(@$); };
|
||||
;
|
||||
|
||||
expr_undefined
|
||||
: UNDEFINED
|
||||
{ $$ = std::make_unique<ast::expr_undefined>(@$); };
|
||||
;
|
||||
|
||||
expr_game
|
||||
: GAME
|
||||
{ $$ = std::make_unique<ast::expr_game>(@$); };
|
||||
;
|
||||
|
||||
expr_self
|
||||
: SELF
|
||||
{ $$ = std::make_unique<ast::expr_self>(@$); };
|
||||
;
|
||||
|
||||
expr_anim
|
||||
: ANIM
|
||||
{ $$ = std::make_unique<ast::expr_anim>(@$); };
|
||||
;
|
||||
|
||||
expr_level
|
||||
: LEVEL
|
||||
{ $$ = std::make_unique<ast::expr_level>(@$); };
|
||||
;
|
||||
|
||||
expr_animation
|
||||
: MOD IDENTIFIER %prec ANIMREF
|
||||
{ $$ = std::make_unique<ast::expr_animation>(@$, $2); };
|
||||
;
|
||||
|
||||
expr_animtree
|
||||
: ANIMTREE
|
||||
{ $$ = std::make_unique<ast::expr_animtree>(@$); };
|
||||
;
|
||||
|
||||
expr_identifier_nosize
|
||||
: IDENTIFIER
|
||||
{ $$ = std::make_unique<ast::expr_identifier>(@$, $1); };
|
||||
;
|
||||
|
||||
expr_identifier
|
||||
: IDENTIFIER
|
||||
{ $$ = std::make_unique<ast::expr_identifier>(@$, $1); };
|
||||
| SIZE
|
||||
{ $$ = std::make_unique<ast::expr_identifier>(@$, "size"); };
|
||||
;
|
||||
|
||||
expr_path
|
||||
: IDENTIFIER
|
||||
{ $$ = std::make_unique<ast::expr_path>(@$, $1); };
|
||||
| PATH
|
||||
{ $$ = std::make_unique<ast::expr_path>(@$, $1); };
|
||||
;
|
||||
|
||||
expr_istring
|
||||
: ISTRING
|
||||
{ $$ = std::make_unique<ast::expr_istring>(@$, $1); };
|
||||
;
|
||||
|
||||
expr_string
|
||||
: STRING
|
||||
{ $$ = std::make_unique<ast::expr_string>(@$, $1); };
|
||||
;
|
||||
|
||||
expr_vector
|
||||
: LPAREN expr COMMA expr COMMA expr RPAREN
|
||||
{ $$ = std::make_unique<ast::expr_vector>(@$, std::move($2), std::move($4), std::move($6)); };
|
||||
;
|
||||
|
||||
expr_float
|
||||
: SUB FLOAT %prec NEG
|
||||
{ $$ = std::make_unique<ast::expr_float>(@$, "-" + $2); };
|
||||
| FLOAT
|
||||
{ $$ = std::make_unique<ast::expr_float>(@$, $1); };
|
||||
;
|
||||
|
||||
expr_integer
|
||||
: SUB INTEGER %prec NEG
|
||||
{ $$ = std::make_unique<ast::expr_integer>(@$, "-" + $2); };
|
||||
| INTEGER
|
||||
{ $$ = std::make_unique<ast::expr_integer>(@$, $1); };
|
||||
;
|
||||
|
||||
expr_false
|
||||
: FALSE
|
||||
{ $$ = std::make_unique<ast::expr_false>(@$); };
|
||||
;
|
||||
|
||||
expr_true
|
||||
: TRUE
|
||||
{ $$ = std::make_unique<ast::expr_true>(@$); };
|
||||
;
|
||||
|
||||
%%
|
||||
|
||||
void xsk::gsc::iw6::parser::error(const xsk::gsc::location& loc, const std::string& msg)
|
||||
{
|
||||
throw xsk::gsc::comp_error(loc, msg);
|
||||
}
|
@ -1,9 +0,0 @@
|
||||
generate: iw7
|
||||
|
||||
clean:
|
||||
rm -rf ./parser.hpp
|
||||
rm -rf ./parser.cpp
|
||||
|
||||
iw7: parser.ypp
|
||||
bison parser.ypp -Wcounterexamples
|
||||
mv parser.hpp parser.cpp ../../src/iw7/xsk/
|
@ -1,888 +0,0 @@
|
||||
/* Copyright 2022 xensik. All rights reserved.
|
||||
//
|
||||
// Use of this source code is governed by a GNU GPLv3 license
|
||||
// that can be found in the LICENSE file.
|
||||
*/
|
||||
|
||||
%require "3.7"
|
||||
%skeleton "lalr1.cc"
|
||||
%language "c++"
|
||||
%output "parser.cpp"
|
||||
%defines "parser.hpp"
|
||||
%define api.prefix {IW7}
|
||||
%define api.namespace {xsk::gsc::iw7}
|
||||
%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 { xsk::gsc::iw7::lexer& lexer }
|
||||
%parse-param { xsk::gsc::iw7::lexer& lexer }
|
||||
%parse-param { xsk::gsc::ast::program::ptr& ast }
|
||||
|
||||
%code requires
|
||||
{
|
||||
#ifdef _MSC_VER
|
||||
#pragma warning(disable:4065)
|
||||
#pragma warning(disable:4127)
|
||||
#endif
|
||||
#include "iw7.hpp"
|
||||
namespace xsk::gsc::iw7 { class lexer; }
|
||||
}
|
||||
|
||||
%code top
|
||||
{
|
||||
#include "stdafx.hpp"
|
||||
#include "parser.hpp"
|
||||
#include "lexer.hpp"
|
||||
using namespace xsk::gsc;
|
||||
xsk::gsc::iw7::parser::symbol_type IW7lex(xsk::gsc::iw7::lexer& lexer);
|
||||
}
|
||||
|
||||
%token SH_DEFINE "#define"
|
||||
%token SH_UNDEF "#undef"
|
||||
%token SH_IFDEF "#ifdef"
|
||||
%token SH_IFNDEF "#ifndef"
|
||||
%token SH_IF "#if"
|
||||
%token SH_ELIF "#elif"
|
||||
%token SH_ELSE "#else"
|
||||
%token SH_ENDIF "#endif"
|
||||
%token DEVBEGIN "/#"
|
||||
%token DEVEND "#/"
|
||||
%token INLINE "#inline"
|
||||
%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 IF "if"
|
||||
%token ELSE "else"
|
||||
%token DO "do"
|
||||
%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 BREAKPOINT "breakpoint"
|
||||
%token PROFBEGIN "prof_begin"
|
||||
%token PROFEND "prof_end"
|
||||
%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_MUL "*="
|
||||
%token ASSIGN_DIV "/="
|
||||
%token ASSIGN_MOD "%="
|
||||
%token ASSIGN_BW_OR "|="
|
||||
%token ASSIGN_BW_AND "&="
|
||||
%token ASSIGN_BW_EXOR "^="
|
||||
%token ASSIGN_RSHIFT ">>="
|
||||
%token ASSIGN_LSHIFT "<<="
|
||||
%token BITWISE_OR "|"
|
||||
%token BITWISE_AND "&"
|
||||
%token BITWISE_EXOR "^"
|
||||
%token ADD "+"
|
||||
%token SUB "-"
|
||||
%token MUL "*"
|
||||
%token DIV "/"
|
||||
%token MOD "%"
|
||||
%token <std::string> PATH "path"
|
||||
%token <std::string> IDENTIFIER "identifier"
|
||||
%token <std::string> STRING "string literal"
|
||||
%token <std::string> ISTRING "localized string"
|
||||
%token <std::string> FLOAT "float"
|
||||
%token <std::string> INTEGER "integer"
|
||||
|
||||
%type <ast::program::ptr> program
|
||||
%type <ast::include::ptr> include
|
||||
%type <ast::decl> declaration
|
||||
%type <ast::decl_usingtree::ptr> decl_usingtree
|
||||
%type <ast::decl_constant::ptr> decl_constant
|
||||
%type <ast::decl_thread::ptr> decl_thread
|
||||
%type <ast::stmt> stmt
|
||||
%type <ast::stmt> stmt_or_dev
|
||||
%type <ast::stmt_list::ptr> stmt_list
|
||||
%type <ast::stmt_list::ptr> stmt_or_dev_list
|
||||
%type <ast::stmt_dev::ptr> stmt_dev
|
||||
%type <ast::stmt_list::ptr> stmt_block
|
||||
%type <ast::stmt_expr::ptr> stmt_expr
|
||||
%type <ast::stmt_call::ptr> stmt_call
|
||||
%type <ast::stmt_assign::ptr> stmt_assign
|
||||
%type <ast::stmt_endon::ptr> stmt_endon
|
||||
%type <ast::stmt_notify::ptr> stmt_notify
|
||||
%type <ast::stmt_wait::ptr> stmt_wait
|
||||
%type <ast::stmt_waittill::ptr> stmt_waittill
|
||||
%type <ast::stmt_waittillmatch::ptr> stmt_waittillmatch
|
||||
%type <ast::stmt_waittillframeend::ptr> stmt_waittillframeend
|
||||
%type <ast::stmt_if::ptr> stmt_if
|
||||
%type <ast::stmt_ifelse::ptr> stmt_ifelse
|
||||
%type <ast::stmt_while::ptr> stmt_while
|
||||
%type <ast::stmt_dowhile::ptr> stmt_dowhile
|
||||
%type <ast::stmt_for::ptr> stmt_for
|
||||
%type <ast::stmt_foreach::ptr> stmt_foreach
|
||||
%type <ast::stmt_switch::ptr> stmt_switch
|
||||
%type <ast::stmt_case::ptr> stmt_case
|
||||
%type <ast::stmt_default::ptr> stmt_default
|
||||
%type <ast::stmt_break::ptr> stmt_break
|
||||
%type <ast::stmt_continue::ptr> stmt_continue
|
||||
%type <ast::stmt_return::ptr> stmt_return
|
||||
%type <ast::stmt_breakpoint::ptr> stmt_breakpoint
|
||||
%type <ast::stmt_prof_begin::ptr> stmt_prof_begin
|
||||
%type <ast::stmt_prof_end::ptr> stmt_prof_end
|
||||
%type <ast::expr> expr
|
||||
%type <ast::expr> expr_or_empty
|
||||
%type <ast::expr> expr_assign
|
||||
%type <ast::expr> expr_increment
|
||||
%type <ast::expr> expr_decrement
|
||||
%type <ast::expr> expr_ternary
|
||||
%type <ast::expr> expr_binary
|
||||
%type <ast::expr> expr_primitive
|
||||
%type <ast::expr_complement::ptr> expr_complement
|
||||
%type <ast::expr_negate::ptr> expr_negate
|
||||
%type <ast::expr_not::ptr> expr_not
|
||||
%type <ast::expr_call::ptr> expr_call
|
||||
%type <ast::expr_method::ptr> expr_method
|
||||
%type <ast::call> expr_function
|
||||
%type <ast::call> expr_pointer
|
||||
%type <ast::expr_add_array::ptr> expr_add_array
|
||||
%type <ast::expr_parameters::ptr> expr_parameters
|
||||
%type <ast::expr_arguments::ptr> expr_arguments
|
||||
%type <ast::expr_arguments::ptr> expr_arguments_no_empty
|
||||
%type <ast::expr_reference::ptr> expr_reference
|
||||
%type <ast::expr> expr_tuple
|
||||
%type <ast::expr_tuple::ptr> expr_tuple_arguments
|
||||
%type <ast::expr> expr_tuple_types
|
||||
%type <ast::expr_array::ptr> expr_array
|
||||
%type <ast::expr_field::ptr> expr_field
|
||||
%type <ast::expr_size::ptr> expr_size
|
||||
%type <ast::expr_paren::ptr> expr_paren
|
||||
%type <ast::expr> expr_object
|
||||
%type <ast::expr_thisthread::ptr> expr_thisthread
|
||||
%type <ast::expr_empty_array::ptr> expr_empty_array
|
||||
%type <ast::expr_undefined::ptr> expr_undefined
|
||||
%type <ast::expr_game::ptr> expr_game
|
||||
%type <ast::expr_self::ptr> expr_self
|
||||
%type <ast::expr_anim::ptr> expr_anim
|
||||
%type <ast::expr_level::ptr> expr_level
|
||||
%type <ast::expr_animation::ptr> expr_animation
|
||||
%type <ast::expr_animtree::ptr> expr_animtree
|
||||
%type <ast::expr_identifier::ptr> expr_identifier_nosize
|
||||
%type <ast::expr_identifier::ptr> expr_identifier
|
||||
%type <ast::expr_path::ptr> expr_path
|
||||
%type <ast::expr_istring::ptr> expr_istring
|
||||
%type <ast::expr_string::ptr> expr_string
|
||||
%type <ast::expr_vector::ptr> expr_vector
|
||||
%type <ast::expr_float::ptr> expr_float
|
||||
%type <ast::expr_integer::ptr> expr_integer
|
||||
%type <ast::expr_false::ptr> expr_false
|
||||
%type <ast::expr_true::ptr> expr_true
|
||||
|
||||
%nonassoc SIZEOF
|
||||
%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_EXOR
|
||||
%left BITWISE_AND
|
||||
%left EQUALITY INEQUALITY
|
||||
%left LESS GREATER LESS_EQUAL GREATER_EQUAL
|
||||
%left LSHIFT RSHIFT
|
||||
%left ADD SUB
|
||||
%left MUL 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<ast::program>(@$); }
|
||||
;
|
||||
|
||||
program
|
||||
: program inline
|
||||
{ $$ = std::move($1); }
|
||||
| program include
|
||||
{ $$ = std::move($1); $$->includes.push_back(std::move($2)); }
|
||||
| program declaration
|
||||
{ $$ = std::move($1); $$->declarations.push_back(std::move($2)); }
|
||||
| inline
|
||||
{ $$ = std::make_unique<ast::program>(@$); }
|
||||
| include
|
||||
{ $$ = std::make_unique<ast::program>(@$); $$->includes.push_back(std::move($1)); }
|
||||
| declaration
|
||||
{ $$ = std::make_unique<ast::program>(@$); $$->declarations.push_back(std::move($1)); }
|
||||
;
|
||||
|
||||
inline
|
||||
: INLINE expr_path SEMICOLON { lexer.push_header($2->value); }
|
||||
;
|
||||
|
||||
include
|
||||
: INCLUDE expr_path SEMICOLON
|
||||
{ $$ = std::make_unique<ast::include>(@$, std::move($2)); }
|
||||
;
|
||||
|
||||
declaration
|
||||
: DEVBEGIN { $$.as_dev_begin = std::make_unique<ast::decl_dev_begin>(@$); }
|
||||
| DEVEND { $$.as_dev_end = std::make_unique<ast::decl_dev_end>(@$); }
|
||||
| decl_usingtree { $$.as_usingtree = std::move($1); }
|
||||
| decl_constant { $$.as_constant = std::move($1); }
|
||||
| decl_thread { $$.as_thread = std::move($1); }
|
||||
;
|
||||
|
||||
decl_usingtree
|
||||
: USINGTREE LPAREN expr_string RPAREN SEMICOLON
|
||||
{ lexer.ban_header(@$); $$ = std::make_unique<ast::decl_usingtree>(@$, std::move($3)); }
|
||||
;
|
||||
|
||||
decl_constant
|
||||
: expr_identifier ASSIGN expr SEMICOLON
|
||||
{ $$ = std::make_unique<ast::decl_constant>(@$, std::move($1), std::move($3)); }
|
||||
;
|
||||
|
||||
decl_thread
|
||||
: expr_identifier LPAREN expr_parameters RPAREN stmt_block
|
||||
{ lexer.ban_header(@$); $$ = std::make_unique<ast::decl_thread>(@$, std::move($1), std::move($3), std::move($5)); }
|
||||
;
|
||||
|
||||
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_if { $$.as_if = std::move($1); }
|
||||
| stmt_ifelse { $$.as_ifelse = std::move($1); }
|
||||
| stmt_while { $$.as_while = std::move($1); }
|
||||
| stmt_dowhile { $$.as_dowhile = 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_breakpoint { $$.as_breakpoint = std::move($1); }
|
||||
| stmt_prof_begin { $$.as_prof_begin = std::move($1); }
|
||||
| stmt_prof_end { $$.as_prof_end = std::move($1); }
|
||||
;
|
||||
|
||||
stmt_or_dev
|
||||
: stmt { $$ = std::move($1); }
|
||||
| stmt_dev { $$.as_dev = std::move($1); }
|
||||
;
|
||||
|
||||
stmt_list
|
||||
: stmt_list stmt
|
||||
{ $$ = std::move($1); $$->list.push_back(std::move($2)); }
|
||||
| stmt
|
||||
{ $$ = std::make_unique<ast::stmt_list>(@$); $$->list.push_back(std::move($1)); }
|
||||
;
|
||||
|
||||
stmt_or_dev_list
|
||||
: stmt_or_dev_list stmt_or_dev
|
||||
{ $$ = std::move($1); $$->list.push_back(std::move($2)); }
|
||||
| stmt_or_dev
|
||||
{ $$ = std::make_unique<ast::stmt_list>(@$); $$->list.push_back(std::move($1)); }
|
||||
;
|
||||
|
||||
stmt_dev
|
||||
: DEVBEGIN stmt_list DEVEND { $$ = std::make_unique<ast::stmt_dev>(@$, std::move($2)); }
|
||||
| DEVBEGIN DEVEND { $$ = std::make_unique<ast::stmt_dev>(@$, std::make_unique<ast::stmt_list>(@$)); }
|
||||
;
|
||||
|
||||
stmt_block
|
||||
: LBRACE stmt_or_dev_list RBRACE { $$ = std::move($2); }
|
||||
| LBRACE RBRACE { $$ = std::make_unique<ast::stmt_list>(@$); }
|
||||
;
|
||||
|
||||
stmt_expr
|
||||
: expr_assign
|
||||
{ $$ = std::make_unique<ast::stmt_expr>(@$, std::move($1)); }
|
||||
| expr_increment
|
||||
{ $$ = std::make_unique<ast::stmt_expr>(@$, std::move($1)); }
|
||||
| expr_decrement
|
||||
{ $$ = std::make_unique<ast::stmt_expr>(@$, std::move($1)); }
|
||||
|
|
||||
{ $$ = std::make_unique<ast::stmt_expr>(@$, std::make_unique<ast::node>(@$)); }
|
||||
;
|
||||
|
||||
stmt_call
|
||||
: expr_call SEMICOLON
|
||||
{ $$ = std::make_unique<ast::stmt_call>(@$, ast::expr(std::move($1))); }
|
||||
| expr_method SEMICOLON
|
||||
{ $$ = std::make_unique<ast::stmt_call>(@$, ast::expr(std::move($1))); }
|
||||
;
|
||||
|
||||
stmt_assign
|
||||
: expr_assign SEMICOLON
|
||||
{ $$ = std::make_unique<ast::stmt_assign>(@$, std::move($1)); }
|
||||
| expr_increment SEMICOLON
|
||||
{ $$ = std::make_unique<ast::stmt_assign>(@$, std::move($1)); }
|
||||
| expr_decrement SEMICOLON
|
||||
{ $$ = std::make_unique<ast::stmt_assign>(@$, std::move($1)); }
|
||||
;
|
||||
|
||||
stmt_endon
|
||||
: expr_object ENDON LPAREN expr RPAREN SEMICOLON
|
||||
{ $$ = std::make_unique<ast::stmt_endon>(@$, std::move($1), std::move($4)); }
|
||||
;
|
||||
|
||||
stmt_notify
|
||||
: expr_object NOTIFY LPAREN expr COMMA expr_arguments_no_empty RPAREN SEMICOLON
|
||||
{ $$ = std::make_unique<ast::stmt_notify>(@$, std::move($1), std::move($4), std::move($6)); }
|
||||
| expr_object NOTIFY LPAREN expr RPAREN SEMICOLON
|
||||
{ $$ = std::make_unique<ast::stmt_notify>(@$, std::move($1), std::move($4), std::make_unique<ast::expr_arguments>(@$)); }
|
||||
;
|
||||
|
||||
stmt_wait
|
||||
: WAIT expr SEMICOLON
|
||||
{ $$ = std::make_unique<ast::stmt_wait>(@$, std::move($2)); }
|
||||
;
|
||||
|
||||
stmt_waittill
|
||||
: expr_object WAITTILL LPAREN expr COMMA expr_arguments_no_empty RPAREN SEMICOLON
|
||||
{ $$ = std::make_unique<ast::stmt_waittill>(@$, std::move($1), std::move($4), std::move($6)); }
|
||||
| expr_object WAITTILL LPAREN expr RPAREN SEMICOLON
|
||||
{ $$ = std::make_unique<ast::stmt_waittill>(@$, std::move($1), std::move($4), std::make_unique<ast::expr_arguments>(@$)); }
|
||||
;
|
||||
|
||||
stmt_waittillmatch
|
||||
: expr_object WAITTILLMATCH LPAREN expr COMMA expr_arguments_no_empty RPAREN SEMICOLON
|
||||
{ $$ = std::make_unique<ast::stmt_waittillmatch>(@$, std::move($1), std::move($4), std::move($6)); }
|
||||
| expr_object WAITTILLMATCH LPAREN expr RPAREN SEMICOLON
|
||||
{ $$ = std::make_unique<ast::stmt_waittillmatch>(@$, std::move($1), std::move($4), std::make_unique<ast::expr_arguments>(@$)); }
|
||||
;
|
||||
|
||||
stmt_waittillframeend
|
||||
: WAITTILLFRAMEEND SEMICOLON
|
||||
{ $$ = std::make_unique<ast::stmt_waittillframeend>(@$); }
|
||||
;
|
||||
|
||||
stmt_if
|
||||
: IF LPAREN expr RPAREN stmt %prec THEN
|
||||
{ $$ = std::make_unique<ast::stmt_if>(@$, std::move($3), std::move($5)); }
|
||||
;
|
||||
|
||||
stmt_ifelse
|
||||
: IF LPAREN expr RPAREN stmt ELSE stmt
|
||||
{ $$ = std::make_unique<ast::stmt_ifelse>(@$, std::move($3), std::move($5), std::move($7)); }
|
||||
;
|
||||
|
||||
stmt_while
|
||||
: WHILE LPAREN expr RPAREN stmt
|
||||
{ $$ = std::make_unique<ast::stmt_while>(@$, std::move($3), std::move($5)); }
|
||||
;
|
||||
|
||||
stmt_dowhile
|
||||
: DO stmt WHILE LPAREN expr RPAREN SEMICOLON
|
||||
{ $$ = std::make_unique<ast::stmt_dowhile>(@$, std::move($5), std::move($2)); }
|
||||
;
|
||||
|
||||
stmt_for
|
||||
: FOR LPAREN stmt_expr SEMICOLON expr_or_empty SEMICOLON stmt_expr RPAREN stmt
|
||||
{ $$ = std::make_unique<ast::stmt_for>(@$, ast::stmt(std::move($3)), std::move($5), ast::stmt(std::move($7)), std::move($9)); }
|
||||
;
|
||||
|
||||
stmt_foreach
|
||||
: FOREACH LPAREN expr_identifier IN expr RPAREN stmt
|
||||
{ $$ = std::make_unique<ast::stmt_foreach>(@$, ast::expr(std::move($3)), std::move($5), std::move($7)); }
|
||||
| FOREACH LPAREN expr_identifier COMMA expr_identifier IN expr RPAREN stmt
|
||||
{ $$ = std::make_unique<ast::stmt_foreach>(@$, ast::expr(std::move($3)), ast::expr(std::move($5)), std::move($7), std::move($9)); }
|
||||
;
|
||||
|
||||
stmt_switch
|
||||
: SWITCH LPAREN expr RPAREN stmt_block
|
||||
{ $$ = std::make_unique<ast::stmt_switch>(@$, std::move($3), std::move($5)); }
|
||||
;
|
||||
|
||||
stmt_case
|
||||
: CASE expr_integer COLON
|
||||
{ $$ = std::make_unique<ast::stmt_case>(@$, ast::expr(std::move($2)), std::make_unique<ast::stmt_list>(@$)); }
|
||||
| CASE expr_string COLON
|
||||
{ $$ = std::make_unique<ast::stmt_case>(@$, ast::expr(std::move($2)), std::make_unique<ast::stmt_list>(@$)); }
|
||||
;
|
||||
|
||||
stmt_default
|
||||
: DEFAULT COLON
|
||||
{ $$ = std::make_unique<ast::stmt_default>(@$, std::make_unique<ast::stmt_list>(@$)); }
|
||||
;
|
||||
|
||||
stmt_break
|
||||
: BREAK SEMICOLON
|
||||
{ $$ = std::make_unique<ast::stmt_break>(@$); }
|
||||
;
|
||||
|
||||
stmt_continue
|
||||
: CONTINUE SEMICOLON
|
||||
{ $$ = std::make_unique<ast::stmt_continue>(@$); }
|
||||
;
|
||||
|
||||
stmt_return
|
||||
: RETURN expr SEMICOLON
|
||||
{ $$ = std::make_unique<ast::stmt_return>(@$, std::move($2)); }
|
||||
| RETURN SEMICOLON
|
||||
{ $$ = std::make_unique<ast::stmt_return>(@$, std::make_unique<ast::node>(@$)); }
|
||||
;
|
||||
|
||||
stmt_breakpoint
|
||||
: BREAKPOINT SEMICOLON
|
||||
{ $$ = std::make_unique<ast::stmt_breakpoint>(@$); }
|
||||
;
|
||||
|
||||
stmt_prof_begin
|
||||
: PROFBEGIN LPAREN expr_arguments RPAREN SEMICOLON
|
||||
{ $$ = std::make_unique<ast::stmt_prof_begin>(@$, std::move($3)); }
|
||||
;
|
||||
|
||||
stmt_prof_end
|
||||
: PROFEND LPAREN expr_arguments RPAREN SEMICOLON
|
||||
{ $$ = std::make_unique<ast::stmt_prof_end>(@$, std::move($3)); }
|
||||
;
|
||||
|
||||
expr
|
||||
: expr_ternary { $$ = std::move($1); }
|
||||
| expr_binary { $$ = std::move($1); }
|
||||
| expr_primitive { $$ = std::move($1); }
|
||||
;
|
||||
|
||||
expr_or_empty
|
||||
: expr { $$ = std::move($1); }
|
||||
| { $$.as_node = std::make_unique<ast::node>(@$); }
|
||||
;
|
||||
|
||||
expr_assign
|
||||
: expr_tuple ASSIGN expr
|
||||
{ $$.as_node = std::make_unique<ast::expr_assign_equal>(@$, std::move($1), std::move($3)); }
|
||||
| expr_object ASSIGN expr
|
||||
{ $$.as_node = std::make_unique<ast::expr_assign_equal>(@$, std::move($1), std::move($3)); }
|
||||
| expr_object ASSIGN_BW_OR expr
|
||||
{ $$.as_node = std::make_unique<ast::expr_assign_bitwise_or>(@$, std::move($1), std::move($3)); }
|
||||
| expr_object ASSIGN_BW_AND expr
|
||||
{ $$.as_node = std::make_unique<ast::expr_assign_bitwise_and>(@$, std::move($1), std::move($3)); }
|
||||
| expr_object ASSIGN_BW_EXOR expr
|
||||
{ $$.as_node = std::make_unique<ast::expr_assign_bitwise_exor>(@$, std::move($1), std::move($3)); }
|
||||
| expr_object ASSIGN_LSHIFT expr
|
||||
{ $$.as_node = std::make_unique<ast::expr_assign_shift_left>(@$, std::move($1),std::move( $3)); }
|
||||
| expr_object ASSIGN_RSHIFT expr
|
||||
{ $$.as_node = std::make_unique<ast::expr_assign_shift_right>(@$, std::move($1), std::move($3)); }
|
||||
| expr_object ASSIGN_ADD expr
|
||||
{ $$.as_node = std::make_unique<ast::expr_assign_add>(@$, std::move($1), std::move($3)); }
|
||||
| expr_object ASSIGN_SUB expr
|
||||
{ $$.as_node = std::make_unique<ast::expr_assign_sub>(@$, std::move($1), std::move($3)); }
|
||||
| expr_object ASSIGN_MUL expr
|
||||
{ $$.as_node = std::make_unique<ast::expr_assign_mul>(@$, std::move($1), std::move($3)); }
|
||||
| expr_object ASSIGN_DIV expr
|
||||
{ $$.as_node = std::make_unique<ast::expr_assign_div>(@$, std::move($1), std::move($3)); }
|
||||
| expr_object ASSIGN_MOD expr
|
||||
{ $$.as_node = std::make_unique<ast::expr_assign_mod>(@$, std::move($1), std::move($3)); }
|
||||
;
|
||||
|
||||
expr_increment
|
||||
: INCREMENT expr_object %prec PREINC
|
||||
{ $$.as_node = std::make_unique<ast::expr_increment>(@$, std::move($2), true); }
|
||||
| expr_object INCREMENT %prec POSTINC
|
||||
{ $$.as_node = std::make_unique<ast::expr_increment>(@$, std::move($1), false); }
|
||||
;
|
||||
|
||||
expr_decrement
|
||||
: DECREMENT expr_object %prec PREDEC
|
||||
{ $$.as_node = std::make_unique<ast::expr_decrement>(@$, std::move($2), true); }
|
||||
| expr_object DECREMENT %prec POSTDEC
|
||||
{ $$.as_node = std::make_unique<ast::expr_decrement>(@$, std::move($1), false); }
|
||||
;
|
||||
|
||||
expr_ternary
|
||||
: expr QMARK expr COLON expr %prec TERN
|
||||
{ $$.as_node = std::make_unique<ast::expr_ternary>(@$, std::move($1), std::move($3), std::move($5)); }
|
||||
;
|
||||
|
||||
expr_binary
|
||||
: expr OR expr
|
||||
{ $$.as_node = std::make_unique<ast::expr_or>(@$, std::move($1), std::move($3)); }
|
||||
| expr AND expr
|
||||
{ $$.as_node = std::make_unique<ast::expr_and>(@$, std::move($1), std::move($3)); }
|
||||
| expr EQUALITY expr
|
||||
{ $$.as_node = std::make_unique<ast::expr_equality>(@$, std::move($1), std::move($3)); }
|
||||
| expr INEQUALITY expr
|
||||
{ $$.as_node = std::make_unique<ast::expr_inequality>(@$, std::move($1), std::move($3)); }
|
||||
| expr LESS_EQUAL expr
|
||||
{ $$.as_node = std::make_unique<ast::expr_less_equal>(@$, std::move($1), std::move($3)); }
|
||||
| expr GREATER_EQUAL expr
|
||||
{ $$.as_node = std::make_unique<ast::expr_greater_equal>(@$, std::move($1), std::move($3)); }
|
||||
| expr LESS expr
|
||||
{ $$.as_node = std::make_unique<ast::expr_less>(@$, std::move($1), std::move($3)); }
|
||||
| expr GREATER expr
|
||||
{ $$.as_node = std::make_unique<ast::expr_greater>(@$, std::move($1), std::move($3)); }
|
||||
| expr BITWISE_OR expr
|
||||
{ $$.as_node = std::make_unique<ast::expr_bitwise_or>(@$, std::move($1), std::move($3)); }
|
||||
| expr BITWISE_AND expr
|
||||
{ $$.as_node = std::make_unique<ast::expr_bitwise_and>(@$, std::move($1), std::move($3)); }
|
||||
| expr BITWISE_EXOR expr
|
||||
{ $$.as_node = std::make_unique<ast::expr_bitwise_exor>(@$, std::move($1), std::move($3)); }
|
||||
| expr LSHIFT expr
|
||||
{ $$.as_node = std::make_unique<ast::expr_shift_left>(@$, std::move($1), std::move($3)); }
|
||||
| expr RSHIFT expr
|
||||
{ $$.as_node = std::make_unique<ast::expr_shift_right>(@$, std::move($1), std::move($3)); }
|
||||
| expr ADD expr
|
||||
{ $$.as_node = std::make_unique<ast::expr_add>(@$, std::move($1), std::move($3)); }
|
||||
| expr SUB expr
|
||||
{ $$.as_node = std::make_unique<ast::expr_sub>(@$, std::move($1), std::move($3)); }
|
||||
| expr MUL expr
|
||||
{ $$.as_node = std::make_unique<ast::expr_mul>(@$, std::move($1), std::move($3)); }
|
||||
| expr DIV expr
|
||||
{ $$.as_node = std::make_unique<ast::expr_div>(@$, std::move($1), std::move($3)); }
|
||||
| expr MOD expr
|
||||
{ $$.as_node = std::make_unique<ast::expr_mod>(@$, std::move($1), std::move($3)); }
|
||||
;
|
||||
|
||||
expr_primitive
|
||||
: expr_complement { $$.as_node = std::move($1); }
|
||||
| expr_negate { $$.as_node = std::move($1); }
|
||||
| expr_not { $$.as_node = std::move($1); }
|
||||
| expr_call { $$.as_node = std::move($1); }
|
||||
| expr_method { $$.as_node = std::move($1); }
|
||||
| expr_add_array { $$.as_node = std::move($1); }
|
||||
| expr_reference { $$.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); }
|
||||
| expr_paren { $$.as_node = std::move($1); }
|
||||
| expr_thisthread { $$.as_node = std::move($1); }
|
||||
| expr_empty_array { $$.as_node = std::move($1); }
|
||||
| expr_undefined { $$.as_node = std::move($1); }
|
||||
| expr_game { $$.as_node = std::move($1); }
|
||||
| expr_self { $$.as_node = std::move($1); }
|
||||
| expr_anim { $$.as_node = std::move($1); }
|
||||
| expr_level { $$.as_node = std::move($1); }
|
||||
| expr_animation { $$.as_node = std::move($1); }
|
||||
| expr_animtree { $$.as_node = std::move($1); }
|
||||
| expr_identifier { $$.as_node = std::move($1); }
|
||||
| expr_istring { $$.as_node = std::move($1); }
|
||||
| expr_string { $$.as_node = std::move($1); }
|
||||
| expr_vector { $$.as_node = std::move($1); }
|
||||
| expr_float { $$.as_node = std::move($1); }
|
||||
| expr_integer { $$.as_node = std::move($1); }
|
||||
| expr_false { $$.as_node = std::move($1); }
|
||||
| expr_true { $$.as_node = std::move($1); }
|
||||
;
|
||||
|
||||
expr_complement
|
||||
: COMPLEMENT expr
|
||||
{ $$ = std::make_unique<ast::expr_complement>(@$, std::move($2)); }
|
||||
;
|
||||
|
||||
expr_negate
|
||||
: SUB expr_identifier %prec NEG
|
||||
{ $$ = std::make_unique<ast::expr_negate>(@$, ast::expr(std::move($2))); }
|
||||
| SUB expr_paren %prec NEG
|
||||
{ $$ = std::make_unique<ast::expr_negate>(@$, ast::expr(std::move($2))); }
|
||||
| SUB expr_array %prec NEG
|
||||
{ $$ = std::make_unique<ast::expr_negate>(@$, ast::expr(std::move($2))); }
|
||||
| SUB expr_field %prec NEG
|
||||
{ $$ = std::make_unique<ast::expr_negate>(@$, ast::expr(std::move($2))); }
|
||||
;
|
||||
|
||||
expr_not
|
||||
: NOT expr
|
||||
{ $$ = std::make_unique<ast::expr_not>(@$, std::move($2)); }
|
||||
;
|
||||
|
||||
expr_call
|
||||
: expr_function { $$ = std::make_unique<ast::expr_call>(@$, std::move($1)); }
|
||||
| expr_pointer { $$ = std::make_unique<ast::expr_call>(@$, std::move($1)); }
|
||||
;
|
||||
expr_method
|
||||
: expr_object expr_function { $$ = std::make_unique<ast::expr_method>(@$, std::move($1), std::move($2)); }
|
||||
| expr_object expr_pointer { $$ = std::make_unique<ast::expr_method>(@$, std::move($1), std::move($2)); }
|
||||
;
|
||||
|
||||
expr_function
|
||||
: expr_identifier LPAREN expr_arguments RPAREN
|
||||
{ $$.as_function = std::make_unique<ast::expr_function>(@$, std::make_unique<ast::expr_path>(@$), std::move($1), std::move($3), ast::call::mode::normal); }
|
||||
| expr_path DOUBLECOLON expr_identifier LPAREN expr_arguments RPAREN
|
||||
{ $$.as_function = std::make_unique<ast::expr_function>(@$, std::move($1), std::move($3), std::move($5), ast::call::mode::normal); }
|
||||
| THREAD expr_identifier LPAREN expr_arguments RPAREN
|
||||
{ $$.as_function = std::make_unique<ast::expr_function>(@$, std::make_unique<ast::expr_path>(@$), std::move($2), std::move($4), ast::call::mode::thread); }
|
||||
| THREAD expr_path DOUBLECOLON expr_identifier LPAREN expr_arguments RPAREN
|
||||
{ $$.as_function = std::make_unique<ast::expr_function>(@$, std::move($2), std::move($4), std::move($6), ast::call::mode::thread); }
|
||||
| CHILDTHREAD expr_identifier LPAREN expr_arguments RPAREN
|
||||
{ $$.as_function = std::make_unique<ast::expr_function>(@$, std::make_unique<ast::expr_path>(@$), std::move($2), std::move($4), ast::call::mode::childthread); }
|
||||
| CHILDTHREAD expr_path DOUBLECOLON expr_identifier LPAREN expr_arguments RPAREN
|
||||
{ $$.as_function = std::make_unique<ast::expr_function>(@$, std::move($2), std::move($4), std::move($6), ast::call::mode::childthread); }
|
||||
;
|
||||
|
||||
expr_pointer
|
||||
: LBRACKET LBRACKET expr RBRACKET RBRACKET LPAREN expr_arguments RPAREN
|
||||
{ $$.as_pointer = std::make_unique<ast::expr_pointer>(@$, std::move($3), std::move($7), ast::call::mode::normal); }
|
||||
| THREAD LBRACKET LBRACKET expr RBRACKET RBRACKET LPAREN expr_arguments RPAREN
|
||||
{ $$.as_pointer = std::make_unique<ast::expr_pointer>(@$, std::move($4), std::move($8), ast::call::mode::thread); }
|
||||
| CHILDTHREAD LBRACKET LBRACKET expr RBRACKET RBRACKET LPAREN expr_arguments RPAREN
|
||||
{ $$.as_pointer = std::make_unique<ast::expr_pointer>(@$, std::move($4), std::move($8), ast::call::mode::childthread); }
|
||||
| CALL LBRACKET LBRACKET expr RBRACKET RBRACKET LPAREN expr_arguments RPAREN
|
||||
{ $$.as_pointer = std::make_unique<ast::expr_pointer>(@$, std::move($4), std::move($8), ast::call::mode::builtin); }
|
||||
;
|
||||
|
||||
expr_add_array
|
||||
: LBRACKET expr_arguments_no_empty RBRACKET
|
||||
{ $$ = std::make_unique<ast::expr_add_array>(@$, std::move($2)); }
|
||||
;
|
||||
|
||||
expr_parameters
|
||||
: expr_parameters COMMA expr_identifier
|
||||
{ $$ = std::move($1); $$->list.push_back(std::move($3)); }
|
||||
| expr_identifier
|
||||
{ $$ = std::make_unique<ast::expr_parameters>(@$); $$->list.push_back(std::move($1)); }
|
||||
|
|
||||
{ $$ = std::make_unique<ast::expr_parameters>(@$); }
|
||||
;
|
||||
|
||||
expr_arguments
|
||||
: expr_arguments_no_empty
|
||||
{ $$ = std::move($1); }
|
||||
|
|
||||
{ $$ = std::make_unique<ast::expr_arguments>(@$); }
|
||||
;
|
||||
|
||||
expr_arguments_no_empty
|
||||
: expr_arguments COMMA expr
|
||||
{ $$ = std::move($1); $$->list.push_back(std::move($3)); }
|
||||
| expr %prec ADD_ARRAY
|
||||
{ $$ = std::make_unique<ast::expr_arguments>(@$); $$->list.push_back(std::move($1)); }
|
||||
;
|
||||
|
||||
expr_reference
|
||||
: DOUBLECOLON expr_identifier
|
||||
{ $$ = std::make_unique<ast::expr_reference>(@$, std::make_unique<ast::expr_path>(@$), std::move($2)); }
|
||||
| expr_path DOUBLECOLON expr_identifier
|
||||
{ $$ = std::make_unique<ast::expr_reference>(@$, std::move($1), std::move($3)); }
|
||||
;
|
||||
|
||||
expr_tuple
|
||||
: LBRACKET expr_tuple_arguments RBRACKET
|
||||
{ $$.as_node = std::move($2); }
|
||||
;
|
||||
|
||||
expr_tuple_arguments
|
||||
: expr_tuple_arguments COMMA expr_tuple_types
|
||||
{ $$ = std::move($1); $$->list.push_back(std::move($3)); }
|
||||
| expr_tuple_types
|
||||
{ $$ = std::make_unique<ast::expr_tuple>(@$); $$->list.push_back(std::move($1)); }
|
||||
;
|
||||
|
||||
expr_tuple_types
|
||||
: expr_array { $$.as_node = std::move($1); }
|
||||
| expr_field { $$.as_node = std::move($1); }
|
||||
| expr_identifier { $$.as_node = std::move($1); }
|
||||
;
|
||||
|
||||
expr_array
|
||||
: expr_object LBRACKET expr RBRACKET
|
||||
{ $$ = std::make_unique<ast::expr_array>(@$, std::move($1), std::move($3)); }
|
||||
;
|
||||
|
||||
expr_field
|
||||
: expr_object DOT expr_identifier_nosize
|
||||
{ $$ = std::make_unique<ast::expr_field>(@$, std::move($1), std::move($3)); }
|
||||
;
|
||||
|
||||
expr_size
|
||||
: expr_object DOT SIZE %prec SIZEOF
|
||||
{ $$ = std::make_unique<ast::expr_size>(@$, std::move($1)); }
|
||||
;
|
||||
|
||||
expr_paren
|
||||
: LPAREN expr RPAREN
|
||||
{ $$ = std::make_unique<ast::expr_paren>(@$, std::move($2)); }
|
||||
;
|
||||
|
||||
expr_object
|
||||
: expr_call { $$.as_node = std::move($1); }
|
||||
| expr_method { $$.as_node = std::move($1); }
|
||||
| expr_array { $$.as_node = std::move($1); }
|
||||
| expr_field { $$.as_node = std::move($1); }
|
||||
| expr_game { $$.as_node = std::move($1); }
|
||||
| expr_self { $$.as_node = std::move($1); }
|
||||
| expr_anim { $$.as_node = std::move($1); }
|
||||
| expr_level { $$.as_node = std::move($1); }
|
||||
| expr_identifier { $$.as_node = std::move($1); }
|
||||
;
|
||||
|
||||
expr_thisthread
|
||||
: THISTHREAD
|
||||
{ $$ = std::make_unique<ast::expr_thisthread>(@$); };
|
||||
;
|
||||
|
||||
expr_empty_array
|
||||
: LBRACKET RBRACKET
|
||||
{ $$ = std::make_unique<ast::expr_empty_array>(@$); };
|
||||
;
|
||||
|
||||
expr_undefined
|
||||
: UNDEFINED
|
||||
{ $$ = std::make_unique<ast::expr_undefined>(@$); };
|
||||
;
|
||||
|
||||
expr_game
|
||||
: GAME
|
||||
{ $$ = std::make_unique<ast::expr_game>(@$); };
|
||||
;
|
||||
|
||||
expr_self
|
||||
: SELF
|
||||
{ $$ = std::make_unique<ast::expr_self>(@$); };
|
||||
;
|
||||
|
||||
expr_anim
|
||||
: ANIM
|
||||
{ $$ = std::make_unique<ast::expr_anim>(@$); };
|
||||
;
|
||||
|
||||
expr_level
|
||||
: LEVEL
|
||||
{ $$ = std::make_unique<ast::expr_level>(@$); };
|
||||
;
|
||||
|
||||
expr_animation
|
||||
: MOD IDENTIFIER %prec ANIMREF
|
||||
{ $$ = std::make_unique<ast::expr_animation>(@$, $2); };
|
||||
;
|
||||
|
||||
expr_animtree
|
||||
: ANIMTREE
|
||||
{ $$ = std::make_unique<ast::expr_animtree>(@$); };
|
||||
;
|
||||
|
||||
expr_identifier_nosize
|
||||
: IDENTIFIER
|
||||
{ $$ = std::make_unique<ast::expr_identifier>(@$, $1); };
|
||||
;
|
||||
|
||||
expr_identifier
|
||||
: IDENTIFIER
|
||||
{ $$ = std::make_unique<ast::expr_identifier>(@$, $1); };
|
||||
| SIZE
|
||||
{ $$ = std::make_unique<ast::expr_identifier>(@$, "size"); };
|
||||
;
|
||||
|
||||
expr_path
|
||||
: IDENTIFIER
|
||||
{ $$ = std::make_unique<ast::expr_path>(@$, $1); };
|
||||
| PATH
|
||||
{ $$ = std::make_unique<ast::expr_path>(@$, $1); };
|
||||
;
|
||||
|
||||
expr_istring
|
||||
: ISTRING
|
||||
{ $$ = std::make_unique<ast::expr_istring>(@$, $1); };
|
||||
;
|
||||
|
||||
expr_string
|
||||
: STRING
|
||||
{ $$ = std::make_unique<ast::expr_string>(@$, $1); };
|
||||
;
|
||||
|
||||
expr_vector
|
||||
: LPAREN expr COMMA expr COMMA expr RPAREN
|
||||
{ $$ = std::make_unique<ast::expr_vector>(@$, std::move($2), std::move($4), std::move($6)); };
|
||||
;
|
||||
|
||||
expr_float
|
||||
: SUB FLOAT %prec NEG
|
||||
{ $$ = std::make_unique<ast::expr_float>(@$, "-" + $2); };
|
||||
| FLOAT
|
||||
{ $$ = std::make_unique<ast::expr_float>(@$, $1); };
|
||||
;
|
||||
|
||||
expr_integer
|
||||
: SUB INTEGER %prec NEG
|
||||
{ $$ = std::make_unique<ast::expr_integer>(@$, "-" + $2); };
|
||||
| INTEGER
|
||||
{ $$ = std::make_unique<ast::expr_integer>(@$, $1); };
|
||||
;
|
||||
|
||||
expr_false
|
||||
: FALSE
|
||||
{ $$ = std::make_unique<ast::expr_false>(@$); };
|
||||
;
|
||||
|
||||
expr_true
|
||||
: TRUE
|
||||
{ $$ = std::make_unique<ast::expr_true>(@$); };
|
||||
;
|
||||
|
||||
%%
|
||||
|
||||
void xsk::gsc::iw7::parser::error(const xsk::gsc::location& loc, const std::string& msg)
|
||||
{
|
||||
throw xsk::gsc::comp_error(loc, msg);
|
||||
}
|
@ -1,9 +0,0 @@
|
||||
generate: iw8
|
||||
|
||||
clean:
|
||||
rm -rf ./parser.hpp
|
||||
rm -rf ./parser.cpp
|
||||
|
||||
iw8: parser.ypp
|
||||
bison parser.ypp -Wcounterexamples
|
||||
mv parser.hpp parser.cpp ../../src/iw8/xsk/
|
@ -1,914 +0,0 @@
|
||||
/* Copyright 2022 xensik. All rights reserved.
|
||||
//
|
||||
// Use of this source code is governed by a GNU GPLv3 license
|
||||
// that can be found in the LICENSE file.
|
||||
*/
|
||||
|
||||
%require "3.7"
|
||||
%skeleton "lalr1.cc"
|
||||
%language "c++"
|
||||
%output "parser.cpp"
|
||||
%defines "parser.hpp"
|
||||
%define api.prefix {IW8}
|
||||
%define api.namespace {xsk::gsc::iw8}
|
||||
%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 { xsk::gsc::iw8::lexer& lexer }
|
||||
%parse-param { xsk::gsc::iw8::lexer& lexer }
|
||||
%parse-param { xsk::gsc::ast::program::ptr& ast }
|
||||
|
||||
%code requires
|
||||
{
|
||||
#ifdef _MSC_VER
|
||||
#pragma warning(disable:4065)
|
||||
#pragma warning(disable:4127)
|
||||
#endif
|
||||
#include "iw8.hpp"
|
||||
namespace xsk::gsc::iw8 { class lexer; }
|
||||
}
|
||||
|
||||
%code top
|
||||
{
|
||||
#include "stdafx.hpp"
|
||||
#include "parser.hpp"
|
||||
#include "lexer.hpp"
|
||||
using namespace xsk::gsc;
|
||||
xsk::gsc::iw8::parser::symbol_type IW8lex(xsk::gsc::iw8::lexer& lexer);
|
||||
}
|
||||
|
||||
%token SH_DEFINE "#define"
|
||||
%token SH_UNDEF "#undef"
|
||||
%token SH_IFDEF "#ifdef"
|
||||
%token SH_IFNDEF "#ifndef"
|
||||
%token SH_IF "#if"
|
||||
%token SH_ELIF "#elif"
|
||||
%token SH_ELSE "#else"
|
||||
%token SH_ENDIF "#endif"
|
||||
%token DEVBEGIN "/#"
|
||||
%token DEVEND "#/"
|
||||
%token INLINE "#inline"
|
||||
%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 DO "do"
|
||||
%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 BREAKPOINT "breakpoint"
|
||||
%token PROFBEGIN "prof_begin"
|
||||
%token PROFEND "prof_end"
|
||||
%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 ISDEFINED "isdefined"
|
||||
%token ISTRUE "istrue"
|
||||
%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_MUL "*="
|
||||
%token ASSIGN_DIV "/="
|
||||
%token ASSIGN_MOD "%="
|
||||
%token ASSIGN_BW_OR "|="
|
||||
%token ASSIGN_BW_AND "&="
|
||||
%token ASSIGN_BW_EXOR "^="
|
||||
%token ASSIGN_RSHIFT ">>="
|
||||
%token ASSIGN_LSHIFT "<<="
|
||||
%token BITWISE_OR "|"
|
||||
%token BITWISE_AND "&"
|
||||
%token BITWISE_EXOR "^"
|
||||
%token ADD "+"
|
||||
%token SUB "-"
|
||||
%token MUL "*"
|
||||
%token DIV "/"
|
||||
%token MOD "%"
|
||||
%token <std::string> PATH "path"
|
||||
%token <std::string> IDENTIFIER "identifier"
|
||||
%token <std::string> STRING "string literal"
|
||||
%token <std::string> ISTRING "localized string"
|
||||
%token <std::string> FLOAT "float"
|
||||
%token <std::string> INTEGER "integer"
|
||||
|
||||
%type <ast::program::ptr> program
|
||||
%type <ast::include::ptr> include
|
||||
%type <ast::decl> declaration
|
||||
%type <ast::decl_usingtree::ptr> decl_usingtree
|
||||
%type <ast::decl_constant::ptr> decl_constant
|
||||
%type <ast::decl_thread::ptr> decl_thread
|
||||
%type <ast::stmt> stmt
|
||||
%type <ast::stmt> stmt_or_dev
|
||||
%type <ast::stmt_list::ptr> stmt_list
|
||||
%type <ast::stmt_list::ptr> stmt_or_dev_list
|
||||
%type <ast::stmt_dev::ptr> stmt_dev
|
||||
%type <ast::stmt_list::ptr> stmt_block
|
||||
%type <ast::stmt_expr::ptr> stmt_expr
|
||||
%type <ast::stmt_call::ptr> stmt_call
|
||||
%type <ast::stmt_assign::ptr> stmt_assign
|
||||
%type <ast::stmt_endon::ptr> stmt_endon
|
||||
%type <ast::stmt_notify::ptr> stmt_notify
|
||||
%type <ast::stmt_wait::ptr> stmt_wait
|
||||
%type <ast::stmt_waittill::ptr> stmt_waittill
|
||||
%type <ast::stmt_waittillmatch::ptr> stmt_waittillmatch
|
||||
%type <ast::stmt_waittillframeend::ptr> stmt_waittillframeend
|
||||
%type <ast::stmt_waitframe::ptr> stmt_waitframe
|
||||
%type <ast::stmt_if::ptr> stmt_if
|
||||
%type <ast::stmt_ifelse::ptr> stmt_ifelse
|
||||
%type <ast::stmt_while::ptr> stmt_while
|
||||
%type <ast::stmt_dowhile::ptr> stmt_dowhile
|
||||
%type <ast::stmt_for::ptr> stmt_for
|
||||
%type <ast::stmt_foreach::ptr> stmt_foreach
|
||||
%type <ast::stmt_switch::ptr> stmt_switch
|
||||
%type <ast::stmt_case::ptr> stmt_case
|
||||
%type <ast::stmt_default::ptr> stmt_default
|
||||
%type <ast::stmt_break::ptr> stmt_break
|
||||
%type <ast::stmt_continue::ptr> stmt_continue
|
||||
%type <ast::stmt_return::ptr> stmt_return
|
||||
%type <ast::stmt_breakpoint::ptr> stmt_breakpoint
|
||||
%type <ast::stmt_prof_begin::ptr> stmt_prof_begin
|
||||
%type <ast::stmt_prof_end::ptr> stmt_prof_end
|
||||
%type <ast::expr> expr
|
||||
%type <ast::expr> expr_or_empty
|
||||
%type <ast::expr> expr_assign
|
||||
%type <ast::expr> expr_increment
|
||||
%type <ast::expr> expr_decrement
|
||||
%type <ast::expr> expr_ternary
|
||||
%type <ast::expr> expr_binary
|
||||
%type <ast::expr> expr_primitive
|
||||
%type <ast::expr_complement::ptr> expr_complement
|
||||
%type <ast::expr_negate::ptr> expr_negate
|
||||
%type <ast::expr_not::ptr> expr_not
|
||||
%type <ast::expr_call::ptr> expr_call
|
||||
%type <ast::expr_method::ptr> expr_method
|
||||
%type <ast::call> expr_function
|
||||
%type <ast::call> expr_pointer
|
||||
%type <ast::expr_add_array::ptr> expr_add_array
|
||||
%type <ast::expr_parameters::ptr> expr_parameters
|
||||
%type <ast::expr_arguments::ptr> expr_arguments
|
||||
%type <ast::expr_arguments::ptr> expr_arguments_no_empty
|
||||
%type <ast::expr_isdefined::ptr> expr_isdefined
|
||||
%type <ast::expr_istrue::ptr> expr_istrue
|
||||
%type <ast::expr_reference::ptr> expr_reference
|
||||
%type <ast::expr> expr_tuple
|
||||
%type <ast::expr_tuple::ptr> expr_tuple_arguments
|
||||
%type <ast::expr> expr_tuple_types
|
||||
%type <ast::expr_array::ptr> expr_array
|
||||
%type <ast::expr_field::ptr> expr_field
|
||||
%type <ast::expr_size::ptr> expr_size
|
||||
%type <ast::expr_paren::ptr> expr_paren
|
||||
%type <ast::expr> expr_object
|
||||
%type <ast::expr_thisthread::ptr> expr_thisthread
|
||||
%type <ast::expr_empty_array::ptr> expr_empty_array
|
||||
%type <ast::expr_undefined::ptr> expr_undefined
|
||||
%type <ast::expr_game::ptr> expr_game
|
||||
%type <ast::expr_self::ptr> expr_self
|
||||
%type <ast::expr_anim::ptr> expr_anim
|
||||
%type <ast::expr_level::ptr> expr_level
|
||||
%type <ast::expr_animation::ptr> expr_animation
|
||||
%type <ast::expr_animtree::ptr> expr_animtree
|
||||
%type <ast::expr_identifier::ptr> expr_identifier_nosize
|
||||
%type <ast::expr_identifier::ptr> expr_identifier
|
||||
%type <ast::expr_path::ptr> expr_path
|
||||
%type <ast::expr_istring::ptr> expr_istring
|
||||
%type <ast::expr_string::ptr> expr_string
|
||||
%type <ast::expr_vector::ptr> expr_vector
|
||||
%type <ast::expr_float::ptr> expr_float
|
||||
%type <ast::expr_integer::ptr> expr_integer
|
||||
%type <ast::expr_false::ptr> expr_false
|
||||
%type <ast::expr_true::ptr> expr_true
|
||||
|
||||
%nonassoc SIZEOF
|
||||
%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_EXOR
|
||||
%left BITWISE_AND
|
||||
%left EQUALITY INEQUALITY
|
||||
%left LESS GREATER LESS_EQUAL GREATER_EQUAL
|
||||
%left LSHIFT RSHIFT
|
||||
%left ADD SUB
|
||||
%left MUL 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<ast::program>(@$); }
|
||||
;
|
||||
|
||||
program
|
||||
: program inline
|
||||
{ $$ = std::move($1); }
|
||||
| program include
|
||||
{ $$ = std::move($1); $$->includes.push_back(std::move($2)); }
|
||||
| program declaration
|
||||
{ $$ = std::move($1); $$->declarations.push_back(std::move($2)); }
|
||||
| inline
|
||||
{ $$ = std::make_unique<ast::program>(@$); }
|
||||
| include
|
||||
{ $$ = std::make_unique<ast::program>(@$); $$->includes.push_back(std::move($1)); }
|
||||
| declaration
|
||||
{ $$ = std::make_unique<ast::program>(@$); $$->declarations.push_back(std::move($1)); }
|
||||
;
|
||||
|
||||
inline
|
||||
: INLINE expr_path SEMICOLON { lexer.push_header($2->value); }
|
||||
;
|
||||
|
||||
include
|
||||
: INCLUDE expr_path SEMICOLON
|
||||
{ $$ = std::make_unique<ast::include>(@$, std::move($2)); }
|
||||
;
|
||||
|
||||
declaration
|
||||
: DEVBEGIN { $$.as_dev_begin = std::make_unique<ast::decl_dev_begin>(@$); }
|
||||
| DEVEND { $$.as_dev_end = std::make_unique<ast::decl_dev_end>(@$); }
|
||||
| decl_usingtree { $$.as_usingtree = std::move($1); }
|
||||
| decl_constant { $$.as_constant = std::move($1); }
|
||||
| decl_thread { $$.as_thread = std::move($1); }
|
||||
;
|
||||
|
||||
decl_usingtree
|
||||
: USINGTREE LPAREN expr_string RPAREN SEMICOLON
|
||||
{ lexer.ban_header(@$); $$ = std::make_unique<ast::decl_usingtree>(@$, std::move($3)); }
|
||||
;
|
||||
|
||||
decl_constant
|
||||
: expr_identifier ASSIGN expr SEMICOLON
|
||||
{ $$ = std::make_unique<ast::decl_constant>(@$, std::move($1), std::move($3)); }
|
||||
;
|
||||
|
||||
decl_thread
|
||||
: expr_identifier LPAREN expr_parameters RPAREN stmt_block
|
||||
{ lexer.ban_header(@$); $$ = std::make_unique<ast::decl_thread>(@$, std::move($1), std::move($3), std::move($5)); }
|
||||
;
|
||||
|
||||
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_dowhile { $$.as_dowhile = 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_breakpoint { $$.as_breakpoint = std::move($1); }
|
||||
| stmt_prof_begin { $$.as_prof_begin = std::move($1); }
|
||||
| stmt_prof_end { $$.as_prof_end = std::move($1); }
|
||||
;
|
||||
|
||||
stmt_or_dev
|
||||
: stmt { $$ = std::move($1); }
|
||||
| stmt_dev { $$.as_dev = std::move($1); }
|
||||
;
|
||||
|
||||
stmt_list
|
||||
: stmt_list stmt
|
||||
{ $$ = std::move($1); $$->list.push_back(std::move($2)); }
|
||||
| stmt
|
||||
{ $$ = std::make_unique<ast::stmt_list>(@$); $$->list.push_back(std::move($1)); }
|
||||
;
|
||||
|
||||
stmt_or_dev_list
|
||||
: stmt_or_dev_list stmt_or_dev
|
||||
{ $$ = std::move($1); $$->list.push_back(std::move($2)); }
|
||||
| stmt_or_dev
|
||||
{ $$ = std::make_unique<ast::stmt_list>(@$); $$->list.push_back(std::move($1)); }
|
||||
;
|
||||
|
||||
stmt_dev
|
||||
: DEVBEGIN stmt_list DEVEND { $$ = std::make_unique<ast::stmt_dev>(@$, std::move($2)); }
|
||||
| DEVBEGIN DEVEND { $$ = std::make_unique<ast::stmt_dev>(@$, std::make_unique<ast::stmt_list>(@$)); }
|
||||
;
|
||||
|
||||
stmt_block
|
||||
: LBRACE stmt_or_dev_list RBRACE { $$ = std::move($2); }
|
||||
| LBRACE RBRACE { $$ = std::make_unique<ast::stmt_list>(@$); }
|
||||
;
|
||||
|
||||
stmt_expr
|
||||
: expr_assign
|
||||
{ $$ = std::make_unique<ast::stmt_expr>(@$, std::move($1)); }
|
||||
| expr_increment
|
||||
{ $$ = std::make_unique<ast::stmt_expr>(@$, std::move($1)); }
|
||||
| expr_decrement
|
||||
{ $$ = std::make_unique<ast::stmt_expr>(@$, std::move($1)); }
|
||||
|
|
||||
{ $$ = std::make_unique<ast::stmt_expr>(@$, std::make_unique<ast::node>(@$)); }
|
||||
;
|
||||
|
||||
stmt_call
|
||||
: expr_call SEMICOLON
|
||||
{ $$ = std::make_unique<ast::stmt_call>(@$, ast::expr(std::move($1))); }
|
||||
| expr_method SEMICOLON
|
||||
{ $$ = std::make_unique<ast::stmt_call>(@$, ast::expr(std::move($1))); }
|
||||
;
|
||||
|
||||
stmt_assign
|
||||
: expr_assign SEMICOLON
|
||||
{ $$ = std::make_unique<ast::stmt_assign>(@$, std::move($1)); }
|
||||
| expr_increment SEMICOLON
|
||||
{ $$ = std::make_unique<ast::stmt_assign>(@$, std::move($1)); }
|
||||
| expr_decrement SEMICOLON
|
||||
{ $$ = std::make_unique<ast::stmt_assign>(@$, std::move($1)); }
|
||||
;
|
||||
|
||||
stmt_endon
|
||||
: expr_object ENDON LPAREN expr RPAREN SEMICOLON
|
||||
{ $$ = std::make_unique<ast::stmt_endon>(@$, std::move($1), std::move($4)); }
|
||||
;
|
||||
|
||||
stmt_notify
|
||||
: expr_object NOTIFY LPAREN expr COMMA expr_arguments_no_empty RPAREN SEMICOLON
|
||||
{ $$ = std::make_unique<ast::stmt_notify>(@$, std::move($1), std::move($4), std::move($6)); }
|
||||
| expr_object NOTIFY LPAREN expr RPAREN SEMICOLON
|
||||
{ $$ = std::make_unique<ast::stmt_notify>(@$, std::move($1), std::move($4), std::make_unique<ast::expr_arguments>(@$)); }
|
||||
;
|
||||
|
||||
stmt_wait
|
||||
: WAIT expr SEMICOLON
|
||||
{ $$ = std::make_unique<ast::stmt_wait>(@$, std::move($2)); }
|
||||
;
|
||||
|
||||
stmt_waittill
|
||||
: expr_object WAITTILL LPAREN expr COMMA expr_arguments_no_empty RPAREN SEMICOLON
|
||||
{ $$ = std::make_unique<ast::stmt_waittill>(@$, std::move($1), std::move($4), std::move($6)); }
|
||||
| expr_object WAITTILL LPAREN expr RPAREN SEMICOLON
|
||||
{ $$ = std::make_unique<ast::stmt_waittill>(@$, std::move($1), std::move($4), std::make_unique<ast::expr_arguments>(@$)); }
|
||||
;
|
||||
|
||||
stmt_waittillmatch
|
||||
: expr_object WAITTILLMATCH LPAREN expr COMMA expr_arguments_no_empty RPAREN SEMICOLON
|
||||
{ $$ = std::make_unique<ast::stmt_waittillmatch>(@$, std::move($1), std::move($4), std::move($6)); }
|
||||
| expr_object WAITTILLMATCH LPAREN expr RPAREN SEMICOLON
|
||||
{ $$ = std::make_unique<ast::stmt_waittillmatch>(@$, std::move($1), std::move($4), std::make_unique<ast::expr_arguments>(@$)); }
|
||||
;
|
||||
|
||||
stmt_waittillframeend
|
||||
: WAITTILLFRAMEEND SEMICOLON
|
||||
{ $$ = std::make_unique<ast::stmt_waittillframeend>(@$); }
|
||||
;
|
||||
|
||||
stmt_waitframe
|
||||
: WAITFRAME SEMICOLON
|
||||
{ $$ = std::make_unique<ast::stmt_waitframe>(@$); }
|
||||
| WAITFRAME LPAREN RPAREN SEMICOLON
|
||||
{ $$ = std::make_unique<ast::stmt_waitframe>(@$); }
|
||||
;
|
||||
|
||||
stmt_if
|
||||
: IF LPAREN expr RPAREN stmt %prec THEN
|
||||
{ $$ = std::make_unique<ast::stmt_if>(@$, std::move($3), std::move($5)); }
|
||||
;
|
||||
|
||||
stmt_ifelse
|
||||
: IF LPAREN expr RPAREN stmt ELSE stmt
|
||||
{ $$ = std::make_unique<ast::stmt_ifelse>(@$, std::move($3), std::move($5), std::move($7)); }
|
||||
;
|
||||
|
||||
stmt_while
|
||||
: WHILE LPAREN expr RPAREN stmt
|
||||
{ $$ = std::make_unique<ast::stmt_while>(@$, std::move($3), std::move($5)); }
|
||||
;
|
||||
|
||||
stmt_dowhile
|
||||
: DO stmt WHILE LPAREN expr RPAREN SEMICOLON
|
||||
{ $$ = std::make_unique<ast::stmt_dowhile>(@$, std::move($5), std::move($2)); }
|
||||
;
|
||||
|
||||
stmt_for
|
||||
: FOR LPAREN stmt_expr SEMICOLON expr_or_empty SEMICOLON stmt_expr RPAREN stmt
|
||||
{ $$ = std::make_unique<ast::stmt_for>(@$, ast::stmt(std::move($3)), std::move($5), ast::stmt(std::move($7)), std::move($9)); }
|
||||
;
|
||||
|
||||
stmt_foreach
|
||||
: FOREACH LPAREN expr_identifier IN expr RPAREN stmt
|
||||
{ $$ = std::make_unique<ast::stmt_foreach>(@$, ast::expr(std::move($3)), std::move($5), std::move($7)); }
|
||||
| FOREACH LPAREN expr_identifier COMMA expr_identifier IN expr RPAREN stmt
|
||||
{ $$ = std::make_unique<ast::stmt_foreach>(@$, ast::expr(std::move($3)), ast::expr(std::move($5)), std::move($7), std::move($9)); }
|
||||
;
|
||||
|
||||
stmt_switch
|
||||
: SWITCH LPAREN expr RPAREN stmt_block
|
||||
{ $$ = std::make_unique<ast::stmt_switch>(@$, std::move($3), std::move($5)); }
|
||||
;
|
||||
|
||||
stmt_case
|
||||
: CASE expr_integer COLON
|
||||
{ $$ = std::make_unique<ast::stmt_case>(@$, ast::expr(std::move($2)), std::make_unique<ast::stmt_list>(@$)); }
|
||||
| CASE expr_string COLON
|
||||
{ $$ = std::make_unique<ast::stmt_case>(@$, ast::expr(std::move($2)), std::make_unique<ast::stmt_list>(@$)); }
|
||||
;
|
||||
|
||||
stmt_default
|
||||
: DEFAULT COLON
|
||||
{ $$ = std::make_unique<ast::stmt_default>(@$, std::make_unique<ast::stmt_list>(@$)); }
|
||||
;
|
||||
|
||||
stmt_break
|
||||
: BREAK SEMICOLON
|
||||
{ $$ = std::make_unique<ast::stmt_break>(@$); }
|
||||
;
|
||||
|
||||
stmt_continue
|
||||
: CONTINUE SEMICOLON
|
||||
{ $$ = std::make_unique<ast::stmt_continue>(@$); }
|
||||
;
|
||||
|
||||
stmt_return
|
||||
: RETURN expr SEMICOLON
|
||||
{ $$ = std::make_unique<ast::stmt_return>(@$, std::move($2)); }
|
||||
| RETURN SEMICOLON
|
||||
{ $$ = std::make_unique<ast::stmt_return>(@$, std::make_unique<ast::node>(@$)); }
|
||||
;
|
||||
|
||||
stmt_breakpoint
|
||||
: BREAKPOINT SEMICOLON
|
||||
{ $$ = std::make_unique<ast::stmt_breakpoint>(@$); }
|
||||
;
|
||||
|
||||
stmt_prof_begin
|
||||
: PROFBEGIN LPAREN expr_arguments RPAREN SEMICOLON
|
||||
{ $$ = std::make_unique<ast::stmt_prof_begin>(@$, std::move($3)); }
|
||||
;
|
||||
|
||||
stmt_prof_end
|
||||
: PROFEND LPAREN expr_arguments RPAREN SEMICOLON
|
||||
{ $$ = std::make_unique<ast::stmt_prof_end>(@$, std::move($3)); }
|
||||
;
|
||||
|
||||
expr
|
||||
: expr_ternary { $$ = std::move($1); }
|
||||
| expr_binary { $$ = std::move($1); }
|
||||
| expr_primitive { $$ = std::move($1); }
|
||||
;
|
||||
|
||||
expr_or_empty
|
||||
: expr { $$ = std::move($1); }
|
||||
| { $$.as_node = std::make_unique<ast::node>(@$); }
|
||||
;
|
||||
|
||||
expr_assign
|
||||
: expr_tuple ASSIGN expr
|
||||
{ $$.as_node = std::make_unique<ast::expr_assign_equal>(@$, std::move($1), std::move($3)); }
|
||||
| expr_object ASSIGN expr
|
||||
{ $$.as_node = std::make_unique<ast::expr_assign_equal>(@$, std::move($1), std::move($3)); }
|
||||
| expr_object ASSIGN_BW_OR expr
|
||||
{ $$.as_node = std::make_unique<ast::expr_assign_bitwise_or>(@$, std::move($1), std::move($3)); }
|
||||
| expr_object ASSIGN_BW_AND expr
|
||||
{ $$.as_node = std::make_unique<ast::expr_assign_bitwise_and>(@$, std::move($1), std::move($3)); }
|
||||
| expr_object ASSIGN_BW_EXOR expr
|
||||
{ $$.as_node = std::make_unique<ast::expr_assign_bitwise_exor>(@$, std::move($1), std::move($3)); }
|
||||
| expr_object ASSIGN_LSHIFT expr
|
||||
{ $$.as_node = std::make_unique<ast::expr_assign_shift_left>(@$, std::move($1),std::move( $3)); }
|
||||
| expr_object ASSIGN_RSHIFT expr
|
||||
{ $$.as_node = std::make_unique<ast::expr_assign_shift_right>(@$, std::move($1), std::move($3)); }
|
||||
| expr_object ASSIGN_ADD expr
|
||||
{ $$.as_node = std::make_unique<ast::expr_assign_add>(@$, std::move($1), std::move($3)); }
|
||||
| expr_object ASSIGN_SUB expr
|
||||
{ $$.as_node = std::make_unique<ast::expr_assign_sub>(@$, std::move($1), std::move($3)); }
|
||||
| expr_object ASSIGN_MUL expr
|
||||
{ $$.as_node = std::make_unique<ast::expr_assign_mul>(@$, std::move($1), std::move($3)); }
|
||||
| expr_object ASSIGN_DIV expr
|
||||
{ $$.as_node = std::make_unique<ast::expr_assign_div>(@$, std::move($1), std::move($3)); }
|
||||
| expr_object ASSIGN_MOD expr
|
||||
{ $$.as_node = std::make_unique<ast::expr_assign_mod>(@$, std::move($1), std::move($3)); }
|
||||
;
|
||||
|
||||
expr_increment
|
||||
: INCREMENT expr_object %prec PREINC
|
||||
{ $$.as_node = std::make_unique<ast::expr_increment>(@$, std::move($2), true); }
|
||||
| expr_object INCREMENT %prec POSTINC
|
||||
{ $$.as_node = std::make_unique<ast::expr_increment>(@$, std::move($1), false); }
|
||||
;
|
||||
|
||||
expr_decrement
|
||||
: DECREMENT expr_object %prec PREDEC
|
||||
{ $$.as_node = std::make_unique<ast::expr_decrement>(@$, std::move($2), true); }
|
||||
| expr_object DECREMENT %prec POSTDEC
|
||||
{ $$.as_node = std::make_unique<ast::expr_decrement>(@$, std::move($1), false); }
|
||||
;
|
||||
|
||||
expr_ternary
|
||||
: expr QMARK expr COLON expr %prec TERN
|
||||
{ $$.as_node = std::make_unique<ast::expr_ternary>(@$, std::move($1), std::move($3), std::move($5)); }
|
||||
;
|
||||
|
||||
expr_binary
|
||||
: expr OR expr
|
||||
{ $$.as_node = std::make_unique<ast::expr_or>(@$, std::move($1), std::move($3)); }
|
||||
| expr AND expr
|
||||
{ $$.as_node = std::make_unique<ast::expr_and>(@$, std::move($1), std::move($3)); }
|
||||
| expr EQUALITY expr
|
||||
{ $$.as_node = std::make_unique<ast::expr_equality>(@$, std::move($1), std::move($3)); }
|
||||
| expr INEQUALITY expr
|
||||
{ $$.as_node = std::make_unique<ast::expr_inequality>(@$, std::move($1), std::move($3)); }
|
||||
| expr LESS_EQUAL expr
|
||||
{ $$.as_node = std::make_unique<ast::expr_less_equal>(@$, std::move($1), std::move($3)); }
|
||||
| expr GREATER_EQUAL expr
|
||||
{ $$.as_node = std::make_unique<ast::expr_greater_equal>(@$, std::move($1), std::move($3)); }
|
||||
| expr LESS expr
|
||||
{ $$.as_node = std::make_unique<ast::expr_less>(@$, std::move($1), std::move($3)); }
|
||||
| expr GREATER expr
|
||||
{ $$.as_node = std::make_unique<ast::expr_greater>(@$, std::move($1), std::move($3)); }
|
||||
| expr BITWISE_OR expr
|
||||
{ $$.as_node = std::make_unique<ast::expr_bitwise_or>(@$, std::move($1), std::move($3)); }
|
||||
| expr BITWISE_AND expr
|
||||
{ $$.as_node = std::make_unique<ast::expr_bitwise_and>(@$, std::move($1), std::move($3)); }
|
||||
| expr BITWISE_EXOR expr
|
||||
{ $$.as_node = std::make_unique<ast::expr_bitwise_exor>(@$, std::move($1), std::move($3)); }
|
||||
| expr LSHIFT expr
|
||||
{ $$.as_node = std::make_unique<ast::expr_shift_left>(@$, std::move($1), std::move($3)); }
|
||||
| expr RSHIFT expr
|
||||
{ $$.as_node = std::make_unique<ast::expr_shift_right>(@$, std::move($1), std::move($3)); }
|
||||
| expr ADD expr
|
||||
{ $$.as_node = std::make_unique<ast::expr_add>(@$, std::move($1), std::move($3)); }
|
||||
| expr SUB expr
|
||||
{ $$.as_node = std::make_unique<ast::expr_sub>(@$, std::move($1), std::move($3)); }
|
||||
| expr MUL expr
|
||||
{ $$.as_node = std::make_unique<ast::expr_mul>(@$, std::move($1), std::move($3)); }
|
||||
| expr DIV expr
|
||||
{ $$.as_node = std::make_unique<ast::expr_div>(@$, std::move($1), std::move($3)); }
|
||||
| expr MOD expr
|
||||
{ $$.as_node = std::make_unique<ast::expr_mod>(@$, std::move($1), std::move($3)); }
|
||||
;
|
||||
|
||||
expr_primitive
|
||||
: expr_complement { $$.as_node = std::move($1); }
|
||||
| expr_negate { $$.as_node = std::move($1); }
|
||||
| expr_not { $$.as_node = std::move($1); }
|
||||
| expr_call { $$.as_node = std::move($1); }
|
||||
| expr_method { $$.as_node = std::move($1); }
|
||||
| expr_add_array { $$.as_node = std::move($1); }
|
||||
| expr_isdefined { $$.as_node = std::move($1); }
|
||||
| expr_istrue { $$.as_node = std::move($1); }
|
||||
| expr_reference { $$.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); }
|
||||
| expr_paren { $$.as_node = std::move($1); }
|
||||
| expr_thisthread { $$.as_node = std::move($1); }
|
||||
| expr_empty_array { $$.as_node = std::move($1); }
|
||||
| expr_undefined { $$.as_node = std::move($1); }
|
||||
| expr_game { $$.as_node = std::move($1); }
|
||||
| expr_self { $$.as_node = std::move($1); }
|
||||
| expr_anim { $$.as_node = std::move($1); }
|
||||
| expr_level { $$.as_node = std::move($1); }
|
||||
| expr_animation { $$.as_node = std::move($1); }
|
||||
| expr_animtree { $$.as_node = std::move($1); }
|
||||
| expr_identifier { $$.as_node = std::move($1); }
|
||||
| expr_istring { $$.as_node = std::move($1); }
|
||||
| expr_string { $$.as_node = std::move($1); }
|
||||
| expr_vector { $$.as_node = std::move($1); }
|
||||
| expr_float { $$.as_node = std::move($1); }
|
||||
| expr_integer { $$.as_node = std::move($1); }
|
||||
| expr_false { $$.as_node = std::move($1); }
|
||||
| expr_true { $$.as_node = std::move($1); }
|
||||
;
|
||||
|
||||
expr_complement
|
||||
: COMPLEMENT expr
|
||||
{ $$ = std::make_unique<ast::expr_complement>(@$, std::move($2)); }
|
||||
;
|
||||
|
||||
expr_negate
|
||||
: SUB expr_identifier %prec NEG
|
||||
{ $$ = std::make_unique<ast::expr_negate>(@$, ast::expr(std::move($2))); }
|
||||
| SUB expr_paren %prec NEG
|
||||
{ $$ = std::make_unique<ast::expr_negate>(@$, ast::expr(std::move($2))); }
|
||||
| SUB expr_array %prec NEG
|
||||
{ $$ = std::make_unique<ast::expr_negate>(@$, ast::expr(std::move($2))); }
|
||||
| SUB expr_field %prec NEG
|
||||
{ $$ = std::make_unique<ast::expr_negate>(@$, ast::expr(std::move($2))); }
|
||||
;
|
||||
|
||||
expr_not
|
||||
: NOT expr
|
||||
{ $$ = std::make_unique<ast::expr_not>(@$, std::move($2)); }
|
||||
;
|
||||
|
||||
expr_call
|
||||
: expr_function { $$ = std::make_unique<ast::expr_call>(@$, std::move($1)); }
|
||||
| expr_pointer { $$ = std::make_unique<ast::expr_call>(@$, std::move($1)); }
|
||||
;
|
||||
expr_method
|
||||
: expr_object expr_function { $$ = std::make_unique<ast::expr_method>(@$, std::move($1), std::move($2)); }
|
||||
| expr_object expr_pointer { $$ = std::make_unique<ast::expr_method>(@$, std::move($1), std::move($2)); }
|
||||
;
|
||||
|
||||
expr_function
|
||||
: expr_identifier LPAREN expr_arguments RPAREN
|
||||
{ $$.as_function = std::make_unique<ast::expr_function>(@$, std::make_unique<ast::expr_path>(@$), std::move($1), std::move($3), ast::call::mode::normal); }
|
||||
| expr_path DOUBLECOLON expr_identifier LPAREN expr_arguments RPAREN
|
||||
{ $$.as_function = std::make_unique<ast::expr_function>(@$, std::move($1), std::move($3), std::move($5), ast::call::mode::normal); }
|
||||
| THREAD expr_identifier LPAREN expr_arguments RPAREN
|
||||
{ $$.as_function = std::make_unique<ast::expr_function>(@$, std::make_unique<ast::expr_path>(@$), std::move($2), std::move($4), ast::call::mode::thread); }
|
||||
| THREAD expr_path DOUBLECOLON expr_identifier LPAREN expr_arguments RPAREN
|
||||
{ $$.as_function = std::make_unique<ast::expr_function>(@$, std::move($2), std::move($4), std::move($6), ast::call::mode::thread); }
|
||||
| CHILDTHREAD expr_identifier LPAREN expr_arguments RPAREN
|
||||
{ $$.as_function = std::make_unique<ast::expr_function>(@$, std::make_unique<ast::expr_path>(@$), std::move($2), std::move($4), ast::call::mode::childthread); }
|
||||
| CHILDTHREAD expr_path DOUBLECOLON expr_identifier LPAREN expr_arguments RPAREN
|
||||
{ $$.as_function = std::make_unique<ast::expr_function>(@$, std::move($2), std::move($4), std::move($6), ast::call::mode::childthread); }
|
||||
;
|
||||
|
||||
expr_pointer
|
||||
: LBRACKET LBRACKET expr RBRACKET RBRACKET LPAREN expr_arguments RPAREN
|
||||
{ $$.as_pointer = std::make_unique<ast::expr_pointer>(@$, std::move($3), std::move($7), ast::call::mode::normal); }
|
||||
| THREAD LBRACKET LBRACKET expr RBRACKET RBRACKET LPAREN expr_arguments RPAREN
|
||||
{ $$.as_pointer = std::make_unique<ast::expr_pointer>(@$, std::move($4), std::move($8), ast::call::mode::thread); }
|
||||
| CHILDTHREAD LBRACKET LBRACKET expr RBRACKET RBRACKET LPAREN expr_arguments RPAREN
|
||||
{ $$.as_pointer = std::make_unique<ast::expr_pointer>(@$, std::move($4), std::move($8), ast::call::mode::childthread); }
|
||||
| CALL LBRACKET LBRACKET expr RBRACKET RBRACKET LPAREN expr_arguments RPAREN
|
||||
{ $$.as_pointer = std::make_unique<ast::expr_pointer>(@$, std::move($4), std::move($8), ast::call::mode::builtin); }
|
||||
;
|
||||
|
||||
expr_add_array
|
||||
: LBRACKET expr_arguments_no_empty RBRACKET
|
||||
{ $$ = std::make_unique<ast::expr_add_array>(@$, std::move($2)); }
|
||||
;
|
||||
|
||||
expr_parameters
|
||||
: expr_parameters COMMA expr_identifier
|
||||
{ $$ = std::move($1); $$->list.push_back(std::move($3)); }
|
||||
| expr_identifier
|
||||
{ $$ = std::make_unique<ast::expr_parameters>(@$); $$->list.push_back(std::move($1)); }
|
||||
|
|
||||
{ $$ = std::make_unique<ast::expr_parameters>(@$); }
|
||||
;
|
||||
|
||||
expr_arguments
|
||||
: expr_arguments_no_empty
|
||||
{ $$ = std::move($1); }
|
||||
|
|
||||
{ $$ = std::make_unique<ast::expr_arguments>(@$); }
|
||||
;
|
||||
|
||||
expr_arguments_no_empty
|
||||
: expr_arguments COMMA expr
|
||||
{ $$ = std::move($1); $$->list.push_back(std::move($3)); }
|
||||
| expr %prec ADD_ARRAY
|
||||
{ $$ = std::make_unique<ast::expr_arguments>(@$); $$->list.push_back(std::move($1)); }
|
||||
;
|
||||
|
||||
expr_isdefined
|
||||
: ISDEFINED LPAREN expr RPAREN
|
||||
{ $$ = std::make_unique<ast::expr_isdefined>(@$, std::move($3)); }
|
||||
;
|
||||
|
||||
expr_istrue
|
||||
: ISTRUE LPAREN expr RPAREN
|
||||
{ $$ = std::make_unique<ast::expr_istrue>(@$, std::move($3)); }
|
||||
;
|
||||
|
||||
expr_reference
|
||||
: DOUBLECOLON expr_identifier
|
||||
{ $$ = std::make_unique<ast::expr_reference>(@$, std::make_unique<ast::expr_path>(@$), std::move($2)); }
|
||||
| expr_path DOUBLECOLON expr_identifier
|
||||
{ $$ = std::make_unique<ast::expr_reference>(@$, std::move($1), std::move($3)); }
|
||||
;
|
||||
|
||||
expr_tuple
|
||||
: LBRACKET expr_tuple_arguments RBRACKET
|
||||
{ $$.as_node = std::move($2); }
|
||||
;
|
||||
|
||||
expr_tuple_arguments
|
||||
: expr_tuple_arguments COMMA expr_tuple_types
|
||||
{ $$ = std::move($1); $$->list.push_back(std::move($3)); }
|
||||
| expr_tuple_types
|
||||
{ $$ = std::make_unique<ast::expr_tuple>(@$); $$->list.push_back(std::move($1)); }
|
||||
;
|
||||
|
||||
expr_tuple_types
|
||||
: expr_array { $$.as_node = std::move($1); }
|
||||
| expr_field { $$.as_node = std::move($1); }
|
||||
| expr_identifier { $$.as_node = std::move($1); }
|
||||
;
|
||||
|
||||
expr_array
|
||||
: expr_object LBRACKET expr RBRACKET
|
||||
{ $$ = std::make_unique<ast::expr_array>(@$, std::move($1), std::move($3)); }
|
||||
;
|
||||
|
||||
expr_field
|
||||
: expr_object DOT expr_identifier_nosize
|
||||
{ $$ = std::make_unique<ast::expr_field>(@$, std::move($1), std::move($3)); }
|
||||
;
|
||||
|
||||
expr_size
|
||||
: expr_object DOT SIZE %prec SIZEOF
|
||||
{ $$ = std::make_unique<ast::expr_size>(@$, std::move($1)); }
|
||||
;
|
||||
|
||||
expr_paren
|
||||
: LPAREN expr RPAREN
|
||||
{ $$ = std::make_unique<ast::expr_paren>(@$, std::move($2)); }
|
||||
;
|
||||
|
||||
expr_object
|
||||
: expr_call { $$.as_node = std::move($1); }
|
||||
| expr_method { $$.as_node = std::move($1); }
|
||||
| expr_array { $$.as_node = std::move($1); }
|
||||
| expr_field { $$.as_node = std::move($1); }
|
||||
| expr_game { $$.as_node = std::move($1); }
|
||||
| expr_self { $$.as_node = std::move($1); }
|
||||
| expr_anim { $$.as_node = std::move($1); }
|
||||
| expr_level { $$.as_node = std::move($1); }
|
||||
| expr_identifier { $$.as_node = std::move($1); }
|
||||
;
|
||||
|
||||
expr_thisthread
|
||||
: THISTHREAD
|
||||
{ $$ = std::make_unique<ast::expr_thisthread>(@$); };
|
||||
;
|
||||
|
||||
expr_empty_array
|
||||
: LBRACKET RBRACKET
|
||||
{ $$ = std::make_unique<ast::expr_empty_array>(@$); };
|
||||
;
|
||||
|
||||
expr_undefined
|
||||
: UNDEFINED
|
||||
{ $$ = std::make_unique<ast::expr_undefined>(@$); };
|
||||
;
|
||||
|
||||
expr_game
|
||||
: GAME
|
||||
{ $$ = std::make_unique<ast::expr_game>(@$); };
|
||||
;
|
||||
|
||||
expr_self
|
||||
: SELF
|
||||
{ $$ = std::make_unique<ast::expr_self>(@$); };
|
||||
;
|
||||
|
||||
expr_anim
|
||||
: ANIM
|
||||
{ $$ = std::make_unique<ast::expr_anim>(@$); };
|
||||
;
|
||||
|
||||
expr_level
|
||||
: LEVEL
|
||||
{ $$ = std::make_unique<ast::expr_level>(@$); };
|
||||
;
|
||||
|
||||
expr_animation
|
||||
: MOD IDENTIFIER %prec ANIMREF
|
||||
{ $$ = std::make_unique<ast::expr_animation>(@$, $2); };
|
||||
;
|
||||
|
||||
expr_animtree
|
||||
: ANIMTREE
|
||||
{ $$ = std::make_unique<ast::expr_animtree>(@$); };
|
||||
;
|
||||
|
||||
expr_identifier_nosize
|
||||
: IDENTIFIER
|
||||
{ $$ = std::make_unique<ast::expr_identifier>(@$, $1); };
|
||||
;
|
||||
|
||||
expr_identifier
|
||||
: IDENTIFIER
|
||||
{ $$ = std::make_unique<ast::expr_identifier>(@$, $1); };
|
||||
| SIZE
|
||||
{ $$ = std::make_unique<ast::expr_identifier>(@$, "size"); };
|
||||
;
|
||||
|
||||
expr_path
|
||||
: IDENTIFIER
|
||||
{ $$ = std::make_unique<ast::expr_path>(@$, $1); };
|
||||
| PATH
|
||||
{ $$ = std::make_unique<ast::expr_path>(@$, $1); };
|
||||
;
|
||||
|
||||
expr_istring
|
||||
: ISTRING
|
||||
{ $$ = std::make_unique<ast::expr_istring>(@$, $1); };
|
||||
;
|
||||
|
||||
expr_string
|
||||
: STRING
|
||||
{ $$ = std::make_unique<ast::expr_string>(@$, $1); };
|
||||
;
|
||||
|
||||
expr_vector
|
||||
: LPAREN expr COMMA expr COMMA expr RPAREN
|
||||
{ $$ = std::make_unique<ast::expr_vector>(@$, std::move($2), std::move($4), std::move($6)); };
|
||||
;
|
||||
|
||||
expr_float
|
||||
: SUB FLOAT %prec NEG
|
||||
{ $$ = std::make_unique<ast::expr_float>(@$, "-" + $2); };
|
||||
| FLOAT
|
||||
{ $$ = std::make_unique<ast::expr_float>(@$, $1); };
|
||||
;
|
||||
|
||||
expr_integer
|
||||
: SUB INTEGER %prec NEG
|
||||
{ $$ = std::make_unique<ast::expr_integer>(@$, "-" + $2); };
|
||||
| INTEGER
|
||||
{ $$ = std::make_unique<ast::expr_integer>(@$, $1); };
|
||||
;
|
||||
|
||||
expr_false
|
||||
: FALSE
|
||||
{ $$ = std::make_unique<ast::expr_false>(@$); };
|
||||
;
|
||||
|
||||
expr_true
|
||||
: TRUE
|
||||
{ $$ = std::make_unique<ast::expr_true>(@$); };
|
||||
;
|
||||
|
||||
%%
|
||||
|
||||
void xsk::gsc::iw8::parser::error(const xsk::gsc::location& loc, const std::string& msg)
|
||||
{
|
||||
throw xsk::gsc::comp_error(loc, msg);
|
||||
}
|
@ -1,9 +0,0 @@
|
||||
generate: iw9
|
||||
|
||||
clean:
|
||||
rm -rf ./parser.hpp
|
||||
rm -rf ./parser.cpp
|
||||
|
||||
iw9: parser.ypp
|
||||
bison parser.ypp -Wcounterexamples
|
||||
mv parser.hpp parser.cpp ../../src/iw9/xsk/
|
@ -1,914 +0,0 @@
|
||||
/* Copyright 2022 xensik. All rights reserved.
|
||||
//
|
||||
// Use of this source code is governed by a GNU GPLv3 license
|
||||
// that can be found in the LICENSE file.
|
||||
*/
|
||||
|
||||
%require "3.7"
|
||||
%skeleton "lalr1.cc"
|
||||
%language "c++"
|
||||
%output "parser.cpp"
|
||||
%defines "parser.hpp"
|
||||
%define api.prefix {IW9}
|
||||
%define api.namespace {xsk::gsc::iw9}
|
||||
%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 { xsk::gsc::iw9::lexer& lexer }
|
||||
%parse-param { xsk::gsc::iw9::lexer& lexer }
|
||||
%parse-param { xsk::gsc::ast::program::ptr& ast }
|
||||
|
||||
%code requires
|
||||
{
|
||||
#ifdef _MSC_VER
|
||||
#pragma warning(disable:4065)
|
||||
#pragma warning(disable:4127)
|
||||
#endif
|
||||
#include "iw9.hpp"
|
||||
namespace xsk::gsc::iw9 { class lexer; }
|
||||
}
|
||||
|
||||
%code top
|
||||
{
|
||||
#include "stdafx.hpp"
|
||||
#include "parser.hpp"
|
||||
#include "lexer.hpp"
|
||||
using namespace xsk::gsc;
|
||||
xsk::gsc::iw9::parser::symbol_type IW9lex(xsk::gsc::iw9::lexer& lexer);
|
||||
}
|
||||
|
||||
%token SH_DEFINE "#define"
|
||||
%token SH_UNDEF "#undef"
|
||||
%token SH_IFDEF "#ifdef"
|
||||
%token SH_IFNDEF "#ifndef"
|
||||
%token SH_IF "#if"
|
||||
%token SH_ELIF "#elif"
|
||||
%token SH_ELSE "#else"
|
||||
%token SH_ENDIF "#endif"
|
||||
%token DEVBEGIN "/#"
|
||||
%token DEVEND "#/"
|
||||
%token INLINE "#inline"
|
||||
%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 DO "do"
|
||||
%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 BREAKPOINT "breakpoint"
|
||||
%token PROFBEGIN "prof_begin"
|
||||
%token PROFEND "prof_end"
|
||||
%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 ISDEFINED "isdefined"
|
||||
%token ISTRUE "istrue"
|
||||
%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_MUL "*="
|
||||
%token ASSIGN_DIV "/="
|
||||
%token ASSIGN_MOD "%="
|
||||
%token ASSIGN_BW_OR "|="
|
||||
%token ASSIGN_BW_AND "&="
|
||||
%token ASSIGN_BW_EXOR "^="
|
||||
%token ASSIGN_RSHIFT ">>="
|
||||
%token ASSIGN_LSHIFT "<<="
|
||||
%token BITWISE_OR "|"
|
||||
%token BITWISE_AND "&"
|
||||
%token BITWISE_EXOR "^"
|
||||
%token ADD "+"
|
||||
%token SUB "-"
|
||||
%token MUL "*"
|
||||
%token DIV "/"
|
||||
%token MOD "%"
|
||||
%token <std::string> PATH "path"
|
||||
%token <std::string> IDENTIFIER "identifier"
|
||||
%token <std::string> STRING "string literal"
|
||||
%token <std::string> ISTRING "localized string"
|
||||
%token <std::string> FLOAT "float"
|
||||
%token <std::string> INTEGER "integer"
|
||||
|
||||
%type <ast::program::ptr> program
|
||||
%type <ast::include::ptr> include
|
||||
%type <ast::decl> declaration
|
||||
%type <ast::decl_usingtree::ptr> decl_usingtree
|
||||
%type <ast::decl_constant::ptr> decl_constant
|
||||
%type <ast::decl_thread::ptr> decl_thread
|
||||
%type <ast::stmt> stmt
|
||||
%type <ast::stmt> stmt_or_dev
|
||||
%type <ast::stmt_list::ptr> stmt_list
|
||||
%type <ast::stmt_list::ptr> stmt_or_dev_list
|
||||
%type <ast::stmt_dev::ptr> stmt_dev
|
||||
%type <ast::stmt_list::ptr> stmt_block
|
||||
%type <ast::stmt_expr::ptr> stmt_expr
|
||||
%type <ast::stmt_call::ptr> stmt_call
|
||||
%type <ast::stmt_assign::ptr> stmt_assign
|
||||
%type <ast::stmt_endon::ptr> stmt_endon
|
||||
%type <ast::stmt_notify::ptr> stmt_notify
|
||||
%type <ast::stmt_wait::ptr> stmt_wait
|
||||
%type <ast::stmt_waittill::ptr> stmt_waittill
|
||||
%type <ast::stmt_waittillmatch::ptr> stmt_waittillmatch
|
||||
%type <ast::stmt_waittillframeend::ptr> stmt_waittillframeend
|
||||
%type <ast::stmt_waitframe::ptr> stmt_waitframe
|
||||
%type <ast::stmt_if::ptr> stmt_if
|
||||
%type <ast::stmt_ifelse::ptr> stmt_ifelse
|
||||
%type <ast::stmt_while::ptr> stmt_while
|
||||
%type <ast::stmt_dowhile::ptr> stmt_dowhile
|
||||
%type <ast::stmt_for::ptr> stmt_for
|
||||
%type <ast::stmt_foreach::ptr> stmt_foreach
|
||||
%type <ast::stmt_switch::ptr> stmt_switch
|
||||
%type <ast::stmt_case::ptr> stmt_case
|
||||
%type <ast::stmt_default::ptr> stmt_default
|
||||
%type <ast::stmt_break::ptr> stmt_break
|
||||
%type <ast::stmt_continue::ptr> stmt_continue
|
||||
%type <ast::stmt_return::ptr> stmt_return
|
||||
%type <ast::stmt_breakpoint::ptr> stmt_breakpoint
|
||||
%type <ast::stmt_prof_begin::ptr> stmt_prof_begin
|
||||
%type <ast::stmt_prof_end::ptr> stmt_prof_end
|
||||
%type <ast::expr> expr
|
||||
%type <ast::expr> expr_or_empty
|
||||
%type <ast::expr> expr_assign
|
||||
%type <ast::expr> expr_increment
|
||||
%type <ast::expr> expr_decrement
|
||||
%type <ast::expr> expr_ternary
|
||||
%type <ast::expr> expr_binary
|
||||
%type <ast::expr> expr_primitive
|
||||
%type <ast::expr_complement::ptr> expr_complement
|
||||
%type <ast::expr_negate::ptr> expr_negate
|
||||
%type <ast::expr_not::ptr> expr_not
|
||||
%type <ast::expr_call::ptr> expr_call
|
||||
%type <ast::expr_method::ptr> expr_method
|
||||
%type <ast::call> expr_function
|
||||
%type <ast::call> expr_pointer
|
||||
%type <ast::expr_add_array::ptr> expr_add_array
|
||||
%type <ast::expr_parameters::ptr> expr_parameters
|
||||
%type <ast::expr_arguments::ptr> expr_arguments
|
||||
%type <ast::expr_arguments::ptr> expr_arguments_no_empty
|
||||
%type <ast::expr_isdefined::ptr> expr_isdefined
|
||||
%type <ast::expr_istrue::ptr> expr_istrue
|
||||
%type <ast::expr_reference::ptr> expr_reference
|
||||
%type <ast::expr> expr_tuple
|
||||
%type <ast::expr_tuple::ptr> expr_tuple_arguments
|
||||
%type <ast::expr> expr_tuple_types
|
||||
%type <ast::expr_array::ptr> expr_array
|
||||
%type <ast::expr_field::ptr> expr_field
|
||||
%type <ast::expr_size::ptr> expr_size
|
||||
%type <ast::expr_paren::ptr> expr_paren
|
||||
%type <ast::expr> expr_object
|
||||
%type <ast::expr_thisthread::ptr> expr_thisthread
|
||||
%type <ast::expr_empty_array::ptr> expr_empty_array
|
||||
%type <ast::expr_undefined::ptr> expr_undefined
|
||||
%type <ast::expr_game::ptr> expr_game
|
||||
%type <ast::expr_self::ptr> expr_self
|
||||
%type <ast::expr_anim::ptr> expr_anim
|
||||
%type <ast::expr_level::ptr> expr_level
|
||||
%type <ast::expr_animation::ptr> expr_animation
|
||||
%type <ast::expr_animtree::ptr> expr_animtree
|
||||
%type <ast::expr_identifier::ptr> expr_identifier_nosize
|
||||
%type <ast::expr_identifier::ptr> expr_identifier
|
||||
%type <ast::expr_path::ptr> expr_path
|
||||
%type <ast::expr_istring::ptr> expr_istring
|
||||
%type <ast::expr_string::ptr> expr_string
|
||||
%type <ast::expr_vector::ptr> expr_vector
|
||||
%type <ast::expr_float::ptr> expr_float
|
||||
%type <ast::expr_integer::ptr> expr_integer
|
||||
%type <ast::expr_false::ptr> expr_false
|
||||
%type <ast::expr_true::ptr> expr_true
|
||||
|
||||
%nonassoc SIZEOF
|
||||
%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_EXOR
|
||||
%left BITWISE_AND
|
||||
%left EQUALITY INEQUALITY
|
||||
%left LESS GREATER LESS_EQUAL GREATER_EQUAL
|
||||
%left LSHIFT RSHIFT
|
||||
%left ADD SUB
|
||||
%left MUL 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<ast::program>(@$); }
|
||||
;
|
||||
|
||||
program
|
||||
: program inline
|
||||
{ $$ = std::move($1); }
|
||||
| program include
|
||||
{ $$ = std::move($1); $$->includes.push_back(std::move($2)); }
|
||||
| program declaration
|
||||
{ $$ = std::move($1); $$->declarations.push_back(std::move($2)); }
|
||||
| inline
|
||||
{ $$ = std::make_unique<ast::program>(@$); }
|
||||
| include
|
||||
{ $$ = std::make_unique<ast::program>(@$); $$->includes.push_back(std::move($1)); }
|
||||
| declaration
|
||||
{ $$ = std::make_unique<ast::program>(@$); $$->declarations.push_back(std::move($1)); }
|
||||
;
|
||||
|
||||
inline
|
||||
: INLINE expr_path SEMICOLON { lexer.push_header($2->value); }
|
||||
;
|
||||
|
||||
include
|
||||
: INCLUDE expr_path SEMICOLON
|
||||
{ $$ = std::make_unique<ast::include>(@$, std::move($2)); }
|
||||
;
|
||||
|
||||
declaration
|
||||
: DEVBEGIN { $$.as_dev_begin = std::make_unique<ast::decl_dev_begin>(@$); }
|
||||
| DEVEND { $$.as_dev_end = std::make_unique<ast::decl_dev_end>(@$); }
|
||||
| decl_usingtree { $$.as_usingtree = std::move($1); }
|
||||
| decl_constant { $$.as_constant = std::move($1); }
|
||||
| decl_thread { $$.as_thread = std::move($1); }
|
||||
;
|
||||
|
||||
decl_usingtree
|
||||
: USINGTREE LPAREN expr_string RPAREN SEMICOLON
|
||||
{ lexer.ban_header(@$); $$ = std::make_unique<ast::decl_usingtree>(@$, std::move($3)); }
|
||||
;
|
||||
|
||||
decl_constant
|
||||
: expr_identifier ASSIGN expr SEMICOLON
|
||||
{ $$ = std::make_unique<ast::decl_constant>(@$, std::move($1), std::move($3)); }
|
||||
;
|
||||
|
||||
decl_thread
|
||||
: expr_identifier LPAREN expr_parameters RPAREN stmt_block
|
||||
{ lexer.ban_header(@$); $$ = std::make_unique<ast::decl_thread>(@$, std::move($1), std::move($3), std::move($5)); }
|
||||
;
|
||||
|
||||
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_dowhile { $$.as_dowhile = 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_breakpoint { $$.as_breakpoint = std::move($1); }
|
||||
| stmt_prof_begin { $$.as_prof_begin = std::move($1); }
|
||||
| stmt_prof_end { $$.as_prof_end = std::move($1); }
|
||||
;
|
||||
|
||||
stmt_or_dev
|
||||
: stmt { $$ = std::move($1); }
|
||||
| stmt_dev { $$.as_dev = std::move($1); }
|
||||
;
|
||||
|
||||
stmt_list
|
||||
: stmt_list stmt
|
||||
{ $$ = std::move($1); $$->list.push_back(std::move($2)); }
|
||||
| stmt
|
||||
{ $$ = std::make_unique<ast::stmt_list>(@$); $$->list.push_back(std::move($1)); }
|
||||
;
|
||||
|
||||
stmt_or_dev_list
|
||||
: stmt_or_dev_list stmt_or_dev
|
||||
{ $$ = std::move($1); $$->list.push_back(std::move($2)); }
|
||||
| stmt_or_dev
|
||||
{ $$ = std::make_unique<ast::stmt_list>(@$); $$->list.push_back(std::move($1)); }
|
||||
;
|
||||
|
||||
stmt_dev
|
||||
: DEVBEGIN stmt_list DEVEND { $$ = std::make_unique<ast::stmt_dev>(@$, std::move($2)); }
|
||||
| DEVBEGIN DEVEND { $$ = std::make_unique<ast::stmt_dev>(@$, std::make_unique<ast::stmt_list>(@$)); }
|
||||
;
|
||||
|
||||
stmt_block
|
||||
: LBRACE stmt_or_dev_list RBRACE { $$ = std::move($2); }
|
||||
| LBRACE RBRACE { $$ = std::make_unique<ast::stmt_list>(@$); }
|
||||
;
|
||||
|
||||
stmt_expr
|
||||
: expr_assign
|
||||
{ $$ = std::make_unique<ast::stmt_expr>(@$, std::move($1)); }
|
||||
| expr_increment
|
||||
{ $$ = std::make_unique<ast::stmt_expr>(@$, std::move($1)); }
|
||||
| expr_decrement
|
||||
{ $$ = std::make_unique<ast::stmt_expr>(@$, std::move($1)); }
|
||||
|
|
||||
{ $$ = std::make_unique<ast::stmt_expr>(@$, std::make_unique<ast::node>(@$)); }
|
||||
;
|
||||
|
||||
stmt_call
|
||||
: expr_call SEMICOLON
|
||||
{ $$ = std::make_unique<ast::stmt_call>(@$, ast::expr(std::move($1))); }
|
||||
| expr_method SEMICOLON
|
||||
{ $$ = std::make_unique<ast::stmt_call>(@$, ast::expr(std::move($1))); }
|
||||
;
|
||||
|
||||
stmt_assign
|
||||
: expr_assign SEMICOLON
|
||||
{ $$ = std::make_unique<ast::stmt_assign>(@$, std::move($1)); }
|
||||
| expr_increment SEMICOLON
|
||||
{ $$ = std::make_unique<ast::stmt_assign>(@$, std::move($1)); }
|
||||
| expr_decrement SEMICOLON
|
||||
{ $$ = std::make_unique<ast::stmt_assign>(@$, std::move($1)); }
|
||||
;
|
||||
|
||||
stmt_endon
|
||||
: expr_object ENDON LPAREN expr RPAREN SEMICOLON
|
||||
{ $$ = std::make_unique<ast::stmt_endon>(@$, std::move($1), std::move($4)); }
|
||||
;
|
||||
|
||||
stmt_notify
|
||||
: expr_object NOTIFY LPAREN expr COMMA expr_arguments_no_empty RPAREN SEMICOLON
|
||||
{ $$ = std::make_unique<ast::stmt_notify>(@$, std::move($1), std::move($4), std::move($6)); }
|
||||
| expr_object NOTIFY LPAREN expr RPAREN SEMICOLON
|
||||
{ $$ = std::make_unique<ast::stmt_notify>(@$, std::move($1), std::move($4), std::make_unique<ast::expr_arguments>(@$)); }
|
||||
;
|
||||
|
||||
stmt_wait
|
||||
: WAIT expr SEMICOLON
|
||||
{ $$ = std::make_unique<ast::stmt_wait>(@$, std::move($2)); }
|
||||
;
|
||||
|
||||
stmt_waittill
|
||||
: expr_object WAITTILL LPAREN expr COMMA expr_arguments_no_empty RPAREN SEMICOLON
|
||||
{ $$ = std::make_unique<ast::stmt_waittill>(@$, std::move($1), std::move($4), std::move($6)); }
|
||||
| expr_object WAITTILL LPAREN expr RPAREN SEMICOLON
|
||||
{ $$ = std::make_unique<ast::stmt_waittill>(@$, std::move($1), std::move($4), std::make_unique<ast::expr_arguments>(@$)); }
|
||||
;
|
||||
|
||||
stmt_waittillmatch
|
||||
: expr_object WAITTILLMATCH LPAREN expr COMMA expr_arguments_no_empty RPAREN SEMICOLON
|
||||
{ $$ = std::make_unique<ast::stmt_waittillmatch>(@$, std::move($1), std::move($4), std::move($6)); }
|
||||
| expr_object WAITTILLMATCH LPAREN expr RPAREN SEMICOLON
|
||||
{ $$ = std::make_unique<ast::stmt_waittillmatch>(@$, std::move($1), std::move($4), std::make_unique<ast::expr_arguments>(@$)); }
|
||||
;
|
||||
|
||||
stmt_waittillframeend
|
||||
: WAITTILLFRAMEEND SEMICOLON
|
||||
{ $$ = std::make_unique<ast::stmt_waittillframeend>(@$); }
|
||||
;
|
||||
|
||||
stmt_waitframe
|
||||
: WAITFRAME SEMICOLON
|
||||
{ $$ = std::make_unique<ast::stmt_waitframe>(@$); }
|
||||
| WAITFRAME LPAREN RPAREN SEMICOLON
|
||||
{ $$ = std::make_unique<ast::stmt_waitframe>(@$); }
|
||||
;
|
||||
|
||||
stmt_if
|
||||
: IF LPAREN expr RPAREN stmt %prec THEN
|
||||
{ $$ = std::make_unique<ast::stmt_if>(@$, std::move($3), std::move($5)); }
|
||||
;
|
||||
|
||||
stmt_ifelse
|
||||
: IF LPAREN expr RPAREN stmt ELSE stmt
|
||||
{ $$ = std::make_unique<ast::stmt_ifelse>(@$, std::move($3), std::move($5), std::move($7)); }
|
||||
;
|
||||
|
||||
stmt_while
|
||||
: WHILE LPAREN expr RPAREN stmt
|
||||
{ $$ = std::make_unique<ast::stmt_while>(@$, std::move($3), std::move($5)); }
|
||||
;
|
||||
|
||||
stmt_dowhile
|
||||
: DO stmt WHILE LPAREN expr RPAREN SEMICOLON
|
||||
{ $$ = std::make_unique<ast::stmt_dowhile>(@$, std::move($5), std::move($2)); }
|
||||
;
|
||||
|
||||
stmt_for
|
||||
: FOR LPAREN stmt_expr SEMICOLON expr_or_empty SEMICOLON stmt_expr RPAREN stmt
|
||||
{ $$ = std::make_unique<ast::stmt_for>(@$, ast::stmt(std::move($3)), std::move($5), ast::stmt(std::move($7)), std::move($9)); }
|
||||
;
|
||||
|
||||
stmt_foreach
|
||||
: FOREACH LPAREN expr_identifier IN expr RPAREN stmt
|
||||
{ $$ = std::make_unique<ast::stmt_foreach>(@$, ast::expr(std::move($3)), std::move($5), std::move($7)); }
|
||||
| FOREACH LPAREN expr_identifier COMMA expr_identifier IN expr RPAREN stmt
|
||||
{ $$ = std::make_unique<ast::stmt_foreach>(@$, ast::expr(std::move($3)), ast::expr(std::move($5)), std::move($7), std::move($9)); }
|
||||
;
|
||||
|
||||
stmt_switch
|
||||
: SWITCH LPAREN expr RPAREN stmt_block
|
||||
{ $$ = std::make_unique<ast::stmt_switch>(@$, std::move($3), std::move($5)); }
|
||||
;
|
||||
|
||||
stmt_case
|
||||
: CASE expr_integer COLON
|
||||
{ $$ = std::make_unique<ast::stmt_case>(@$, ast::expr(std::move($2)), std::make_unique<ast::stmt_list>(@$)); }
|
||||
| CASE expr_string COLON
|
||||
{ $$ = std::make_unique<ast::stmt_case>(@$, ast::expr(std::move($2)), std::make_unique<ast::stmt_list>(@$)); }
|
||||
;
|
||||
|
||||
stmt_default
|
||||
: DEFAULT COLON
|
||||
{ $$ = std::make_unique<ast::stmt_default>(@$, std::make_unique<ast::stmt_list>(@$)); }
|
||||
;
|
||||
|
||||
stmt_break
|
||||
: BREAK SEMICOLON
|
||||
{ $$ = std::make_unique<ast::stmt_break>(@$); }
|
||||
;
|
||||
|
||||
stmt_continue
|
||||
: CONTINUE SEMICOLON
|
||||
{ $$ = std::make_unique<ast::stmt_continue>(@$); }
|
||||
;
|
||||
|
||||
stmt_return
|
||||
: RETURN expr SEMICOLON
|
||||
{ $$ = std::make_unique<ast::stmt_return>(@$, std::move($2)); }
|
||||
| RETURN SEMICOLON
|
||||
{ $$ = std::make_unique<ast::stmt_return>(@$, std::make_unique<ast::node>(@$)); }
|
||||
;
|
||||
|
||||
stmt_breakpoint
|
||||
: BREAKPOINT SEMICOLON
|
||||
{ $$ = std::make_unique<ast::stmt_breakpoint>(@$); }
|
||||
;
|
||||
|
||||
stmt_prof_begin
|
||||
: PROFBEGIN LPAREN expr_arguments RPAREN SEMICOLON
|
||||
{ $$ = std::make_unique<ast::stmt_prof_begin>(@$, std::move($3)); }
|
||||
;
|
||||
|
||||
stmt_prof_end
|
||||
: PROFEND LPAREN expr_arguments RPAREN SEMICOLON
|
||||
{ $$ = std::make_unique<ast::stmt_prof_end>(@$, std::move($3)); }
|
||||
;
|
||||
|
||||
expr
|
||||
: expr_ternary { $$ = std::move($1); }
|
||||
| expr_binary { $$ = std::move($1); }
|
||||
| expr_primitive { $$ = std::move($1); }
|
||||
;
|
||||
|
||||
expr_or_empty
|
||||
: expr { $$ = std::move($1); }
|
||||
| { $$.as_node = std::make_unique<ast::node>(@$); }
|
||||
;
|
||||
|
||||
expr_assign
|
||||
: expr_tuple ASSIGN expr
|
||||
{ $$.as_node = std::make_unique<ast::expr_assign_equal>(@$, std::move($1), std::move($3)); }
|
||||
| expr_object ASSIGN expr
|
||||
{ $$.as_node = std::make_unique<ast::expr_assign_equal>(@$, std::move($1), std::move($3)); }
|
||||
| expr_object ASSIGN_BW_OR expr
|
||||
{ $$.as_node = std::make_unique<ast::expr_assign_bitwise_or>(@$, std::move($1), std::move($3)); }
|
||||
| expr_object ASSIGN_BW_AND expr
|
||||
{ $$.as_node = std::make_unique<ast::expr_assign_bitwise_and>(@$, std::move($1), std::move($3)); }
|
||||
| expr_object ASSIGN_BW_EXOR expr
|
||||
{ $$.as_node = std::make_unique<ast::expr_assign_bitwise_exor>(@$, std::move($1), std::move($3)); }
|
||||
| expr_object ASSIGN_LSHIFT expr
|
||||
{ $$.as_node = std::make_unique<ast::expr_assign_shift_left>(@$, std::move($1),std::move( $3)); }
|
||||
| expr_object ASSIGN_RSHIFT expr
|
||||
{ $$.as_node = std::make_unique<ast::expr_assign_shift_right>(@$, std::move($1), std::move($3)); }
|
||||
| expr_object ASSIGN_ADD expr
|
||||
{ $$.as_node = std::make_unique<ast::expr_assign_add>(@$, std::move($1), std::move($3)); }
|
||||
| expr_object ASSIGN_SUB expr
|
||||
{ $$.as_node = std::make_unique<ast::expr_assign_sub>(@$, std::move($1), std::move($3)); }
|
||||
| expr_object ASSIGN_MUL expr
|
||||
{ $$.as_node = std::make_unique<ast::expr_assign_mul>(@$, std::move($1), std::move($3)); }
|
||||
| expr_object ASSIGN_DIV expr
|
||||
{ $$.as_node = std::make_unique<ast::expr_assign_div>(@$, std::move($1), std::move($3)); }
|
||||
| expr_object ASSIGN_MOD expr
|
||||
{ $$.as_node = std::make_unique<ast::expr_assign_mod>(@$, std::move($1), std::move($3)); }
|
||||
;
|
||||
|
||||
expr_increment
|
||||
: INCREMENT expr_object %prec PREINC
|
||||
{ $$.as_node = std::make_unique<ast::expr_increment>(@$, std::move($2), true); }
|
||||
| expr_object INCREMENT %prec POSTINC
|
||||
{ $$.as_node = std::make_unique<ast::expr_increment>(@$, std::move($1), false); }
|
||||
;
|
||||
|
||||
expr_decrement
|
||||
: DECREMENT expr_object %prec PREDEC
|
||||
{ $$.as_node = std::make_unique<ast::expr_decrement>(@$, std::move($2), true); }
|
||||
| expr_object DECREMENT %prec POSTDEC
|
||||
{ $$.as_node = std::make_unique<ast::expr_decrement>(@$, std::move($1), false); }
|
||||
;
|
||||
|
||||
expr_ternary
|
||||
: expr QMARK expr COLON expr %prec TERN
|
||||
{ $$.as_node = std::make_unique<ast::expr_ternary>(@$, std::move($1), std::move($3), std::move($5)); }
|
||||
;
|
||||
|
||||
expr_binary
|
||||
: expr OR expr
|
||||
{ $$.as_node = std::make_unique<ast::expr_or>(@$, std::move($1), std::move($3)); }
|
||||
| expr AND expr
|
||||
{ $$.as_node = std::make_unique<ast::expr_and>(@$, std::move($1), std::move($3)); }
|
||||
| expr EQUALITY expr
|
||||
{ $$.as_node = std::make_unique<ast::expr_equality>(@$, std::move($1), std::move($3)); }
|
||||
| expr INEQUALITY expr
|
||||
{ $$.as_node = std::make_unique<ast::expr_inequality>(@$, std::move($1), std::move($3)); }
|
||||
| expr LESS_EQUAL expr
|
||||
{ $$.as_node = std::make_unique<ast::expr_less_equal>(@$, std::move($1), std::move($3)); }
|
||||
| expr GREATER_EQUAL expr
|
||||
{ $$.as_node = std::make_unique<ast::expr_greater_equal>(@$, std::move($1), std::move($3)); }
|
||||
| expr LESS expr
|
||||
{ $$.as_node = std::make_unique<ast::expr_less>(@$, std::move($1), std::move($3)); }
|
||||
| expr GREATER expr
|
||||
{ $$.as_node = std::make_unique<ast::expr_greater>(@$, std::move($1), std::move($3)); }
|
||||
| expr BITWISE_OR expr
|
||||
{ $$.as_node = std::make_unique<ast::expr_bitwise_or>(@$, std::move($1), std::move($3)); }
|
||||
| expr BITWISE_AND expr
|
||||
{ $$.as_node = std::make_unique<ast::expr_bitwise_and>(@$, std::move($1), std::move($3)); }
|
||||
| expr BITWISE_EXOR expr
|
||||
{ $$.as_node = std::make_unique<ast::expr_bitwise_exor>(@$, std::move($1), std::move($3)); }
|
||||
| expr LSHIFT expr
|
||||
{ $$.as_node = std::make_unique<ast::expr_shift_left>(@$, std::move($1), std::move($3)); }
|
||||
| expr RSHIFT expr
|
||||
{ $$.as_node = std::make_unique<ast::expr_shift_right>(@$, std::move($1), std::move($3)); }
|
||||
| expr ADD expr
|
||||
{ $$.as_node = std::make_unique<ast::expr_add>(@$, std::move($1), std::move($3)); }
|
||||
| expr SUB expr
|
||||
{ $$.as_node = std::make_unique<ast::expr_sub>(@$, std::move($1), std::move($3)); }
|
||||
| expr MUL expr
|
||||
{ $$.as_node = std::make_unique<ast::expr_mul>(@$, std::move($1), std::move($3)); }
|
||||
| expr DIV expr
|
||||
{ $$.as_node = std::make_unique<ast::expr_div>(@$, std::move($1), std::move($3)); }
|
||||
| expr MOD expr
|
||||
{ $$.as_node = std::make_unique<ast::expr_mod>(@$, std::move($1), std::move($3)); }
|
||||
;
|
||||
|
||||
expr_primitive
|
||||
: expr_complement { $$.as_node = std::move($1); }
|
||||
| expr_negate { $$.as_node = std::move($1); }
|
||||
| expr_not { $$.as_node = std::move($1); }
|
||||
| expr_call { $$.as_node = std::move($1); }
|
||||
| expr_method { $$.as_node = std::move($1); }
|
||||
| expr_add_array { $$.as_node = std::move($1); }
|
||||
| expr_isdefined { $$.as_node = std::move($1); }
|
||||
| expr_istrue { $$.as_node = std::move($1); }
|
||||
| expr_reference { $$.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); }
|
||||
| expr_paren { $$.as_node = std::move($1); }
|
||||
| expr_thisthread { $$.as_node = std::move($1); }
|
||||
| expr_empty_array { $$.as_node = std::move($1); }
|
||||
| expr_undefined { $$.as_node = std::move($1); }
|
||||
| expr_game { $$.as_node = std::move($1); }
|
||||
| expr_self { $$.as_node = std::move($1); }
|
||||
| expr_anim { $$.as_node = std::move($1); }
|
||||
| expr_level { $$.as_node = std::move($1); }
|
||||
| expr_animation { $$.as_node = std::move($1); }
|
||||
| expr_animtree { $$.as_node = std::move($1); }
|
||||
| expr_identifier { $$.as_node = std::move($1); }
|
||||
| expr_istring { $$.as_node = std::move($1); }
|
||||
| expr_string { $$.as_node = std::move($1); }
|
||||
| expr_vector { $$.as_node = std::move($1); }
|
||||
| expr_float { $$.as_node = std::move($1); }
|
||||
| expr_integer { $$.as_node = std::move($1); }
|
||||
| expr_false { $$.as_node = std::move($1); }
|
||||
| expr_true { $$.as_node = std::move($1); }
|
||||
;
|
||||
|
||||
expr_complement
|
||||
: COMPLEMENT expr
|
||||
{ $$ = std::make_unique<ast::expr_complement>(@$, std::move($2)); }
|
||||
;
|
||||
|
||||
expr_negate
|
||||
: SUB expr_identifier %prec NEG
|
||||
{ $$ = std::make_unique<ast::expr_negate>(@$, ast::expr(std::move($2))); }
|
||||
| SUB expr_paren %prec NEG
|
||||
{ $$ = std::make_unique<ast::expr_negate>(@$, ast::expr(std::move($2))); }
|
||||
| SUB expr_array %prec NEG
|
||||
{ $$ = std::make_unique<ast::expr_negate>(@$, ast::expr(std::move($2))); }
|
||||
| SUB expr_field %prec NEG
|
||||
{ $$ = std::make_unique<ast::expr_negate>(@$, ast::expr(std::move($2))); }
|
||||
;
|
||||
|
||||
expr_not
|
||||
: NOT expr
|
||||
{ $$ = std::make_unique<ast::expr_not>(@$, std::move($2)); }
|
||||
;
|
||||
|
||||
expr_call
|
||||
: expr_function { $$ = std::make_unique<ast::expr_call>(@$, std::move($1)); }
|
||||
| expr_pointer { $$ = std::make_unique<ast::expr_call>(@$, std::move($1)); }
|
||||
;
|
||||
expr_method
|
||||
: expr_object expr_function { $$ = std::make_unique<ast::expr_method>(@$, std::move($1), std::move($2)); }
|
||||
| expr_object expr_pointer { $$ = std::make_unique<ast::expr_method>(@$, std::move($1), std::move($2)); }
|
||||
;
|
||||
|
||||
expr_function
|
||||
: expr_identifier LPAREN expr_arguments RPAREN
|
||||
{ $$.as_function = std::make_unique<ast::expr_function>(@$, std::make_unique<ast::expr_path>(@$), std::move($1), std::move($3), ast::call::mode::normal); }
|
||||
| expr_path DOUBLECOLON expr_identifier LPAREN expr_arguments RPAREN
|
||||
{ $$.as_function = std::make_unique<ast::expr_function>(@$, std::move($1), std::move($3), std::move($5), ast::call::mode::normal); }
|
||||
| THREAD expr_identifier LPAREN expr_arguments RPAREN
|
||||
{ $$.as_function = std::make_unique<ast::expr_function>(@$, std::make_unique<ast::expr_path>(@$), std::move($2), std::move($4), ast::call::mode::thread); }
|
||||
| THREAD expr_path DOUBLECOLON expr_identifier LPAREN expr_arguments RPAREN
|
||||
{ $$.as_function = std::make_unique<ast::expr_function>(@$, std::move($2), std::move($4), std::move($6), ast::call::mode::thread); }
|
||||
| CHILDTHREAD expr_identifier LPAREN expr_arguments RPAREN
|
||||
{ $$.as_function = std::make_unique<ast::expr_function>(@$, std::make_unique<ast::expr_path>(@$), std::move($2), std::move($4), ast::call::mode::childthread); }
|
||||
| CHILDTHREAD expr_path DOUBLECOLON expr_identifier LPAREN expr_arguments RPAREN
|
||||
{ $$.as_function = std::make_unique<ast::expr_function>(@$, std::move($2), std::move($4), std::move($6), ast::call::mode::childthread); }
|
||||
;
|
||||
|
||||
expr_pointer
|
||||
: LBRACKET LBRACKET expr RBRACKET RBRACKET LPAREN expr_arguments RPAREN
|
||||
{ $$.as_pointer = std::make_unique<ast::expr_pointer>(@$, std::move($3), std::move($7), ast::call::mode::normal); }
|
||||
| THREAD LBRACKET LBRACKET expr RBRACKET RBRACKET LPAREN expr_arguments RPAREN
|
||||
{ $$.as_pointer = std::make_unique<ast::expr_pointer>(@$, std::move($4), std::move($8), ast::call::mode::thread); }
|
||||
| CHILDTHREAD LBRACKET LBRACKET expr RBRACKET RBRACKET LPAREN expr_arguments RPAREN
|
||||
{ $$.as_pointer = std::make_unique<ast::expr_pointer>(@$, std::move($4), std::move($8), ast::call::mode::childthread); }
|
||||
| CALL LBRACKET LBRACKET expr RBRACKET RBRACKET LPAREN expr_arguments RPAREN
|
||||
{ $$.as_pointer = std::make_unique<ast::expr_pointer>(@$, std::move($4), std::move($8), ast::call::mode::builtin); }
|
||||
;
|
||||
|
||||
expr_add_array
|
||||
: LBRACKET expr_arguments_no_empty RBRACKET
|
||||
{ $$ = std::make_unique<ast::expr_add_array>(@$, std::move($2)); }
|
||||
;
|
||||
|
||||
expr_parameters
|
||||
: expr_parameters COMMA expr_identifier
|
||||
{ $$ = std::move($1); $$->list.push_back(std::move($3)); }
|
||||
| expr_identifier
|
||||
{ $$ = std::make_unique<ast::expr_parameters>(@$); $$->list.push_back(std::move($1)); }
|
||||
|
|
||||
{ $$ = std::make_unique<ast::expr_parameters>(@$); }
|
||||
;
|
||||
|
||||
expr_arguments
|
||||
: expr_arguments_no_empty
|
||||
{ $$ = std::move($1); }
|
||||
|
|
||||
{ $$ = std::make_unique<ast::expr_arguments>(@$); }
|
||||
;
|
||||
|
||||
expr_arguments_no_empty
|
||||
: expr_arguments COMMA expr
|
||||
{ $$ = std::move($1); $$->list.push_back(std::move($3)); }
|
||||
| expr %prec ADD_ARRAY
|
||||
{ $$ = std::make_unique<ast::expr_arguments>(@$); $$->list.push_back(std::move($1)); }
|
||||
;
|
||||
|
||||
expr_isdefined
|
||||
: ISDEFINED LPAREN expr RPAREN
|
||||
{ $$ = std::make_unique<ast::expr_isdefined>(@$, std::move($3)); }
|
||||
;
|
||||
|
||||
expr_istrue
|
||||
: ISTRUE LPAREN expr RPAREN
|
||||
{ $$ = std::make_unique<ast::expr_istrue>(@$, std::move($3)); }
|
||||
;
|
||||
|
||||
expr_reference
|
||||
: DOUBLECOLON expr_identifier
|
||||
{ $$ = std::make_unique<ast::expr_reference>(@$, std::make_unique<ast::expr_path>(@$), std::move($2)); }
|
||||
| expr_path DOUBLECOLON expr_identifier
|
||||
{ $$ = std::make_unique<ast::expr_reference>(@$, std::move($1), std::move($3)); }
|
||||
;
|
||||
|
||||
expr_tuple
|
||||
: LBRACKET expr_tuple_arguments RBRACKET
|
||||
{ $$.as_node = std::move($2); }
|
||||
;
|
||||
|
||||
expr_tuple_arguments
|
||||
: expr_tuple_arguments COMMA expr_tuple_types
|
||||
{ $$ = std::move($1); $$->list.push_back(std::move($3)); }
|
||||
| expr_tuple_types
|
||||
{ $$ = std::make_unique<ast::expr_tuple>(@$); $$->list.push_back(std::move($1)); }
|
||||
;
|
||||
|
||||
expr_tuple_types
|
||||
: expr_array { $$.as_node = std::move($1); }
|
||||
| expr_field { $$.as_node = std::move($1); }
|
||||
| expr_identifier { $$.as_node = std::move($1); }
|
||||
;
|
||||
|
||||
expr_array
|
||||
: expr_object LBRACKET expr RBRACKET
|
||||
{ $$ = std::make_unique<ast::expr_array>(@$, std::move($1), std::move($3)); }
|
||||
;
|
||||
|
||||
expr_field
|
||||
: expr_object DOT expr_identifier_nosize
|
||||
{ $$ = std::make_unique<ast::expr_field>(@$, std::move($1), std::move($3)); }
|
||||
;
|
||||
|
||||
expr_size
|
||||
: expr_object DOT SIZE %prec SIZEOF
|
||||
{ $$ = std::make_unique<ast::expr_size>(@$, std::move($1)); }
|
||||
;
|
||||
|
||||
expr_paren
|
||||
: LPAREN expr RPAREN
|
||||
{ $$ = std::make_unique<ast::expr_paren>(@$, std::move($2)); }
|
||||
;
|
||||
|
||||
expr_object
|
||||
: expr_call { $$.as_node = std::move($1); }
|
||||
| expr_method { $$.as_node = std::move($1); }
|
||||
| expr_array { $$.as_node = std::move($1); }
|
||||
| expr_field { $$.as_node = std::move($1); }
|
||||
| expr_game { $$.as_node = std::move($1); }
|
||||
| expr_self { $$.as_node = std::move($1); }
|
||||
| expr_anim { $$.as_node = std::move($1); }
|
||||
| expr_level { $$.as_node = std::move($1); }
|
||||
| expr_identifier { $$.as_node = std::move($1); }
|
||||
;
|
||||
|
||||
expr_thisthread
|
||||
: THISTHREAD
|
||||
{ $$ = std::make_unique<ast::expr_thisthread>(@$); };
|
||||
;
|
||||
|
||||
expr_empty_array
|
||||
: LBRACKET RBRACKET
|
||||
{ $$ = std::make_unique<ast::expr_empty_array>(@$); };
|
||||
;
|
||||
|
||||
expr_undefined
|
||||
: UNDEFINED
|
||||
{ $$ = std::make_unique<ast::expr_undefined>(@$); };
|
||||
;
|
||||
|
||||
expr_game
|
||||
: GAME
|
||||
{ $$ = std::make_unique<ast::expr_game>(@$); };
|
||||
;
|
||||
|
||||
expr_self
|
||||
: SELF
|
||||
{ $$ = std::make_unique<ast::expr_self>(@$); };
|
||||
;
|
||||
|
||||
expr_anim
|
||||
: ANIM
|
||||
{ $$ = std::make_unique<ast::expr_anim>(@$); };
|
||||
;
|
||||
|
||||
expr_level
|
||||
: LEVEL
|
||||
{ $$ = std::make_unique<ast::expr_level>(@$); };
|
||||
;
|
||||
|
||||
expr_animation
|
||||
: MOD IDENTIFIER %prec ANIMREF
|
||||
{ $$ = std::make_unique<ast::expr_animation>(@$, $2); };
|
||||
;
|
||||
|
||||
expr_animtree
|
||||
: ANIMTREE
|
||||
{ $$ = std::make_unique<ast::expr_animtree>(@$); };
|
||||
;
|
||||
|
||||
expr_identifier_nosize
|
||||
: IDENTIFIER
|
||||
{ $$ = std::make_unique<ast::expr_identifier>(@$, $1); };
|
||||
;
|
||||
|
||||
expr_identifier
|
||||
: IDENTIFIER
|
||||
{ $$ = std::make_unique<ast::expr_identifier>(@$, $1); };
|
||||
| SIZE
|
||||
{ $$ = std::make_unique<ast::expr_identifier>(@$, "size"); };
|
||||
;
|
||||
|
||||
expr_path
|
||||
: IDENTIFIER
|
||||
{ $$ = std::make_unique<ast::expr_path>(@$, $1); };
|
||||
| PATH
|
||||
{ $$ = std::make_unique<ast::expr_path>(@$, $1); };
|
||||
;
|
||||
|
||||
expr_istring
|
||||
: ISTRING
|
||||
{ $$ = std::make_unique<ast::expr_istring>(@$, $1); };
|
||||
;
|
||||
|
||||
expr_string
|
||||
: STRING
|
||||
{ $$ = std::make_unique<ast::expr_string>(@$, $1); };
|
||||
;
|
||||
|
||||
expr_vector
|
||||
: LPAREN expr COMMA expr COMMA expr RPAREN
|
||||
{ $$ = std::make_unique<ast::expr_vector>(@$, std::move($2), std::move($4), std::move($6)); };
|
||||
;
|
||||
|
||||
expr_float
|
||||
: SUB FLOAT %prec NEG
|
||||
{ $$ = std::make_unique<ast::expr_float>(@$, "-" + $2); };
|
||||
| FLOAT
|
||||
{ $$ = std::make_unique<ast::expr_float>(@$, $1); };
|
||||
;
|
||||
|
||||
expr_integer
|
||||
: SUB INTEGER %prec NEG
|
||||
{ $$ = std::make_unique<ast::expr_integer>(@$, "-" + $2); };
|
||||
| INTEGER
|
||||
{ $$ = std::make_unique<ast::expr_integer>(@$, $1); };
|
||||
;
|
||||
|
||||
expr_false
|
||||
: FALSE
|
||||
{ $$ = std::make_unique<ast::expr_false>(@$); };
|
||||
;
|
||||
|
||||
expr_true
|
||||
: TRUE
|
||||
{ $$ = std::make_unique<ast::expr_true>(@$); };
|
||||
;
|
||||
|
||||
%%
|
||||
|
||||
void xsk::gsc::iw9::parser::error(const xsk::gsc::location& loc, const std::string& msg)
|
||||
{
|
||||
throw xsk::gsc::comp_error(loc, msg);
|
||||
}
|
@ -1,9 +0,0 @@
|
||||
generate: s1
|
||||
|
||||
clean:
|
||||
rm -rf ./parser.hpp
|
||||
rm -rf ./parser.cpp
|
||||
|
||||
s1: parser.ypp
|
||||
bison parser.ypp -Wcounterexamples
|
||||
mv parser.hpp parser.cpp ../../src/s1/xsk/
|
@ -1,898 +0,0 @@
|
||||
/* Copyright 2022 xensik. All rights reserved.
|
||||
//
|
||||
// Use of this source code is governed by a GNU GPLv3 license
|
||||
// that can be found in the LICENSE file.
|
||||
*/
|
||||
|
||||
%require "3.7"
|
||||
%skeleton "lalr1.cc"
|
||||
%language "c++"
|
||||
%output "parser.cpp"
|
||||
%defines "parser.hpp"
|
||||
%define api.prefix {S1}
|
||||
%define api.namespace {xsk::gsc::s1}
|
||||
%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 { xsk::gsc::s1::lexer& lexer }
|
||||
%parse-param { xsk::gsc::s1::lexer& lexer }
|
||||
%parse-param { xsk::gsc::ast::program::ptr& ast }
|
||||
|
||||
%code requires
|
||||
{
|
||||
#ifdef _MSC_VER
|
||||
#pragma warning(disable:4065)
|
||||
#pragma warning(disable:4127)
|
||||
#endif
|
||||
#include "s1.hpp"
|
||||
namespace xsk::gsc::s1 { class lexer; }
|
||||
}
|
||||
|
||||
%code top
|
||||
{
|
||||
#include "stdafx.hpp"
|
||||
#include "parser.hpp"
|
||||
#include "lexer.hpp"
|
||||
using namespace xsk::gsc;
|
||||
xsk::gsc::s1::parser::symbol_type S1lex(xsk::gsc::s1::lexer& lexer);
|
||||
}
|
||||
|
||||
%token SH_DEFINE "#define"
|
||||
%token SH_UNDEF "#undef"
|
||||
%token SH_IFDEF "#ifdef"
|
||||
%token SH_IFNDEF "#ifndef"
|
||||
%token SH_IF "#if"
|
||||
%token SH_ELIF "#elif"
|
||||
%token SH_ELSE "#else"
|
||||
%token SH_ENDIF "#endif"
|
||||
%token DEVBEGIN "/#"
|
||||
%token DEVEND "#/"
|
||||
%token INLINE "#inline"
|
||||
%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 DO "do"
|
||||
%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 BREAKPOINT "breakpoint"
|
||||
%token PROFBEGIN "prof_begin"
|
||||
%token PROFEND "prof_end"
|
||||
%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_MUL "*="
|
||||
%token ASSIGN_DIV "/="
|
||||
%token ASSIGN_MOD "%="
|
||||
%token ASSIGN_BW_OR "|="
|
||||
%token ASSIGN_BW_AND "&="
|
||||
%token ASSIGN_BW_EXOR "^="
|
||||
%token ASSIGN_RSHIFT ">>="
|
||||
%token ASSIGN_LSHIFT "<<="
|
||||
%token BITWISE_OR "|"
|
||||
%token BITWISE_AND "&"
|
||||
%token BITWISE_EXOR "^"
|
||||
%token ADD "+"
|
||||
%token SUB "-"
|
||||
%token MUL "*"
|
||||
%token DIV "/"
|
||||
%token MOD "%"
|
||||
%token <std::string> PATH "path"
|
||||
%token <std::string> IDENTIFIER "identifier"
|
||||
%token <std::string> STRING "string literal"
|
||||
%token <std::string> ISTRING "localized string"
|
||||
%token <std::string> FLOAT "float"
|
||||
%token <std::string> INTEGER "integer"
|
||||
|
||||
%type <ast::program::ptr> program
|
||||
%type <ast::include::ptr> include
|
||||
%type <ast::decl> declaration
|
||||
%type <ast::decl_usingtree::ptr> decl_usingtree
|
||||
%type <ast::decl_constant::ptr> decl_constant
|
||||
%type <ast::decl_thread::ptr> decl_thread
|
||||
%type <ast::stmt> stmt
|
||||
%type <ast::stmt> stmt_or_dev
|
||||
%type <ast::stmt_list::ptr> stmt_list
|
||||
%type <ast::stmt_list::ptr> stmt_or_dev_list
|
||||
%type <ast::stmt_dev::ptr> stmt_dev
|
||||
%type <ast::stmt_list::ptr> stmt_block
|
||||
%type <ast::stmt_expr::ptr> stmt_expr
|
||||
%type <ast::stmt_call::ptr> stmt_call
|
||||
%type <ast::stmt_assign::ptr> stmt_assign
|
||||
%type <ast::stmt_endon::ptr> stmt_endon
|
||||
%type <ast::stmt_notify::ptr> stmt_notify
|
||||
%type <ast::stmt_wait::ptr> stmt_wait
|
||||
%type <ast::stmt_waittill::ptr> stmt_waittill
|
||||
%type <ast::stmt_waittillmatch::ptr> stmt_waittillmatch
|
||||
%type <ast::stmt_waittillframeend::ptr> stmt_waittillframeend
|
||||
%type <ast::stmt_waitframe::ptr> stmt_waitframe
|
||||
%type <ast::stmt_if::ptr> stmt_if
|
||||
%type <ast::stmt_ifelse::ptr> stmt_ifelse
|
||||
%type <ast::stmt_while::ptr> stmt_while
|
||||
%type <ast::stmt_dowhile::ptr> stmt_dowhile
|
||||
%type <ast::stmt_for::ptr> stmt_for
|
||||
%type <ast::stmt_foreach::ptr> stmt_foreach
|
||||
%type <ast::stmt_switch::ptr> stmt_switch
|
||||
%type <ast::stmt_case::ptr> stmt_case
|
||||
%type <ast::stmt_default::ptr> stmt_default
|
||||
%type <ast::stmt_break::ptr> stmt_break
|
||||
%type <ast::stmt_continue::ptr> stmt_continue
|
||||
%type <ast::stmt_return::ptr> stmt_return
|
||||
%type <ast::stmt_breakpoint::ptr> stmt_breakpoint
|
||||
%type <ast::stmt_prof_begin::ptr> stmt_prof_begin
|
||||
%type <ast::stmt_prof_end::ptr> stmt_prof_end
|
||||
%type <ast::expr> expr
|
||||
%type <ast::expr> expr_or_empty
|
||||
%type <ast::expr> expr_assign
|
||||
%type <ast::expr> expr_increment
|
||||
%type <ast::expr> expr_decrement
|
||||
%type <ast::expr> expr_ternary
|
||||
%type <ast::expr> expr_binary
|
||||
%type <ast::expr> expr_primitive
|
||||
%type <ast::expr_complement::ptr> expr_complement
|
||||
%type <ast::expr_negate::ptr> expr_negate
|
||||
%type <ast::expr_not::ptr> expr_not
|
||||
%type <ast::expr_call::ptr> expr_call
|
||||
%type <ast::expr_method::ptr> expr_method
|
||||
%type <ast::call> expr_function
|
||||
%type <ast::call> expr_pointer
|
||||
%type <ast::expr_add_array::ptr> expr_add_array
|
||||
%type <ast::expr_parameters::ptr> expr_parameters
|
||||
%type <ast::expr_arguments::ptr> expr_arguments
|
||||
%type <ast::expr_arguments::ptr> expr_arguments_no_empty
|
||||
%type <ast::expr_reference::ptr> expr_reference
|
||||
%type <ast::expr> expr_tuple
|
||||
%type <ast::expr_tuple::ptr> expr_tuple_arguments
|
||||
%type <ast::expr> expr_tuple_types
|
||||
%type <ast::expr_array::ptr> expr_array
|
||||
%type <ast::expr_field::ptr> expr_field
|
||||
%type <ast::expr_size::ptr> expr_size
|
||||
%type <ast::expr_paren::ptr> expr_paren
|
||||
%type <ast::expr> expr_object
|
||||
%type <ast::expr_thisthread::ptr> expr_thisthread
|
||||
%type <ast::expr_empty_array::ptr> expr_empty_array
|
||||
%type <ast::expr_undefined::ptr> expr_undefined
|
||||
%type <ast::expr_game::ptr> expr_game
|
||||
%type <ast::expr_self::ptr> expr_self
|
||||
%type <ast::expr_anim::ptr> expr_anim
|
||||
%type <ast::expr_level::ptr> expr_level
|
||||
%type <ast::expr_animation::ptr> expr_animation
|
||||
%type <ast::expr_animtree::ptr> expr_animtree
|
||||
%type <ast::expr_identifier::ptr> expr_identifier_nosize
|
||||
%type <ast::expr_identifier::ptr> expr_identifier
|
||||
%type <ast::expr_path::ptr> expr_path
|
||||
%type <ast::expr_istring::ptr> expr_istring
|
||||
%type <ast::expr_string::ptr> expr_string
|
||||
%type <ast::expr_vector::ptr> expr_vector
|
||||
%type <ast::expr_float::ptr> expr_float
|
||||
%type <ast::expr_integer::ptr> expr_integer
|
||||
%type <ast::expr_false::ptr> expr_false
|
||||
%type <ast::expr_true::ptr> expr_true
|
||||
|
||||
%nonassoc SIZEOF
|
||||
%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_EXOR
|
||||
%left BITWISE_AND
|
||||
%left EQUALITY INEQUALITY
|
||||
%left LESS GREATER LESS_EQUAL GREATER_EQUAL
|
||||
%left LSHIFT RSHIFT
|
||||
%left ADD SUB
|
||||
%left MUL 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<ast::program>(@$); }
|
||||
;
|
||||
|
||||
program
|
||||
: program inline
|
||||
{ $$ = std::move($1); }
|
||||
| program include
|
||||
{ $$ = std::move($1); $$->includes.push_back(std::move($2)); }
|
||||
| program declaration
|
||||
{ $$ = std::move($1); $$->declarations.push_back(std::move($2)); }
|
||||
| inline
|
||||
{ $$ = std::make_unique<ast::program>(@$); }
|
||||
| include
|
||||
{ $$ = std::make_unique<ast::program>(@$); $$->includes.push_back(std::move($1)); }
|
||||
| declaration
|
||||
{ $$ = std::make_unique<ast::program>(@$); $$->declarations.push_back(std::move($1)); }
|
||||
;
|
||||
|
||||
inline
|
||||
: INLINE expr_path SEMICOLON { lexer.push_header($2->value); }
|
||||
;
|
||||
|
||||
include
|
||||
: INCLUDE expr_path SEMICOLON
|
||||
{ $$ = std::make_unique<ast::include>(@$, std::move($2)); }
|
||||
;
|
||||
|
||||
declaration
|
||||
: DEVBEGIN { $$.as_dev_begin = std::make_unique<ast::decl_dev_begin>(@$); }
|
||||
| DEVEND { $$.as_dev_end = std::make_unique<ast::decl_dev_end>(@$); }
|
||||
| decl_usingtree { $$.as_usingtree = std::move($1); }
|
||||
| decl_constant { $$.as_constant = std::move($1); }
|
||||
| decl_thread { $$.as_thread = std::move($1); }
|
||||
;
|
||||
|
||||
decl_usingtree
|
||||
: USINGTREE LPAREN expr_string RPAREN SEMICOLON
|
||||
{ lexer.ban_header(@$); $$ = std::make_unique<ast::decl_usingtree>(@$, std::move($3)); }
|
||||
;
|
||||
|
||||
decl_constant
|
||||
: expr_identifier ASSIGN expr SEMICOLON
|
||||
{ $$ = std::make_unique<ast::decl_constant>(@$, std::move($1), std::move($3)); }
|
||||
;
|
||||
|
||||
decl_thread
|
||||
: expr_identifier LPAREN expr_parameters RPAREN stmt_block
|
||||
{ lexer.ban_header(@$); $$ = std::make_unique<ast::decl_thread>(@$, std::move($1), std::move($3), std::move($5)); }
|
||||
;
|
||||
|
||||
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_dowhile { $$.as_dowhile = 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_breakpoint { $$.as_breakpoint = std::move($1); }
|
||||
| stmt_prof_begin { $$.as_prof_begin = std::move($1); }
|
||||
| stmt_prof_end { $$.as_prof_end = std::move($1); }
|
||||
;
|
||||
|
||||
stmt_or_dev
|
||||
: stmt { $$ = std::move($1); }
|
||||
| stmt_dev { $$.as_dev = std::move($1); }
|
||||
;
|
||||
|
||||
stmt_list
|
||||
: stmt_list stmt
|
||||
{ $$ = std::move($1); $$->list.push_back(std::move($2)); }
|
||||
| stmt
|
||||
{ $$ = std::make_unique<ast::stmt_list>(@$); $$->list.push_back(std::move($1)); }
|
||||
;
|
||||
|
||||
stmt_or_dev_list
|
||||
: stmt_or_dev_list stmt_or_dev
|
||||
{ $$ = std::move($1); $$->list.push_back(std::move($2)); }
|
||||
| stmt_or_dev
|
||||
{ $$ = std::make_unique<ast::stmt_list>(@$); $$->list.push_back(std::move($1)); }
|
||||
;
|
||||
|
||||
stmt_dev
|
||||
: DEVBEGIN stmt_list DEVEND { $$ = std::make_unique<ast::stmt_dev>(@$, std::move($2)); }
|
||||
| DEVBEGIN DEVEND { $$ = std::make_unique<ast::stmt_dev>(@$, std::make_unique<ast::stmt_list>(@$)); }
|
||||
;
|
||||
|
||||
stmt_block
|
||||
: LBRACE stmt_or_dev_list RBRACE { $$ = std::move($2); }
|
||||
| LBRACE RBRACE { $$ = std::make_unique<ast::stmt_list>(@$); }
|
||||
;
|
||||
|
||||
stmt_expr
|
||||
: expr_assign
|
||||
{ $$ = std::make_unique<ast::stmt_expr>(@$, std::move($1)); }
|
||||
| expr_increment
|
||||
{ $$ = std::make_unique<ast::stmt_expr>(@$, std::move($1)); }
|
||||
| expr_decrement
|
||||
{ $$ = std::make_unique<ast::stmt_expr>(@$, std::move($1)); }
|
||||
|
|
||||
{ $$ = std::make_unique<ast::stmt_expr>(@$, std::make_unique<ast::node>(@$)); }
|
||||
;
|
||||
|
||||
stmt_call
|
||||
: expr_call SEMICOLON
|
||||
{ $$ = std::make_unique<ast::stmt_call>(@$, ast::expr(std::move($1))); }
|
||||
| expr_method SEMICOLON
|
||||
{ $$ = std::make_unique<ast::stmt_call>(@$, ast::expr(std::move($1))); }
|
||||
;
|
||||
|
||||
stmt_assign
|
||||
: expr_assign SEMICOLON
|
||||
{ $$ = std::make_unique<ast::stmt_assign>(@$, std::move($1)); }
|
||||
| expr_increment SEMICOLON
|
||||
{ $$ = std::make_unique<ast::stmt_assign>(@$, std::move($1)); }
|
||||
| expr_decrement SEMICOLON
|
||||
{ $$ = std::make_unique<ast::stmt_assign>(@$, std::move($1)); }
|
||||
;
|
||||
|
||||
stmt_endon
|
||||
: expr_object ENDON LPAREN expr RPAREN SEMICOLON
|
||||
{ $$ = std::make_unique<ast::stmt_endon>(@$, std::move($1), std::move($4)); }
|
||||
;
|
||||
|
||||
stmt_notify
|
||||
: expr_object NOTIFY LPAREN expr COMMA expr_arguments_no_empty RPAREN SEMICOLON
|
||||
{ $$ = std::make_unique<ast::stmt_notify>(@$, std::move($1), std::move($4), std::move($6)); }
|
||||
| expr_object NOTIFY LPAREN expr RPAREN SEMICOLON
|
||||
{ $$ = std::make_unique<ast::stmt_notify>(@$, std::move($1), std::move($4), std::make_unique<ast::expr_arguments>(@$)); }
|
||||
;
|
||||
|
||||
stmt_wait
|
||||
: WAIT expr SEMICOLON
|
||||
{ $$ = std::make_unique<ast::stmt_wait>(@$, std::move($2)); }
|
||||
;
|
||||
|
||||
stmt_waittill
|
||||
: expr_object WAITTILL LPAREN expr COMMA expr_arguments_no_empty RPAREN SEMICOLON
|
||||
{ $$ = std::make_unique<ast::stmt_waittill>(@$, std::move($1), std::move($4), std::move($6)); }
|
||||
| expr_object WAITTILL LPAREN expr RPAREN SEMICOLON
|
||||
{ $$ = std::make_unique<ast::stmt_waittill>(@$, std::move($1), std::move($4), std::make_unique<ast::expr_arguments>(@$)); }
|
||||
;
|
||||
|
||||
stmt_waittillmatch
|
||||
: expr_object WAITTILLMATCH LPAREN expr COMMA expr_arguments_no_empty RPAREN SEMICOLON
|
||||
{ $$ = std::make_unique<ast::stmt_waittillmatch>(@$, std::move($1), std::move($4), std::move($6)); }
|
||||
| expr_object WAITTILLMATCH LPAREN expr RPAREN SEMICOLON
|
||||
{ $$ = std::make_unique<ast::stmt_waittillmatch>(@$, std::move($1), std::move($4), std::make_unique<ast::expr_arguments>(@$)); }
|
||||
;
|
||||
|
||||
stmt_waittillframeend
|
||||
: WAITTILLFRAMEEND SEMICOLON
|
||||
{ $$ = std::make_unique<ast::stmt_waittillframeend>(@$); }
|
||||
;
|
||||
|
||||
stmt_waitframe
|
||||
: WAITFRAME SEMICOLON
|
||||
{ $$ = std::make_unique<ast::stmt_waitframe>(@$); }
|
||||
| WAITFRAME LPAREN RPAREN SEMICOLON
|
||||
{ $$ = std::make_unique<ast::stmt_waitframe>(@$); }
|
||||
;
|
||||
|
||||
stmt_if
|
||||
: IF LPAREN expr RPAREN stmt %prec THEN
|
||||
{ $$ = std::make_unique<ast::stmt_if>(@$, std::move($3), std::move($5)); }
|
||||
;
|
||||
|
||||
stmt_ifelse
|
||||
: IF LPAREN expr RPAREN stmt ELSE stmt
|
||||
{ $$ = std::make_unique<ast::stmt_ifelse>(@$, std::move($3), std::move($5), std::move($7)); }
|
||||
;
|
||||
|
||||
stmt_while
|
||||
: WHILE LPAREN expr RPAREN stmt
|
||||
{ $$ = std::make_unique<ast::stmt_while>(@$, std::move($3), std::move($5)); }
|
||||
;
|
||||
|
||||
stmt_dowhile
|
||||
: DO stmt WHILE LPAREN expr RPAREN SEMICOLON
|
||||
{ $$ = std::make_unique<ast::stmt_dowhile>(@$, std::move($5), std::move($2)); }
|
||||
;
|
||||
|
||||
stmt_for
|
||||
: FOR LPAREN stmt_expr SEMICOLON expr_or_empty SEMICOLON stmt_expr RPAREN stmt
|
||||
{ $$ = std::make_unique<ast::stmt_for>(@$, ast::stmt(std::move($3)), std::move($5), ast::stmt(std::move($7)), std::move($9)); }
|
||||
;
|
||||
|
||||
stmt_foreach
|
||||
: FOREACH LPAREN expr_identifier IN expr RPAREN stmt
|
||||
{ $$ = std::make_unique<ast::stmt_foreach>(@$, ast::expr(std::move($3)), std::move($5), std::move($7)); }
|
||||
| FOREACH LPAREN expr_identifier COMMA expr_identifier IN expr RPAREN stmt
|
||||
{ $$ = std::make_unique<ast::stmt_foreach>(@$, ast::expr(std::move($3)), ast::expr(std::move($5)), std::move($7), std::move($9)); }
|
||||
;
|
||||
|
||||
stmt_switch
|
||||
: SWITCH LPAREN expr RPAREN stmt_block
|
||||
{ $$ = std::make_unique<ast::stmt_switch>(@$, std::move($3), std::move($5)); }
|
||||
;
|
||||
|
||||
stmt_case
|
||||
: CASE expr_integer COLON
|
||||
{ $$ = std::make_unique<ast::stmt_case>(@$, ast::expr(std::move($2)), std::make_unique<ast::stmt_list>(@$)); }
|
||||
| CASE expr_string COLON
|
||||
{ $$ = std::make_unique<ast::stmt_case>(@$, ast::expr(std::move($2)), std::make_unique<ast::stmt_list>(@$)); }
|
||||
;
|
||||
|
||||
stmt_default
|
||||
: DEFAULT COLON
|
||||
{ $$ = std::make_unique<ast::stmt_default>(@$, std::make_unique<ast::stmt_list>(@$)); }
|
||||
;
|
||||
|
||||
stmt_break
|
||||
: BREAK SEMICOLON
|
||||
{ $$ = std::make_unique<ast::stmt_break>(@$); }
|
||||
;
|
||||
|
||||
stmt_continue
|
||||
: CONTINUE SEMICOLON
|
||||
{ $$ = std::make_unique<ast::stmt_continue>(@$); }
|
||||
;
|
||||
|
||||
stmt_return
|
||||
: RETURN expr SEMICOLON
|
||||
{ $$ = std::make_unique<ast::stmt_return>(@$, std::move($2)); }
|
||||
| RETURN SEMICOLON
|
||||
{ $$ = std::make_unique<ast::stmt_return>(@$, std::make_unique<ast::node>(@$)); }
|
||||
;
|
||||
|
||||
stmt_breakpoint
|
||||
: BREAKPOINT SEMICOLON
|
||||
{ $$ = std::make_unique<ast::stmt_breakpoint>(@$); }
|
||||
;
|
||||
|
||||
stmt_prof_begin
|
||||
: PROFBEGIN LPAREN expr_arguments RPAREN SEMICOLON
|
||||
{ $$ = std::make_unique<ast::stmt_prof_begin>(@$, std::move($3)); }
|
||||
;
|
||||
|
||||
stmt_prof_end
|
||||
: PROFEND LPAREN expr_arguments RPAREN SEMICOLON
|
||||
{ $$ = std::make_unique<ast::stmt_prof_end>(@$, std::move($3)); }
|
||||
;
|
||||
|
||||
expr
|
||||
: expr_ternary { $$ = std::move($1); }
|
||||
| expr_binary { $$ = std::move($1); }
|
||||
| expr_primitive { $$ = std::move($1); }
|
||||
;
|
||||
|
||||
expr_or_empty
|
||||
: expr { $$ = std::move($1); }
|
||||
| { $$.as_node = std::make_unique<ast::node>(@$); }
|
||||
;
|
||||
|
||||
expr_assign
|
||||
: expr_tuple ASSIGN expr
|
||||
{ $$.as_node = std::make_unique<ast::expr_assign_equal>(@$, std::move($1), std::move($3)); }
|
||||
| expr_object ASSIGN expr
|
||||
{ $$.as_node = std::make_unique<ast::expr_assign_equal>(@$, std::move($1), std::move($3)); }
|
||||
| expr_object ASSIGN_BW_OR expr
|
||||
{ $$.as_node = std::make_unique<ast::expr_assign_bitwise_or>(@$, std::move($1), std::move($3)); }
|
||||
| expr_object ASSIGN_BW_AND expr
|
||||
{ $$.as_node = std::make_unique<ast::expr_assign_bitwise_and>(@$, std::move($1), std::move($3)); }
|
||||
| expr_object ASSIGN_BW_EXOR expr
|
||||
{ $$.as_node = std::make_unique<ast::expr_assign_bitwise_exor>(@$, std::move($1), std::move($3)); }
|
||||
| expr_object ASSIGN_LSHIFT expr
|
||||
{ $$.as_node = std::make_unique<ast::expr_assign_shift_left>(@$, std::move($1),std::move( $3)); }
|
||||
| expr_object ASSIGN_RSHIFT expr
|
||||
{ $$.as_node = std::make_unique<ast::expr_assign_shift_right>(@$, std::move($1), std::move($3)); }
|
||||
| expr_object ASSIGN_ADD expr
|
||||
{ $$.as_node = std::make_unique<ast::expr_assign_add>(@$, std::move($1), std::move($3)); }
|
||||
| expr_object ASSIGN_SUB expr
|
||||
{ $$.as_node = std::make_unique<ast::expr_assign_sub>(@$, std::move($1), std::move($3)); }
|
||||
| expr_object ASSIGN_MUL expr
|
||||
{ $$.as_node = std::make_unique<ast::expr_assign_mul>(@$, std::move($1), std::move($3)); }
|
||||
| expr_object ASSIGN_DIV expr
|
||||
{ $$.as_node = std::make_unique<ast::expr_assign_div>(@$, std::move($1), std::move($3)); }
|
||||
| expr_object ASSIGN_MOD expr
|
||||
{ $$.as_node = std::make_unique<ast::expr_assign_mod>(@$, std::move($1), std::move($3)); }
|
||||
;
|
||||
|
||||
expr_increment
|
||||
: INCREMENT expr_object %prec PREINC
|
||||
{ $$.as_node = std::make_unique<ast::expr_increment>(@$, std::move($2), true); }
|
||||
| expr_object INCREMENT %prec POSTINC
|
||||
{ $$.as_node = std::make_unique<ast::expr_increment>(@$, std::move($1), false); }
|
||||
;
|
||||
|
||||
expr_decrement
|
||||
: DECREMENT expr_object %prec PREDEC
|
||||
{ $$.as_node = std::make_unique<ast::expr_decrement>(@$, std::move($2), true); }
|
||||
| expr_object DECREMENT %prec POSTDEC
|
||||
{ $$.as_node = std::make_unique<ast::expr_decrement>(@$, std::move($1), false); }
|
||||
;
|
||||
|
||||
expr_ternary
|
||||
: expr QMARK expr COLON expr %prec TERN
|
||||
{ $$.as_node = std::make_unique<ast::expr_ternary>(@$, std::move($1), std::move($3), std::move($5)); }
|
||||
;
|
||||
|
||||
expr_binary
|
||||
: expr OR expr
|
||||
{ $$.as_node = std::make_unique<ast::expr_or>(@$, std::move($1), std::move($3)); }
|
||||
| expr AND expr
|
||||
{ $$.as_node = std::make_unique<ast::expr_and>(@$, std::move($1), std::move($3)); }
|
||||
| expr EQUALITY expr
|
||||
{ $$.as_node = std::make_unique<ast::expr_equality>(@$, std::move($1), std::move($3)); }
|
||||
| expr INEQUALITY expr
|
||||
{ $$.as_node = std::make_unique<ast::expr_inequality>(@$, std::move($1), std::move($3)); }
|
||||
| expr LESS_EQUAL expr
|
||||
{ $$.as_node = std::make_unique<ast::expr_less_equal>(@$, std::move($1), std::move($3)); }
|
||||
| expr GREATER_EQUAL expr
|
||||
{ $$.as_node = std::make_unique<ast::expr_greater_equal>(@$, std::move($1), std::move($3)); }
|
||||
| expr LESS expr
|
||||
{ $$.as_node = std::make_unique<ast::expr_less>(@$, std::move($1), std::move($3)); }
|
||||
| expr GREATER expr
|
||||
{ $$.as_node = std::make_unique<ast::expr_greater>(@$, std::move($1), std::move($3)); }
|
||||
| expr BITWISE_OR expr
|
||||
{ $$.as_node = std::make_unique<ast::expr_bitwise_or>(@$, std::move($1), std::move($3)); }
|
||||
| expr BITWISE_AND expr
|
||||
{ $$.as_node = std::make_unique<ast::expr_bitwise_and>(@$, std::move($1), std::move($3)); }
|
||||
| expr BITWISE_EXOR expr
|
||||
{ $$.as_node = std::make_unique<ast::expr_bitwise_exor>(@$, std::move($1), std::move($3)); }
|
||||
| expr LSHIFT expr
|
||||
{ $$.as_node = std::make_unique<ast::expr_shift_left>(@$, std::move($1), std::move($3)); }
|
||||
| expr RSHIFT expr
|
||||
{ $$.as_node = std::make_unique<ast::expr_shift_right>(@$, std::move($1), std::move($3)); }
|
||||
| expr ADD expr
|
||||
{ $$.as_node = std::make_unique<ast::expr_add>(@$, std::move($1), std::move($3)); }
|
||||
| expr SUB expr
|
||||
{ $$.as_node = std::make_unique<ast::expr_sub>(@$, std::move($1), std::move($3)); }
|
||||
| expr MUL expr
|
||||
{ $$.as_node = std::make_unique<ast::expr_mul>(@$, std::move($1), std::move($3)); }
|
||||
| expr DIV expr
|
||||
{ $$.as_node = std::make_unique<ast::expr_div>(@$, std::move($1), std::move($3)); }
|
||||
| expr MOD expr
|
||||
{ $$.as_node = std::make_unique<ast::expr_mod>(@$, std::move($1), std::move($3)); }
|
||||
;
|
||||
|
||||
expr_primitive
|
||||
: expr_complement { $$.as_node = std::move($1); }
|
||||
| expr_negate { $$.as_node = std::move($1); }
|
||||
| expr_not { $$.as_node = std::move($1); }
|
||||
| expr_call { $$.as_node = std::move($1); }
|
||||
| expr_method { $$.as_node = std::move($1); }
|
||||
| expr_add_array { $$.as_node = std::move($1); }
|
||||
| expr_reference { $$.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); }
|
||||
| expr_paren { $$.as_node = std::move($1); }
|
||||
| expr_thisthread { $$.as_node = std::move($1); }
|
||||
| expr_empty_array { $$.as_node = std::move($1); }
|
||||
| expr_undefined { $$.as_node = std::move($1); }
|
||||
| expr_game { $$.as_node = std::move($1); }
|
||||
| expr_self { $$.as_node = std::move($1); }
|
||||
| expr_anim { $$.as_node = std::move($1); }
|
||||
| expr_level { $$.as_node = std::move($1); }
|
||||
| expr_animation { $$.as_node = std::move($1); }
|
||||
| expr_animtree { $$.as_node = std::move($1); }
|
||||
| expr_identifier { $$.as_node = std::move($1); }
|
||||
| expr_istring { $$.as_node = std::move($1); }
|
||||
| expr_string { $$.as_node = std::move($1); }
|
||||
| expr_vector { $$.as_node = std::move($1); }
|
||||
| expr_float { $$.as_node = std::move($1); }
|
||||
| expr_integer { $$.as_node = std::move($1); }
|
||||
| expr_false { $$.as_node = std::move($1); }
|
||||
| expr_true { $$.as_node = std::move($1); }
|
||||
;
|
||||
|
||||
expr_complement
|
||||
: COMPLEMENT expr
|
||||
{ $$ = std::make_unique<ast::expr_complement>(@$, std::move($2)); }
|
||||
;
|
||||
|
||||
expr_negate
|
||||
: SUB expr_identifier %prec NEG
|
||||
{ $$ = std::make_unique<ast::expr_negate>(@$, ast::expr(std::move($2))); }
|
||||
| SUB expr_paren %prec NEG
|
||||
{ $$ = std::make_unique<ast::expr_negate>(@$, ast::expr(std::move($2))); }
|
||||
| SUB expr_array %prec NEG
|
||||
{ $$ = std::make_unique<ast::expr_negate>(@$, ast::expr(std::move($2))); }
|
||||
| SUB expr_field %prec NEG
|
||||
{ $$ = std::make_unique<ast::expr_negate>(@$, ast::expr(std::move($2))); }
|
||||
;
|
||||
|
||||
expr_not
|
||||
: NOT expr
|
||||
{ $$ = std::make_unique<ast::expr_not>(@$, std::move($2)); }
|
||||
;
|
||||
|
||||
expr_call
|
||||
: expr_function { $$ = std::make_unique<ast::expr_call>(@$, std::move($1)); }
|
||||
| expr_pointer { $$ = std::make_unique<ast::expr_call>(@$, std::move($1)); }
|
||||
;
|
||||
expr_method
|
||||
: expr_object expr_function { $$ = std::make_unique<ast::expr_method>(@$, std::move($1), std::move($2)); }
|
||||
| expr_object expr_pointer { $$ = std::make_unique<ast::expr_method>(@$, std::move($1), std::move($2)); }
|
||||
;
|
||||
|
||||
expr_function
|
||||
: expr_identifier LPAREN expr_arguments RPAREN
|
||||
{ $$.as_function = std::make_unique<ast::expr_function>(@$, std::make_unique<ast::expr_path>(@$), std::move($1), std::move($3), ast::call::mode::normal); }
|
||||
| expr_path DOUBLECOLON expr_identifier LPAREN expr_arguments RPAREN
|
||||
{ $$.as_function = std::make_unique<ast::expr_function>(@$, std::move($1), std::move($3), std::move($5), ast::call::mode::normal); }
|
||||
| THREAD expr_identifier LPAREN expr_arguments RPAREN
|
||||
{ $$.as_function = std::make_unique<ast::expr_function>(@$, std::make_unique<ast::expr_path>(@$), std::move($2), std::move($4), ast::call::mode::thread); }
|
||||
| THREAD expr_path DOUBLECOLON expr_identifier LPAREN expr_arguments RPAREN
|
||||
{ $$.as_function = std::make_unique<ast::expr_function>(@$, std::move($2), std::move($4), std::move($6), ast::call::mode::thread); }
|
||||
| CHILDTHREAD expr_identifier LPAREN expr_arguments RPAREN
|
||||
{ $$.as_function = std::make_unique<ast::expr_function>(@$, std::make_unique<ast::expr_path>(@$), std::move($2), std::move($4), ast::call::mode::childthread); }
|
||||
| CHILDTHREAD expr_path DOUBLECOLON expr_identifier LPAREN expr_arguments RPAREN
|
||||
{ $$.as_function = std::make_unique<ast::expr_function>(@$, std::move($2), std::move($4), std::move($6), ast::call::mode::childthread); }
|
||||
;
|
||||
|
||||
expr_pointer
|
||||
: LBRACKET LBRACKET expr RBRACKET RBRACKET LPAREN expr_arguments RPAREN
|
||||
{ $$.as_pointer = std::make_unique<ast::expr_pointer>(@$, std::move($3), std::move($7), ast::call::mode::normal); }
|
||||
| THREAD LBRACKET LBRACKET expr RBRACKET RBRACKET LPAREN expr_arguments RPAREN
|
||||
{ $$.as_pointer = std::make_unique<ast::expr_pointer>(@$, std::move($4), std::move($8), ast::call::mode::thread); }
|
||||
| CHILDTHREAD LBRACKET LBRACKET expr RBRACKET RBRACKET LPAREN expr_arguments RPAREN
|
||||
{ $$.as_pointer = std::make_unique<ast::expr_pointer>(@$, std::move($4), std::move($8), ast::call::mode::childthread); }
|
||||
| CALL LBRACKET LBRACKET expr RBRACKET RBRACKET LPAREN expr_arguments RPAREN
|
||||
{ $$.as_pointer = std::make_unique<ast::expr_pointer>(@$, std::move($4), std::move($8), ast::call::mode::builtin); }
|
||||
;
|
||||
|
||||
expr_add_array
|
||||
: LBRACKET expr_arguments_no_empty RBRACKET
|
||||
{ $$ = std::make_unique<ast::expr_add_array>(@$, std::move($2)); }
|
||||
;
|
||||
|
||||
expr_parameters
|
||||
: expr_parameters COMMA expr_identifier
|
||||
{ $$ = std::move($1); $$->list.push_back(std::move($3)); }
|
||||
| expr_identifier
|
||||
{ $$ = std::make_unique<ast::expr_parameters>(@$); $$->list.push_back(std::move($1)); }
|
||||
|
|
||||
{ $$ = std::make_unique<ast::expr_parameters>(@$); }
|
||||
;
|
||||
|
||||
expr_arguments
|
||||
: expr_arguments_no_empty
|
||||
{ $$ = std::move($1); }
|
||||
|
|
||||
{ $$ = std::make_unique<ast::expr_arguments>(@$); }
|
||||
;
|
||||
|
||||
expr_arguments_no_empty
|
||||
: expr_arguments COMMA expr
|
||||
{ $$ = std::move($1); $$->list.push_back(std::move($3)); }
|
||||
| expr %prec ADD_ARRAY
|
||||
{ $$ = std::make_unique<ast::expr_arguments>(@$); $$->list.push_back(std::move($1)); }
|
||||
;
|
||||
|
||||
expr_reference
|
||||
: DOUBLECOLON expr_identifier
|
||||
{ $$ = std::make_unique<ast::expr_reference>(@$, std::make_unique<ast::expr_path>(@$), std::move($2)); }
|
||||
| expr_path DOUBLECOLON expr_identifier
|
||||
{ $$ = std::make_unique<ast::expr_reference>(@$, std::move($1), std::move($3)); }
|
||||
;
|
||||
|
||||
expr_tuple
|
||||
: LBRACKET expr_tuple_arguments RBRACKET
|
||||
{ $$.as_node = std::move($2); }
|
||||
;
|
||||
|
||||
expr_tuple_arguments
|
||||
: expr_tuple_arguments COMMA expr_tuple_types
|
||||
{ $$ = std::move($1); $$->list.push_back(std::move($3)); }
|
||||
| expr_tuple_types
|
||||
{ $$ = std::make_unique<ast::expr_tuple>(@$); $$->list.push_back(std::move($1)); }
|
||||
;
|
||||
|
||||
expr_tuple_types
|
||||
: expr_array { $$.as_node = std::move($1); }
|
||||
| expr_field { $$.as_node = std::move($1); }
|
||||
| expr_identifier { $$.as_node = std::move($1); }
|
||||
;
|
||||
|
||||
expr_array
|
||||
: expr_object LBRACKET expr RBRACKET
|
||||
{ $$ = std::make_unique<ast::expr_array>(@$, std::move($1), std::move($3)); }
|
||||
;
|
||||
|
||||
expr_field
|
||||
: expr_object DOT expr_identifier_nosize
|
||||
{ $$ = std::make_unique<ast::expr_field>(@$, std::move($1), std::move($3)); }
|
||||
;
|
||||
|
||||
expr_size
|
||||
: expr_object DOT SIZE %prec SIZEOF
|
||||
{ $$ = std::make_unique<ast::expr_size>(@$, std::move($1)); }
|
||||
;
|
||||
|
||||
expr_paren
|
||||
: LPAREN expr RPAREN
|
||||
{ $$ = std::make_unique<ast::expr_paren>(@$, std::move($2)); }
|
||||
;
|
||||
|
||||
expr_object
|
||||
: expr_call { $$.as_node = std::move($1); }
|
||||
| expr_method { $$.as_node = std::move($1); }
|
||||
| expr_array { $$.as_node = std::move($1); }
|
||||
| expr_field { $$.as_node = std::move($1); }
|
||||
| expr_game { $$.as_node = std::move($1); }
|
||||
| expr_self { $$.as_node = std::move($1); }
|
||||
| expr_anim { $$.as_node = std::move($1); }
|
||||
| expr_level { $$.as_node = std::move($1); }
|
||||
| expr_identifier { $$.as_node = std::move($1); }
|
||||
;
|
||||
|
||||
expr_thisthread
|
||||
: THISTHREAD
|
||||
{ $$ = std::make_unique<ast::expr_thisthread>(@$); };
|
||||
;
|
||||
|
||||
expr_empty_array
|
||||
: LBRACKET RBRACKET
|
||||
{ $$ = std::make_unique<ast::expr_empty_array>(@$); };
|
||||
;
|
||||
|
||||
expr_undefined
|
||||
: UNDEFINED
|
||||
{ $$ = std::make_unique<ast::expr_undefined>(@$); };
|
||||
;
|
||||
|
||||
expr_game
|
||||
: GAME
|
||||
{ $$ = std::make_unique<ast::expr_game>(@$); };
|
||||
;
|
||||
|
||||
expr_self
|
||||
: SELF
|
||||
{ $$ = std::make_unique<ast::expr_self>(@$); };
|
||||
;
|
||||
|
||||
expr_anim
|
||||
: ANIM
|
||||
{ $$ = std::make_unique<ast::expr_anim>(@$); };
|
||||
;
|
||||
|
||||
expr_level
|
||||
: LEVEL
|
||||
{ $$ = std::make_unique<ast::expr_level>(@$); };
|
||||
;
|
||||
|
||||
expr_animation
|
||||
: MOD IDENTIFIER %prec ANIMREF
|
||||
{ $$ = std::make_unique<ast::expr_animation>(@$, $2); };
|
||||
;
|
||||
|
||||
expr_animtree
|
||||
: ANIMTREE
|
||||
{ $$ = std::make_unique<ast::expr_animtree>(@$); };
|
||||
;
|
||||
|
||||
expr_identifier_nosize
|
||||
: IDENTIFIER
|
||||
{ $$ = std::make_unique<ast::expr_identifier>(@$, $1); };
|
||||
;
|
||||
|
||||
expr_identifier
|
||||
: IDENTIFIER
|
||||
{ $$ = std::make_unique<ast::expr_identifier>(@$, $1); };
|
||||
| SIZE
|
||||
{ $$ = std::make_unique<ast::expr_identifier>(@$, "size"); };
|
||||
;
|
||||
|
||||
expr_path
|
||||
: IDENTIFIER
|
||||
{ $$ = std::make_unique<ast::expr_path>(@$, $1); };
|
||||
| PATH
|
||||
{ $$ = std::make_unique<ast::expr_path>(@$, $1); };
|
||||
;
|
||||
|
||||
expr_istring
|
||||
: ISTRING
|
||||
{ $$ = std::make_unique<ast::expr_istring>(@$, $1); };
|
||||
;
|
||||
|
||||
expr_string
|
||||
: STRING
|
||||
{ $$ = std::make_unique<ast::expr_string>(@$, $1); };
|
||||
;
|
||||
|
||||
expr_vector
|
||||
: LPAREN expr COMMA expr COMMA expr RPAREN
|
||||
{ $$ = std::make_unique<ast::expr_vector>(@$, std::move($2), std::move($4), std::move($6)); };
|
||||
;
|
||||
|
||||
expr_float
|
||||
: SUB FLOAT %prec NEG
|
||||
{ $$ = std::make_unique<ast::expr_float>(@$, "-" + $2); };
|
||||
| FLOAT
|
||||
{ $$ = std::make_unique<ast::expr_float>(@$, $1); };
|
||||
;
|
||||
|
||||
expr_integer
|
||||
: SUB INTEGER %prec NEG
|
||||
{ $$ = std::make_unique<ast::expr_integer>(@$, "-" + $2); };
|
||||
| INTEGER
|
||||
{ $$ = std::make_unique<ast::expr_integer>(@$, $1); };
|
||||
;
|
||||
|
||||
expr_false
|
||||
: FALSE
|
||||
{ $$ = std::make_unique<ast::expr_false>(@$); };
|
||||
;
|
||||
|
||||
expr_true
|
||||
: TRUE
|
||||
{ $$ = std::make_unique<ast::expr_true>(@$); };
|
||||
;
|
||||
|
||||
%%
|
||||
|
||||
void xsk::gsc::s1::parser::error(const xsk::gsc::location& loc, const std::string& msg)
|
||||
{
|
||||
throw xsk::gsc::comp_error(loc, msg);
|
||||
}
|
@ -1,9 +0,0 @@
|
||||
generate: s2
|
||||
|
||||
clean:
|
||||
rm -rf ./parser.hpp
|
||||
rm -rf ./parser.cpp
|
||||
|
||||
s2: parser.ypp
|
||||
bison parser.ypp -Wcounterexamples
|
||||
mv parser.hpp parser.cpp ../../src/s2/xsk/
|
@ -1,898 +0,0 @@
|
||||
/* Copyright 2022 xensik. All rights reserved.
|
||||
//
|
||||
// Use of this source code is governed by a GNU GPLv3 license
|
||||
// that can be found in the LICENSE file.
|
||||
*/
|
||||
|
||||
%require "3.7"
|
||||
%skeleton "lalr1.cc"
|
||||
%language "c++"
|
||||
%output "parser.cpp"
|
||||
%defines "parser.hpp"
|
||||
%define api.prefix {S2}
|
||||
%define api.namespace {xsk::gsc::s2}
|
||||
%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 { xsk::gsc::s2::lexer& lexer }
|
||||
%parse-param { xsk::gsc::s2::lexer& lexer }
|
||||
%parse-param { xsk::gsc::ast::program::ptr& ast }
|
||||
|
||||
%code requires
|
||||
{
|
||||
#ifdef _MSC_VER
|
||||
#pragma warning(disable:4065)
|
||||
#pragma warning(disable:4127)
|
||||
#endif
|
||||
#include "s2.hpp"
|
||||
namespace xsk::gsc::s2 { class lexer; }
|
||||
}
|
||||
|
||||
%code top
|
||||
{
|
||||
#include "stdafx.hpp"
|
||||
#include "parser.hpp"
|
||||
#include "lexer.hpp"
|
||||
using namespace xsk::gsc;
|
||||
xsk::gsc::s2::parser::symbol_type S2lex(xsk::gsc::s2::lexer& lexer);
|
||||
}
|
||||
|
||||
%token SH_DEFINE "#define"
|
||||
%token SH_UNDEF "#undef"
|
||||
%token SH_IFDEF "#ifdef"
|
||||
%token SH_IFNDEF "#ifndef"
|
||||
%token SH_IF "#if"
|
||||
%token SH_ELIF "#elif"
|
||||
%token SH_ELSE "#else"
|
||||
%token SH_ENDIF "#endif"
|
||||
%token DEVBEGIN "/#"
|
||||
%token DEVEND "#/"
|
||||
%token INLINE "#inline"
|
||||
%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 DO "do"
|
||||
%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 BREAKPOINT "breakpoint"
|
||||
%token PROFBEGIN "prof_begin"
|
||||
%token PROFEND "prof_end"
|
||||
%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_MUL "*="
|
||||
%token ASSIGN_DIV "/="
|
||||
%token ASSIGN_MOD "%="
|
||||
%token ASSIGN_BW_OR "|="
|
||||
%token ASSIGN_BW_AND "&="
|
||||
%token ASSIGN_BW_EXOR "^="
|
||||
%token ASSIGN_RSHIFT ">>="
|
||||
%token ASSIGN_LSHIFT "<<="
|
||||
%token BITWISE_OR "|"
|
||||
%token BITWISE_AND "&"
|
||||
%token BITWISE_EXOR "^"
|
||||
%token ADD "+"
|
||||
%token SUB "-"
|
||||
%token MUL "*"
|
||||
%token DIV "/"
|
||||
%token MOD "%"
|
||||
%token <std::string> PATH "path"
|
||||
%token <std::string> IDENTIFIER "identifier"
|
||||
%token <std::string> STRING "string literal"
|
||||
%token <std::string> ISTRING "localized string"
|
||||
%token <std::string> FLOAT "float"
|
||||
%token <std::string> INTEGER "integer"
|
||||
|
||||
%type <ast::program::ptr> program
|
||||
%type <ast::include::ptr> include
|
||||
%type <ast::decl> declaration
|
||||
%type <ast::decl_usingtree::ptr> decl_usingtree
|
||||
%type <ast::decl_constant::ptr> decl_constant
|
||||
%type <ast::decl_thread::ptr> decl_thread
|
||||
%type <ast::stmt> stmt
|
||||
%type <ast::stmt> stmt_or_dev
|
||||
%type <ast::stmt_list::ptr> stmt_list
|
||||
%type <ast::stmt_list::ptr> stmt_or_dev_list
|
||||
%type <ast::stmt_dev::ptr> stmt_dev
|
||||
%type <ast::stmt_list::ptr> stmt_block
|
||||
%type <ast::stmt_expr::ptr> stmt_expr
|
||||
%type <ast::stmt_call::ptr> stmt_call
|
||||
%type <ast::stmt_assign::ptr> stmt_assign
|
||||
%type <ast::stmt_endon::ptr> stmt_endon
|
||||
%type <ast::stmt_notify::ptr> stmt_notify
|
||||
%type <ast::stmt_wait::ptr> stmt_wait
|
||||
%type <ast::stmt_waittill::ptr> stmt_waittill
|
||||
%type <ast::stmt_waittillmatch::ptr> stmt_waittillmatch
|
||||
%type <ast::stmt_waittillframeend::ptr> stmt_waittillframeend
|
||||
%type <ast::stmt_waitframe::ptr> stmt_waitframe
|
||||
%type <ast::stmt_if::ptr> stmt_if
|
||||
%type <ast::stmt_ifelse::ptr> stmt_ifelse
|
||||
%type <ast::stmt_while::ptr> stmt_while
|
||||
%type <ast::stmt_dowhile::ptr> stmt_dowhile
|
||||
%type <ast::stmt_for::ptr> stmt_for
|
||||
%type <ast::stmt_foreach::ptr> stmt_foreach
|
||||
%type <ast::stmt_switch::ptr> stmt_switch
|
||||
%type <ast::stmt_case::ptr> stmt_case
|
||||
%type <ast::stmt_default::ptr> stmt_default
|
||||
%type <ast::stmt_break::ptr> stmt_break
|
||||
%type <ast::stmt_continue::ptr> stmt_continue
|
||||
%type <ast::stmt_return::ptr> stmt_return
|
||||
%type <ast::stmt_breakpoint::ptr> stmt_breakpoint
|
||||
%type <ast::stmt_prof_begin::ptr> stmt_prof_begin
|
||||
%type <ast::stmt_prof_end::ptr> stmt_prof_end
|
||||
%type <ast::expr> expr
|
||||
%type <ast::expr> expr_or_empty
|
||||
%type <ast::expr> expr_assign
|
||||
%type <ast::expr> expr_increment
|
||||
%type <ast::expr> expr_decrement
|
||||
%type <ast::expr> expr_ternary
|
||||
%type <ast::expr> expr_binary
|
||||
%type <ast::expr> expr_primitive
|
||||
%type <ast::expr_complement::ptr> expr_complement
|
||||
%type <ast::expr_negate::ptr> expr_negate
|
||||
%type <ast::expr_not::ptr> expr_not
|
||||
%type <ast::expr_call::ptr> expr_call
|
||||
%type <ast::expr_method::ptr> expr_method
|
||||
%type <ast::call> expr_function
|
||||
%type <ast::call> expr_pointer
|
||||
%type <ast::expr_add_array::ptr> expr_add_array
|
||||
%type <ast::expr_parameters::ptr> expr_parameters
|
||||
%type <ast::expr_arguments::ptr> expr_arguments
|
||||
%type <ast::expr_arguments::ptr> expr_arguments_no_empty
|
||||
%type <ast::expr_reference::ptr> expr_reference
|
||||
%type <ast::expr> expr_tuple
|
||||
%type <ast::expr_tuple::ptr> expr_tuple_arguments
|
||||
%type <ast::expr> expr_tuple_types
|
||||
%type <ast::expr_array::ptr> expr_array
|
||||
%type <ast::expr_field::ptr> expr_field
|
||||
%type <ast::expr_size::ptr> expr_size
|
||||
%type <ast::expr_paren::ptr> expr_paren
|
||||
%type <ast::expr> expr_object
|
||||
%type <ast::expr_thisthread::ptr> expr_thisthread
|
||||
%type <ast::expr_empty_array::ptr> expr_empty_array
|
||||
%type <ast::expr_undefined::ptr> expr_undefined
|
||||
%type <ast::expr_game::ptr> expr_game
|
||||
%type <ast::expr_self::ptr> expr_self
|
||||
%type <ast::expr_anim::ptr> expr_anim
|
||||
%type <ast::expr_level::ptr> expr_level
|
||||
%type <ast::expr_animation::ptr> expr_animation
|
||||
%type <ast::expr_animtree::ptr> expr_animtree
|
||||
%type <ast::expr_identifier::ptr> expr_identifier_nosize
|
||||
%type <ast::expr_identifier::ptr> expr_identifier
|
||||
%type <ast::expr_path::ptr> expr_path
|
||||
%type <ast::expr_istring::ptr> expr_istring
|
||||
%type <ast::expr_string::ptr> expr_string
|
||||
%type <ast::expr_vector::ptr> expr_vector
|
||||
%type <ast::expr_float::ptr> expr_float
|
||||
%type <ast::expr_integer::ptr> expr_integer
|
||||
%type <ast::expr_false::ptr> expr_false
|
||||
%type <ast::expr_true::ptr> expr_true
|
||||
|
||||
%nonassoc SIZEOF
|
||||
%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_EXOR
|
||||
%left BITWISE_AND
|
||||
%left EQUALITY INEQUALITY
|
||||
%left LESS GREATER LESS_EQUAL GREATER_EQUAL
|
||||
%left LSHIFT RSHIFT
|
||||
%left ADD SUB
|
||||
%left MUL 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<ast::program>(@$); }
|
||||
;
|
||||
|
||||
program
|
||||
: program inline
|
||||
{ $$ = std::move($1); }
|
||||
| program include
|
||||
{ $$ = std::move($1); $$->includes.push_back(std::move($2)); }
|
||||
| program declaration
|
||||
{ $$ = std::move($1); $$->declarations.push_back(std::move($2)); }
|
||||
| inline
|
||||
{ $$ = std::make_unique<ast::program>(@$); }
|
||||
| include
|
||||
{ $$ = std::make_unique<ast::program>(@$); $$->includes.push_back(std::move($1)); }
|
||||
| declaration
|
||||
{ $$ = std::make_unique<ast::program>(@$); $$->declarations.push_back(std::move($1)); }
|
||||
;
|
||||
|
||||
inline
|
||||
: INLINE expr_path SEMICOLON { lexer.push_header($2->value); }
|
||||
;
|
||||
|
||||
include
|
||||
: INCLUDE expr_path SEMICOLON
|
||||
{ $$ = std::make_unique<ast::include>(@$, std::move($2)); }
|
||||
;
|
||||
|
||||
declaration
|
||||
: DEVBEGIN { $$.as_dev_begin = std::make_unique<ast::decl_dev_begin>(@$); }
|
||||
| DEVEND { $$.as_dev_end = std::make_unique<ast::decl_dev_end>(@$); }
|
||||
| decl_usingtree { $$.as_usingtree = std::move($1); }
|
||||
| decl_constant { $$.as_constant = std::move($1); }
|
||||
| decl_thread { $$.as_thread = std::move($1); }
|
||||
;
|
||||
|
||||
decl_usingtree
|
||||
: USINGTREE LPAREN expr_string RPAREN SEMICOLON
|
||||
{ lexer.ban_header(@$); $$ = std::make_unique<ast::decl_usingtree>(@$, std::move($3)); }
|
||||
;
|
||||
|
||||
decl_constant
|
||||
: expr_identifier ASSIGN expr SEMICOLON
|
||||
{ $$ = std::make_unique<ast::decl_constant>(@$, std::move($1), std::move($3)); }
|
||||
;
|
||||
|
||||
decl_thread
|
||||
: expr_identifier LPAREN expr_parameters RPAREN stmt_block
|
||||
{ lexer.ban_header(@$); $$ = std::make_unique<ast::decl_thread>(@$, std::move($1), std::move($3), std::move($5)); }
|
||||
;
|
||||
|
||||
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_dowhile { $$.as_dowhile = 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_breakpoint { $$.as_breakpoint = std::move($1); }
|
||||
| stmt_prof_begin { $$.as_prof_begin = std::move($1); }
|
||||
| stmt_prof_end { $$.as_prof_end = std::move($1); }
|
||||
;
|
||||
|
||||
stmt_or_dev
|
||||
: stmt { $$ = std::move($1); }
|
||||
| stmt_dev { $$.as_dev = std::move($1); }
|
||||
;
|
||||
|
||||
stmt_list
|
||||
: stmt_list stmt
|
||||
{ $$ = std::move($1); $$->list.push_back(std::move($2)); }
|
||||
| stmt
|
||||
{ $$ = std::make_unique<ast::stmt_list>(@$); $$->list.push_back(std::move($1)); }
|
||||
;
|
||||
|
||||
stmt_or_dev_list
|
||||
: stmt_or_dev_list stmt_or_dev
|
||||
{ $$ = std::move($1); $$->list.push_back(std::move($2)); }
|
||||
| stmt_or_dev
|
||||
{ $$ = std::make_unique<ast::stmt_list>(@$); $$->list.push_back(std::move($1)); }
|
||||
;
|
||||
|
||||
stmt_dev
|
||||
: DEVBEGIN stmt_list DEVEND { $$ = std::make_unique<ast::stmt_dev>(@$, std::move($2)); }
|
||||
| DEVBEGIN DEVEND { $$ = std::make_unique<ast::stmt_dev>(@$, std::make_unique<ast::stmt_list>(@$)); }
|
||||
;
|
||||
|
||||
stmt_block
|
||||
: LBRACE stmt_or_dev_list RBRACE { $$ = std::move($2); }
|
||||
| LBRACE RBRACE { $$ = std::make_unique<ast::stmt_list>(@$); }
|
||||
;
|
||||
|
||||
stmt_expr
|
||||
: expr_assign
|
||||
{ $$ = std::make_unique<ast::stmt_expr>(@$, std::move($1)); }
|
||||
| expr_increment
|
||||
{ $$ = std::make_unique<ast::stmt_expr>(@$, std::move($1)); }
|
||||
| expr_decrement
|
||||
{ $$ = std::make_unique<ast::stmt_expr>(@$, std::move($1)); }
|
||||
|
|
||||
{ $$ = std::make_unique<ast::stmt_expr>(@$, std::make_unique<ast::node>(@$)); }
|
||||
;
|
||||
|
||||
stmt_call
|
||||
: expr_call SEMICOLON
|
||||
{ $$ = std::make_unique<ast::stmt_call>(@$, ast::expr(std::move($1))); }
|
||||
| expr_method SEMICOLON
|
||||
{ $$ = std::make_unique<ast::stmt_call>(@$, ast::expr(std::move($1))); }
|
||||
;
|
||||
|
||||
stmt_assign
|
||||
: expr_assign SEMICOLON
|
||||
{ $$ = std::make_unique<ast::stmt_assign>(@$, std::move($1)); }
|
||||
| expr_increment SEMICOLON
|
||||
{ $$ = std::make_unique<ast::stmt_assign>(@$, std::move($1)); }
|
||||
| expr_decrement SEMICOLON
|
||||
{ $$ = std::make_unique<ast::stmt_assign>(@$, std::move($1)); }
|
||||
;
|
||||
|
||||
stmt_endon
|
||||
: expr_object ENDON LPAREN expr RPAREN SEMICOLON
|
||||
{ $$ = std::make_unique<ast::stmt_endon>(@$, std::move($1), std::move($4)); }
|
||||
;
|
||||
|
||||
stmt_notify
|
||||
: expr_object NOTIFY LPAREN expr COMMA expr_arguments_no_empty RPAREN SEMICOLON
|
||||
{ $$ = std::make_unique<ast::stmt_notify>(@$, std::move($1), std::move($4), std::move($6)); }
|
||||
| expr_object NOTIFY LPAREN expr RPAREN SEMICOLON
|
||||
{ $$ = std::make_unique<ast::stmt_notify>(@$, std::move($1), std::move($4), std::make_unique<ast::expr_arguments>(@$)); }
|
||||
;
|
||||
|
||||
stmt_wait
|
||||
: WAIT expr SEMICOLON
|
||||
{ $$ = std::make_unique<ast::stmt_wait>(@$, std::move($2)); }
|
||||
;
|
||||
|
||||
stmt_waittill
|
||||
: expr_object WAITTILL LPAREN expr COMMA expr_arguments_no_empty RPAREN SEMICOLON
|
||||
{ $$ = std::make_unique<ast::stmt_waittill>(@$, std::move($1), std::move($4), std::move($6)); }
|
||||
| expr_object WAITTILL LPAREN expr RPAREN SEMICOLON
|
||||
{ $$ = std::make_unique<ast::stmt_waittill>(@$, std::move($1), std::move($4), std::make_unique<ast::expr_arguments>(@$)); }
|
||||
;
|
||||
|
||||
stmt_waittillmatch
|
||||
: expr_object WAITTILLMATCH LPAREN expr COMMA expr_arguments_no_empty RPAREN SEMICOLON
|
||||
{ $$ = std::make_unique<ast::stmt_waittillmatch>(@$, std::move($1), std::move($4), std::move($6)); }
|
||||
| expr_object WAITTILLMATCH LPAREN expr RPAREN SEMICOLON
|
||||
{ $$ = std::make_unique<ast::stmt_waittillmatch>(@$, std::move($1), std::move($4), std::make_unique<ast::expr_arguments>(@$)); }
|
||||
;
|
||||
|
||||
stmt_waittillframeend
|
||||
: WAITTILLFRAMEEND SEMICOLON
|
||||
{ $$ = std::make_unique<ast::stmt_waittillframeend>(@$); }
|
||||
;
|
||||
|
||||
stmt_waitframe
|
||||
: WAITFRAME SEMICOLON
|
||||
{ $$ = std::make_unique<ast::stmt_waitframe>(@$); }
|
||||
| WAITFRAME LPAREN RPAREN SEMICOLON
|
||||
{ $$ = std::make_unique<ast::stmt_waitframe>(@$); }
|
||||
;
|
||||
|
||||
stmt_if
|
||||
: IF LPAREN expr RPAREN stmt %prec THEN
|
||||
{ $$ = std::make_unique<ast::stmt_if>(@$, std::move($3), std::move($5)); }
|
||||
;
|
||||
|
||||
stmt_ifelse
|
||||
: IF LPAREN expr RPAREN stmt ELSE stmt
|
||||
{ $$ = std::make_unique<ast::stmt_ifelse>(@$, std::move($3), std::move($5), std::move($7)); }
|
||||
;
|
||||
|
||||
stmt_while
|
||||
: WHILE LPAREN expr RPAREN stmt
|
||||
{ $$ = std::make_unique<ast::stmt_while>(@$, std::move($3), std::move($5)); }
|
||||
;
|
||||
|
||||
stmt_dowhile
|
||||
: DO stmt WHILE LPAREN expr RPAREN SEMICOLON
|
||||
{ $$ = std::make_unique<ast::stmt_dowhile>(@$, std::move($5), std::move($2)); }
|
||||
;
|
||||
|
||||
stmt_for
|
||||
: FOR LPAREN stmt_expr SEMICOLON expr_or_empty SEMICOLON stmt_expr RPAREN stmt
|
||||
{ $$ = std::make_unique<ast::stmt_for>(@$, ast::stmt(std::move($3)), std::move($5), ast::stmt(std::move($7)), std::move($9)); }
|
||||
;
|
||||
|
||||
stmt_foreach
|
||||
: FOREACH LPAREN expr_identifier IN expr RPAREN stmt
|
||||
{ $$ = std::make_unique<ast::stmt_foreach>(@$, ast::expr(std::move($3)), std::move($5), std::move($7)); }
|
||||
| FOREACH LPAREN expr_identifier COMMA expr_identifier IN expr RPAREN stmt
|
||||
{ $$ = std::make_unique<ast::stmt_foreach>(@$, ast::expr(std::move($3)), ast::expr(std::move($5)), std::move($7), std::move($9)); }
|
||||
;
|
||||
|
||||
stmt_switch
|
||||
: SWITCH LPAREN expr RPAREN stmt_block
|
||||
{ $$ = std::make_unique<ast::stmt_switch>(@$, std::move($3), std::move($5)); }
|
||||
;
|
||||
|
||||
stmt_case
|
||||
: CASE expr_integer COLON
|
||||
{ $$ = std::make_unique<ast::stmt_case>(@$, ast::expr(std::move($2)), std::make_unique<ast::stmt_list>(@$)); }
|
||||
| CASE expr_string COLON
|
||||
{ $$ = std::make_unique<ast::stmt_case>(@$, ast::expr(std::move($2)), std::make_unique<ast::stmt_list>(@$)); }
|
||||
;
|
||||
|
||||
stmt_default
|
||||
: DEFAULT COLON
|
||||
{ $$ = std::make_unique<ast::stmt_default>(@$, std::make_unique<ast::stmt_list>(@$)); }
|
||||
;
|
||||
|
||||
stmt_break
|
||||
: BREAK SEMICOLON
|
||||
{ $$ = std::make_unique<ast::stmt_break>(@$); }
|
||||
;
|
||||
|
||||
stmt_continue
|
||||
: CONTINUE SEMICOLON
|
||||
{ $$ = std::make_unique<ast::stmt_continue>(@$); }
|
||||
;
|
||||
|
||||
stmt_return
|
||||
: RETURN expr SEMICOLON
|
||||
{ $$ = std::make_unique<ast::stmt_return>(@$, std::move($2)); }
|
||||
| RETURN SEMICOLON
|
||||
{ $$ = std::make_unique<ast::stmt_return>(@$, std::make_unique<ast::node>(@$)); }
|
||||
;
|
||||
|
||||
stmt_breakpoint
|
||||
: BREAKPOINT SEMICOLON
|
||||
{ $$ = std::make_unique<ast::stmt_breakpoint>(@$); }
|
||||
;
|
||||
|
||||
stmt_prof_begin
|
||||
: PROFBEGIN LPAREN expr_arguments RPAREN SEMICOLON
|
||||
{ $$ = std::make_unique<ast::stmt_prof_begin>(@$, std::move($3)); }
|
||||
;
|
||||
|
||||
stmt_prof_end
|
||||
: PROFEND LPAREN expr_arguments RPAREN SEMICOLON
|
||||
{ $$ = std::make_unique<ast::stmt_prof_end>(@$, std::move($3)); }
|
||||
;
|
||||
|
||||
expr
|
||||
: expr_ternary { $$ = std::move($1); }
|
||||
| expr_binary { $$ = std::move($1); }
|
||||
| expr_primitive { $$ = std::move($1); }
|
||||
;
|
||||
|
||||
expr_or_empty
|
||||
: expr { $$ = std::move($1); }
|
||||
| { $$.as_node = std::make_unique<ast::node>(@$); }
|
||||
;
|
||||
|
||||
expr_assign
|
||||
: expr_tuple ASSIGN expr
|
||||
{ $$.as_node = std::make_unique<ast::expr_assign_equal>(@$, std::move($1), std::move($3)); }
|
||||
| expr_object ASSIGN expr
|
||||
{ $$.as_node = std::make_unique<ast::expr_assign_equal>(@$, std::move($1), std::move($3)); }
|
||||
| expr_object ASSIGN_BW_OR expr
|
||||
{ $$.as_node = std::make_unique<ast::expr_assign_bitwise_or>(@$, std::move($1), std::move($3)); }
|
||||
| expr_object ASSIGN_BW_AND expr
|
||||
{ $$.as_node = std::make_unique<ast::expr_assign_bitwise_and>(@$, std::move($1), std::move($3)); }
|
||||
| expr_object ASSIGN_BW_EXOR expr
|
||||
{ $$.as_node = std::make_unique<ast::expr_assign_bitwise_exor>(@$, std::move($1), std::move($3)); }
|
||||
| expr_object ASSIGN_LSHIFT expr
|
||||
{ $$.as_node = std::make_unique<ast::expr_assign_shift_left>(@$, std::move($1),std::move( $3)); }
|
||||
| expr_object ASSIGN_RSHIFT expr
|
||||
{ $$.as_node = std::make_unique<ast::expr_assign_shift_right>(@$, std::move($1), std::move($3)); }
|
||||
| expr_object ASSIGN_ADD expr
|
||||
{ $$.as_node = std::make_unique<ast::expr_assign_add>(@$, std::move($1), std::move($3)); }
|
||||
| expr_object ASSIGN_SUB expr
|
||||
{ $$.as_node = std::make_unique<ast::expr_assign_sub>(@$, std::move($1), std::move($3)); }
|
||||
| expr_object ASSIGN_MUL expr
|
||||
{ $$.as_node = std::make_unique<ast::expr_assign_mul>(@$, std::move($1), std::move($3)); }
|
||||
| expr_object ASSIGN_DIV expr
|
||||
{ $$.as_node = std::make_unique<ast::expr_assign_div>(@$, std::move($1), std::move($3)); }
|
||||
| expr_object ASSIGN_MOD expr
|
||||
{ $$.as_node = std::make_unique<ast::expr_assign_mod>(@$, std::move($1), std::move($3)); }
|
||||
;
|
||||
|
||||
expr_increment
|
||||
: INCREMENT expr_object %prec PREINC
|
||||
{ $$.as_node = std::make_unique<ast::expr_increment>(@$, std::move($2), true); }
|
||||
| expr_object INCREMENT %prec POSTINC
|
||||
{ $$.as_node = std::make_unique<ast::expr_increment>(@$, std::move($1), false); }
|
||||
;
|
||||
|
||||
expr_decrement
|
||||
: DECREMENT expr_object %prec PREDEC
|
||||
{ $$.as_node = std::make_unique<ast::expr_decrement>(@$, std::move($2), true); }
|
||||
| expr_object DECREMENT %prec POSTDEC
|
||||
{ $$.as_node = std::make_unique<ast::expr_decrement>(@$, std::move($1), false); }
|
||||
;
|
||||
|
||||
expr_ternary
|
||||
: expr QMARK expr COLON expr %prec TERN
|
||||
{ $$.as_node = std::make_unique<ast::expr_ternary>(@$, std::move($1), std::move($3), std::move($5)); }
|
||||
;
|
||||
|
||||
expr_binary
|
||||
: expr OR expr
|
||||
{ $$.as_node = std::make_unique<ast::expr_or>(@$, std::move($1), std::move($3)); }
|
||||
| expr AND expr
|
||||
{ $$.as_node = std::make_unique<ast::expr_and>(@$, std::move($1), std::move($3)); }
|
||||
| expr EQUALITY expr
|
||||
{ $$.as_node = std::make_unique<ast::expr_equality>(@$, std::move($1), std::move($3)); }
|
||||
| expr INEQUALITY expr
|
||||
{ $$.as_node = std::make_unique<ast::expr_inequality>(@$, std::move($1), std::move($3)); }
|
||||
| expr LESS_EQUAL expr
|
||||
{ $$.as_node = std::make_unique<ast::expr_less_equal>(@$, std::move($1), std::move($3)); }
|
||||
| expr GREATER_EQUAL expr
|
||||
{ $$.as_node = std::make_unique<ast::expr_greater_equal>(@$, std::move($1), std::move($3)); }
|
||||
| expr LESS expr
|
||||
{ $$.as_node = std::make_unique<ast::expr_less>(@$, std::move($1), std::move($3)); }
|
||||
| expr GREATER expr
|
||||
{ $$.as_node = std::make_unique<ast::expr_greater>(@$, std::move($1), std::move($3)); }
|
||||
| expr BITWISE_OR expr
|
||||
{ $$.as_node = std::make_unique<ast::expr_bitwise_or>(@$, std::move($1), std::move($3)); }
|
||||
| expr BITWISE_AND expr
|
||||
{ $$.as_node = std::make_unique<ast::expr_bitwise_and>(@$, std::move($1), std::move($3)); }
|
||||
| expr BITWISE_EXOR expr
|
||||
{ $$.as_node = std::make_unique<ast::expr_bitwise_exor>(@$, std::move($1), std::move($3)); }
|
||||
| expr LSHIFT expr
|
||||
{ $$.as_node = std::make_unique<ast::expr_shift_left>(@$, std::move($1), std::move($3)); }
|
||||
| expr RSHIFT expr
|
||||
{ $$.as_node = std::make_unique<ast::expr_shift_right>(@$, std::move($1), std::move($3)); }
|
||||
| expr ADD expr
|
||||
{ $$.as_node = std::make_unique<ast::expr_add>(@$, std::move($1), std::move($3)); }
|
||||
| expr SUB expr
|
||||
{ $$.as_node = std::make_unique<ast::expr_sub>(@$, std::move($1), std::move($3)); }
|
||||
| expr MUL expr
|
||||
{ $$.as_node = std::make_unique<ast::expr_mul>(@$, std::move($1), std::move($3)); }
|
||||
| expr DIV expr
|
||||
{ $$.as_node = std::make_unique<ast::expr_div>(@$, std::move($1), std::move($3)); }
|
||||
| expr MOD expr
|
||||
{ $$.as_node = std::make_unique<ast::expr_mod>(@$, std::move($1), std::move($3)); }
|
||||
;
|
||||
|
||||
expr_primitive
|
||||
: expr_complement { $$.as_node = std::move($1); }
|
||||
| expr_negate { $$.as_node = std::move($1); }
|
||||
| expr_not { $$.as_node = std::move($1); }
|
||||
| expr_call { $$.as_node = std::move($1); }
|
||||
| expr_method { $$.as_node = std::move($1); }
|
||||
| expr_add_array { $$.as_node = std::move($1); }
|
||||
| expr_reference { $$.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); }
|
||||
| expr_paren { $$.as_node = std::move($1); }
|
||||
| expr_thisthread { $$.as_node = std::move($1); }
|
||||
| expr_empty_array { $$.as_node = std::move($1); }
|
||||
| expr_undefined { $$.as_node = std::move($1); }
|
||||
| expr_game { $$.as_node = std::move($1); }
|
||||
| expr_self { $$.as_node = std::move($1); }
|
||||
| expr_anim { $$.as_node = std::move($1); }
|
||||
| expr_level { $$.as_node = std::move($1); }
|
||||
| expr_animation { $$.as_node = std::move($1); }
|
||||
| expr_animtree { $$.as_node = std::move($1); }
|
||||
| expr_identifier { $$.as_node = std::move($1); }
|
||||
| expr_istring { $$.as_node = std::move($1); }
|
||||
| expr_string { $$.as_node = std::move($1); }
|
||||
| expr_vector { $$.as_node = std::move($1); }
|
||||
| expr_float { $$.as_node = std::move($1); }
|
||||
| expr_integer { $$.as_node = std::move($1); }
|
||||
| expr_false { $$.as_node = std::move($1); }
|
||||
| expr_true { $$.as_node = std::move($1); }
|
||||
;
|
||||
|
||||
expr_complement
|
||||
: COMPLEMENT expr
|
||||
{ $$ = std::make_unique<ast::expr_complement>(@$, std::move($2)); }
|
||||
;
|
||||
|
||||
expr_negate
|
||||
: SUB expr_identifier %prec NEG
|
||||
{ $$ = std::make_unique<ast::expr_negate>(@$, ast::expr(std::move($2))); }
|
||||
| SUB expr_paren %prec NEG
|
||||
{ $$ = std::make_unique<ast::expr_negate>(@$, ast::expr(std::move($2))); }
|
||||
| SUB expr_array %prec NEG
|
||||
{ $$ = std::make_unique<ast::expr_negate>(@$, ast::expr(std::move($2))); }
|
||||
| SUB expr_field %prec NEG
|
||||
{ $$ = std::make_unique<ast::expr_negate>(@$, ast::expr(std::move($2))); }
|
||||
;
|
||||
|
||||
expr_not
|
||||
: NOT expr
|
||||
{ $$ = std::make_unique<ast::expr_not>(@$, std::move($2)); }
|
||||
;
|
||||
|
||||
expr_call
|
||||
: expr_function { $$ = std::make_unique<ast::expr_call>(@$, std::move($1)); }
|
||||
| expr_pointer { $$ = std::make_unique<ast::expr_call>(@$, std::move($1)); }
|
||||
;
|
||||
expr_method
|
||||
: expr_object expr_function { $$ = std::make_unique<ast::expr_method>(@$, std::move($1), std::move($2)); }
|
||||
| expr_object expr_pointer { $$ = std::make_unique<ast::expr_method>(@$, std::move($1), std::move($2)); }
|
||||
;
|
||||
|
||||
expr_function
|
||||
: expr_identifier LPAREN expr_arguments RPAREN
|
||||
{ $$.as_function = std::make_unique<ast::expr_function>(@$, std::make_unique<ast::expr_path>(@$), std::move($1), std::move($3), ast::call::mode::normal); }
|
||||
| expr_path DOUBLECOLON expr_identifier LPAREN expr_arguments RPAREN
|
||||
{ $$.as_function = std::make_unique<ast::expr_function>(@$, std::move($1), std::move($3), std::move($5), ast::call::mode::normal); }
|
||||
| THREAD expr_identifier LPAREN expr_arguments RPAREN
|
||||
{ $$.as_function = std::make_unique<ast::expr_function>(@$, std::make_unique<ast::expr_path>(@$), std::move($2), std::move($4), ast::call::mode::thread); }
|
||||
| THREAD expr_path DOUBLECOLON expr_identifier LPAREN expr_arguments RPAREN
|
||||
{ $$.as_function = std::make_unique<ast::expr_function>(@$, std::move($2), std::move($4), std::move($6), ast::call::mode::thread); }
|
||||
| CHILDTHREAD expr_identifier LPAREN expr_arguments RPAREN
|
||||
{ $$.as_function = std::make_unique<ast::expr_function>(@$, std::make_unique<ast::expr_path>(@$), std::move($2), std::move($4), ast::call::mode::childthread); }
|
||||
| CHILDTHREAD expr_path DOUBLECOLON expr_identifier LPAREN expr_arguments RPAREN
|
||||
{ $$.as_function = std::make_unique<ast::expr_function>(@$, std::move($2), std::move($4), std::move($6), ast::call::mode::childthread); }
|
||||
;
|
||||
|
||||
expr_pointer
|
||||
: LBRACKET LBRACKET expr RBRACKET RBRACKET LPAREN expr_arguments RPAREN
|
||||
{ $$.as_pointer = std::make_unique<ast::expr_pointer>(@$, std::move($3), std::move($7), ast::call::mode::normal); }
|
||||
| THREAD LBRACKET LBRACKET expr RBRACKET RBRACKET LPAREN expr_arguments RPAREN
|
||||
{ $$.as_pointer = std::make_unique<ast::expr_pointer>(@$, std::move($4), std::move($8), ast::call::mode::thread); }
|
||||
| CHILDTHREAD LBRACKET LBRACKET expr RBRACKET RBRACKET LPAREN expr_arguments RPAREN
|
||||
{ $$.as_pointer = std::make_unique<ast::expr_pointer>(@$, std::move($4), std::move($8), ast::call::mode::childthread); }
|
||||
| CALL LBRACKET LBRACKET expr RBRACKET RBRACKET LPAREN expr_arguments RPAREN
|
||||
{ $$.as_pointer = std::make_unique<ast::expr_pointer>(@$, std::move($4), std::move($8), ast::call::mode::builtin); }
|
||||
;
|
||||
|
||||
expr_add_array
|
||||
: LBRACKET expr_arguments_no_empty RBRACKET
|
||||
{ $$ = std::make_unique<ast::expr_add_array>(@$, std::move($2)); }
|
||||
;
|
||||
|
||||
expr_parameters
|
||||
: expr_parameters COMMA expr_identifier
|
||||
{ $$ = std::move($1); $$->list.push_back(std::move($3)); }
|
||||
| expr_identifier
|
||||
{ $$ = std::make_unique<ast::expr_parameters>(@$); $$->list.push_back(std::move($1)); }
|
||||
|
|
||||
{ $$ = std::make_unique<ast::expr_parameters>(@$); }
|
||||
;
|
||||
|
||||
expr_arguments
|
||||
: expr_arguments_no_empty
|
||||
{ $$ = std::move($1); }
|
||||
|
|
||||
{ $$ = std::make_unique<ast::expr_arguments>(@$); }
|
||||
;
|
||||
|
||||
expr_arguments_no_empty
|
||||
: expr_arguments COMMA expr
|
||||
{ $$ = std::move($1); $$->list.push_back(std::move($3)); }
|
||||
| expr %prec ADD_ARRAY
|
||||
{ $$ = std::make_unique<ast::expr_arguments>(@$); $$->list.push_back(std::move($1)); }
|
||||
;
|
||||
|
||||
expr_reference
|
||||
: DOUBLECOLON expr_identifier
|
||||
{ $$ = std::make_unique<ast::expr_reference>(@$, std::make_unique<ast::expr_path>(@$), std::move($2)); }
|
||||
| expr_path DOUBLECOLON expr_identifier
|
||||
{ $$ = std::make_unique<ast::expr_reference>(@$, std::move($1), std::move($3)); }
|
||||
;
|
||||
|
||||
expr_tuple
|
||||
: LBRACKET expr_tuple_arguments RBRACKET
|
||||
{ $$.as_node = std::move($2); }
|
||||
;
|
||||
|
||||
expr_tuple_arguments
|
||||
: expr_tuple_arguments COMMA expr_tuple_types
|
||||
{ $$ = std::move($1); $$->list.push_back(std::move($3)); }
|
||||
| expr_tuple_types
|
||||
{ $$ = std::make_unique<ast::expr_tuple>(@$); $$->list.push_back(std::move($1)); }
|
||||
;
|
||||
|
||||
expr_tuple_types
|
||||
: expr_array { $$.as_node = std::move($1); }
|
||||
| expr_field { $$.as_node = std::move($1); }
|
||||
| expr_identifier { $$.as_node = std::move($1); }
|
||||
;
|
||||
|
||||
expr_array
|
||||
: expr_object LBRACKET expr RBRACKET
|
||||
{ $$ = std::make_unique<ast::expr_array>(@$, std::move($1), std::move($3)); }
|
||||
;
|
||||
|
||||
expr_field
|
||||
: expr_object DOT expr_identifier_nosize
|
||||
{ $$ = std::make_unique<ast::expr_field>(@$, std::move($1), std::move($3)); }
|
||||
;
|
||||
|
||||
expr_size
|
||||
: expr_object DOT SIZE %prec SIZEOF
|
||||
{ $$ = std::make_unique<ast::expr_size>(@$, std::move($1)); }
|
||||
;
|
||||
|
||||
expr_paren
|
||||
: LPAREN expr RPAREN
|
||||
{ $$ = std::make_unique<ast::expr_paren>(@$, std::move($2)); }
|
||||
;
|
||||
|
||||
expr_object
|
||||
: expr_call { $$.as_node = std::move($1); }
|
||||
| expr_method { $$.as_node = std::move($1); }
|
||||
| expr_array { $$.as_node = std::move($1); }
|
||||
| expr_field { $$.as_node = std::move($1); }
|
||||
| expr_game { $$.as_node = std::move($1); }
|
||||
| expr_self { $$.as_node = std::move($1); }
|
||||
| expr_anim { $$.as_node = std::move($1); }
|
||||
| expr_level { $$.as_node = std::move($1); }
|
||||
| expr_identifier { $$.as_node = std::move($1); }
|
||||
;
|
||||
|
||||
expr_thisthread
|
||||
: THISTHREAD
|
||||
{ $$ = std::make_unique<ast::expr_thisthread>(@$); };
|
||||
;
|
||||
|
||||
expr_empty_array
|
||||
: LBRACKET RBRACKET
|
||||
{ $$ = std::make_unique<ast::expr_empty_array>(@$); };
|
||||
;
|
||||
|
||||
expr_undefined
|
||||
: UNDEFINED
|
||||
{ $$ = std::make_unique<ast::expr_undefined>(@$); };
|
||||
;
|
||||
|
||||
expr_game
|
||||
: GAME
|
||||
{ $$ = std::make_unique<ast::expr_game>(@$); };
|
||||
;
|
||||
|
||||
expr_self
|
||||
: SELF
|
||||
{ $$ = std::make_unique<ast::expr_self>(@$); };
|
||||
;
|
||||
|
||||
expr_anim
|
||||
: ANIM
|
||||
{ $$ = std::make_unique<ast::expr_anim>(@$); };
|
||||
;
|
||||
|
||||
expr_level
|
||||
: LEVEL
|
||||
{ $$ = std::make_unique<ast::expr_level>(@$); };
|
||||
;
|
||||
|
||||
expr_animation
|
||||
: MOD IDENTIFIER %prec ANIMREF
|
||||
{ $$ = std::make_unique<ast::expr_animation>(@$, $2); };
|
||||
;
|
||||
|
||||
expr_animtree
|
||||
: ANIMTREE
|
||||
{ $$ = std::make_unique<ast::expr_animtree>(@$); };
|
||||
;
|
||||
|
||||
expr_identifier_nosize
|
||||
: IDENTIFIER
|
||||
{ $$ = std::make_unique<ast::expr_identifier>(@$, $1); };
|
||||
;
|
||||
|
||||
expr_identifier
|
||||
: IDENTIFIER
|
||||
{ $$ = std::make_unique<ast::expr_identifier>(@$, $1); };
|
||||
| SIZE
|
||||
{ $$ = std::make_unique<ast::expr_identifier>(@$, "size"); };
|
||||
;
|
||||
|
||||
expr_path
|
||||
: IDENTIFIER
|
||||
{ $$ = std::make_unique<ast::expr_path>(@$, $1); };
|
||||
| PATH
|
||||
{ $$ = std::make_unique<ast::expr_path>(@$, $1); };
|
||||
;
|
||||
|
||||
expr_istring
|
||||
: ISTRING
|
||||
{ $$ = std::make_unique<ast::expr_istring>(@$, $1); };
|
||||
;
|
||||
|
||||
expr_string
|
||||
: STRING
|
||||
{ $$ = std::make_unique<ast::expr_string>(@$, $1); };
|
||||
;
|
||||
|
||||
expr_vector
|
||||
: LPAREN expr COMMA expr COMMA expr RPAREN
|
||||
{ $$ = std::make_unique<ast::expr_vector>(@$, std::move($2), std::move($4), std::move($6)); };
|
||||
;
|
||||
|
||||
expr_float
|
||||
: SUB FLOAT %prec NEG
|
||||
{ $$ = std::make_unique<ast::expr_float>(@$, "-" + $2); };
|
||||
| FLOAT
|
||||
{ $$ = std::make_unique<ast::expr_float>(@$, $1); };
|
||||
;
|
||||
|
||||
expr_integer
|
||||
: SUB INTEGER %prec NEG
|
||||
{ $$ = std::make_unique<ast::expr_integer>(@$, "-" + $2); };
|
||||
| INTEGER
|
||||
{ $$ = std::make_unique<ast::expr_integer>(@$, $1); };
|
||||
;
|
||||
|
||||
expr_false
|
||||
: FALSE
|
||||
{ $$ = std::make_unique<ast::expr_false>(@$); };
|
||||
;
|
||||
|
||||
expr_true
|
||||
: TRUE
|
||||
{ $$ = std::make_unique<ast::expr_true>(@$); };
|
||||
;
|
||||
|
||||
%%
|
||||
|
||||
void xsk::gsc::s2::parser::error(const xsk::gsc::location& loc, const std::string& msg)
|
||||
{
|
||||
throw xsk::gsc::comp_error(loc, msg);
|
||||
}
|
@ -1,9 +0,0 @@
|
||||
generate: s4
|
||||
|
||||
clean:
|
||||
rm -rf ./parser.hpp
|
||||
rm -rf ./parser.cpp
|
||||
|
||||
s4: parser.ypp
|
||||
bison parser.ypp -Wcounterexamples
|
||||
mv parser.hpp parser.cpp ../../src/s4/xsk/
|
@ -1,914 +0,0 @@
|
||||
/* Copyright 2022 xensik. All rights reserved.
|
||||
//
|
||||
// Use of this source code is governed by a GNU GPLv3 license
|
||||
// that can be found in the LICENSE file.
|
||||
*/
|
||||
|
||||
%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 { xsk::gsc::s4::lexer& lexer }
|
||||
%parse-param { xsk::gsc::s4::lexer& lexer }
|
||||
%parse-param { xsk::gsc::ast::program::ptr& ast }
|
||||
|
||||
%code requires
|
||||
{
|
||||
#ifdef _MSC_VER
|
||||
#pragma warning(disable:4065)
|
||||
#pragma warning(disable:4127)
|
||||
#endif
|
||||
#include "s4.hpp"
|
||||
namespace xsk::gsc::s4 { class lexer; }
|
||||
}
|
||||
|
||||
%code top
|
||||
{
|
||||
#include "stdafx.hpp"
|
||||
#include "parser.hpp"
|
||||
#include "lexer.hpp"
|
||||
using namespace xsk::gsc;
|
||||
xsk::gsc::s4::parser::symbol_type S4lex(xsk::gsc::s4::lexer& lexer);
|
||||
}
|
||||
|
||||
%token SH_DEFINE "#define"
|
||||
%token SH_UNDEF "#undef"
|
||||
%token SH_IFDEF "#ifdef"
|
||||
%token SH_IFNDEF "#ifndef"
|
||||
%token SH_IF "#if"
|
||||
%token SH_ELIF "#elif"
|
||||
%token SH_ELSE "#else"
|
||||
%token SH_ENDIF "#endif"
|
||||
%token DEVBEGIN "/#"
|
||||
%token DEVEND "#/"
|
||||
%token INLINE "#inline"
|
||||
%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 DO "do"
|
||||
%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 BREAKPOINT "breakpoint"
|
||||
%token PROFBEGIN "prof_begin"
|
||||
%token PROFEND "prof_end"
|
||||
%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 ISDEFINED "isdefined"
|
||||
%token ISTRUE "istrue"
|
||||
%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_MUL "*="
|
||||
%token ASSIGN_DIV "/="
|
||||
%token ASSIGN_MOD "%="
|
||||
%token ASSIGN_BW_OR "|="
|
||||
%token ASSIGN_BW_AND "&="
|
||||
%token ASSIGN_BW_EXOR "^="
|
||||
%token ASSIGN_RSHIFT ">>="
|
||||
%token ASSIGN_LSHIFT "<<="
|
||||
%token BITWISE_OR "|"
|
||||
%token BITWISE_AND "&"
|
||||
%token BITWISE_EXOR "^"
|
||||
%token ADD "+"
|
||||
%token SUB "-"
|
||||
%token MUL "*"
|
||||
%token DIV "/"
|
||||
%token MOD "%"
|
||||
%token <std::string> PATH "path"
|
||||
%token <std::string> IDENTIFIER "identifier"
|
||||
%token <std::string> STRING "string literal"
|
||||
%token <std::string> ISTRING "localized string"
|
||||
%token <std::string> FLOAT "float"
|
||||
%token <std::string> INTEGER "integer"
|
||||
|
||||
%type <ast::program::ptr> program
|
||||
%type <ast::include::ptr> include
|
||||
%type <ast::decl> declaration
|
||||
%type <ast::decl_usingtree::ptr> decl_usingtree
|
||||
%type <ast::decl_constant::ptr> decl_constant
|
||||
%type <ast::decl_thread::ptr> decl_thread
|
||||
%type <ast::stmt> stmt
|
||||
%type <ast::stmt> stmt_or_dev
|
||||
%type <ast::stmt_list::ptr> stmt_list
|
||||
%type <ast::stmt_list::ptr> stmt_or_dev_list
|
||||
%type <ast::stmt_dev::ptr> stmt_dev
|
||||
%type <ast::stmt_list::ptr> stmt_block
|
||||
%type <ast::stmt_expr::ptr> stmt_expr
|
||||
%type <ast::stmt_call::ptr> stmt_call
|
||||
%type <ast::stmt_assign::ptr> stmt_assign
|
||||
%type <ast::stmt_endon::ptr> stmt_endon
|
||||
%type <ast::stmt_notify::ptr> stmt_notify
|
||||
%type <ast::stmt_wait::ptr> stmt_wait
|
||||
%type <ast::stmt_waittill::ptr> stmt_waittill
|
||||
%type <ast::stmt_waittillmatch::ptr> stmt_waittillmatch
|
||||
%type <ast::stmt_waittillframeend::ptr> stmt_waittillframeend
|
||||
%type <ast::stmt_waitframe::ptr> stmt_waitframe
|
||||
%type <ast::stmt_if::ptr> stmt_if
|
||||
%type <ast::stmt_ifelse::ptr> stmt_ifelse
|
||||
%type <ast::stmt_while::ptr> stmt_while
|
||||
%type <ast::stmt_dowhile::ptr> stmt_dowhile
|
||||
%type <ast::stmt_for::ptr> stmt_for
|
||||
%type <ast::stmt_foreach::ptr> stmt_foreach
|
||||
%type <ast::stmt_switch::ptr> stmt_switch
|
||||
%type <ast::stmt_case::ptr> stmt_case
|
||||
%type <ast::stmt_default::ptr> stmt_default
|
||||
%type <ast::stmt_break::ptr> stmt_break
|
||||
%type <ast::stmt_continue::ptr> stmt_continue
|
||||
%type <ast::stmt_return::ptr> stmt_return
|
||||
%type <ast::stmt_breakpoint::ptr> stmt_breakpoint
|
||||
%type <ast::stmt_prof_begin::ptr> stmt_prof_begin
|
||||
%type <ast::stmt_prof_end::ptr> stmt_prof_end
|
||||
%type <ast::expr> expr
|
||||
%type <ast::expr> expr_or_empty
|
||||
%type <ast::expr> expr_assign
|
||||
%type <ast::expr> expr_increment
|
||||
%type <ast::expr> expr_decrement
|
||||
%type <ast::expr> expr_ternary
|
||||
%type <ast::expr> expr_binary
|
||||
%type <ast::expr> expr_primitive
|
||||
%type <ast::expr_complement::ptr> expr_complement
|
||||
%type <ast::expr_negate::ptr> expr_negate
|
||||
%type <ast::expr_not::ptr> expr_not
|
||||
%type <ast::expr_call::ptr> expr_call
|
||||
%type <ast::expr_method::ptr> expr_method
|
||||
%type <ast::call> expr_function
|
||||
%type <ast::call> expr_pointer
|
||||
%type <ast::expr_add_array::ptr> expr_add_array
|
||||
%type <ast::expr_parameters::ptr> expr_parameters
|
||||
%type <ast::expr_arguments::ptr> expr_arguments
|
||||
%type <ast::expr_arguments::ptr> expr_arguments_no_empty
|
||||
%type <ast::expr_isdefined::ptr> expr_isdefined
|
||||
%type <ast::expr_istrue::ptr> expr_istrue
|
||||
%type <ast::expr_reference::ptr> expr_reference
|
||||
%type <ast::expr> expr_tuple
|
||||
%type <ast::expr_tuple::ptr> expr_tuple_arguments
|
||||
%type <ast::expr> expr_tuple_types
|
||||
%type <ast::expr_array::ptr> expr_array
|
||||
%type <ast::expr_field::ptr> expr_field
|
||||
%type <ast::expr_size::ptr> expr_size
|
||||
%type <ast::expr_paren::ptr> expr_paren
|
||||
%type <ast::expr> expr_object
|
||||
%type <ast::expr_thisthread::ptr> expr_thisthread
|
||||
%type <ast::expr_empty_array::ptr> expr_empty_array
|
||||
%type <ast::expr_undefined::ptr> expr_undefined
|
||||
%type <ast::expr_game::ptr> expr_game
|
||||
%type <ast::expr_self::ptr> expr_self
|
||||
%type <ast::expr_anim::ptr> expr_anim
|
||||
%type <ast::expr_level::ptr> expr_level
|
||||
%type <ast::expr_animation::ptr> expr_animation
|
||||
%type <ast::expr_animtree::ptr> expr_animtree
|
||||
%type <ast::expr_identifier::ptr> expr_identifier_nosize
|
||||
%type <ast::expr_identifier::ptr> expr_identifier
|
||||
%type <ast::expr_path::ptr> expr_path
|
||||
%type <ast::expr_istring::ptr> expr_istring
|
||||
%type <ast::expr_string::ptr> expr_string
|
||||
%type <ast::expr_vector::ptr> expr_vector
|
||||
%type <ast::expr_float::ptr> expr_float
|
||||
%type <ast::expr_integer::ptr> expr_integer
|
||||
%type <ast::expr_false::ptr> expr_false
|
||||
%type <ast::expr_true::ptr> expr_true
|
||||
|
||||
%nonassoc SIZEOF
|
||||
%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_EXOR
|
||||
%left BITWISE_AND
|
||||
%left EQUALITY INEQUALITY
|
||||
%left LESS GREATER LESS_EQUAL GREATER_EQUAL
|
||||
%left LSHIFT RSHIFT
|
||||
%left ADD SUB
|
||||
%left MUL 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<ast::program>(@$); }
|
||||
;
|
||||
|
||||
program
|
||||
: program inline
|
||||
{ $$ = std::move($1); }
|
||||
| program include
|
||||
{ $$ = std::move($1); $$->includes.push_back(std::move($2)); }
|
||||
| program declaration
|
||||
{ $$ = std::move($1); $$->declarations.push_back(std::move($2)); }
|
||||
| inline
|
||||
{ $$ = std::make_unique<ast::program>(@$); }
|
||||
| include
|
||||
{ $$ = std::make_unique<ast::program>(@$); $$->includes.push_back(std::move($1)); }
|
||||
| declaration
|
||||
{ $$ = std::make_unique<ast::program>(@$); $$->declarations.push_back(std::move($1)); }
|
||||
;
|
||||
|
||||
inline
|
||||
: INLINE expr_path SEMICOLON { lexer.push_header($2->value); }
|
||||
;
|
||||
|
||||
include
|
||||
: INCLUDE expr_path SEMICOLON
|
||||
{ $$ = std::make_unique<ast::include>(@$, std::move($2)); }
|
||||
;
|
||||
|
||||
declaration
|
||||
: DEVBEGIN { $$.as_dev_begin = std::make_unique<ast::decl_dev_begin>(@$); }
|
||||
| DEVEND { $$.as_dev_end = std::make_unique<ast::decl_dev_end>(@$); }
|
||||
| decl_usingtree { $$.as_usingtree = std::move($1); }
|
||||
| decl_constant { $$.as_constant = std::move($1); }
|
||||
| decl_thread { $$.as_thread = std::move($1); }
|
||||
;
|
||||
|
||||
decl_usingtree
|
||||
: USINGTREE LPAREN expr_string RPAREN SEMICOLON
|
||||
{ lexer.ban_header(@$); $$ = std::make_unique<ast::decl_usingtree>(@$, std::move($3)); }
|
||||
;
|
||||
|
||||
decl_constant
|
||||
: expr_identifier ASSIGN expr SEMICOLON
|
||||
{ $$ = std::make_unique<ast::decl_constant>(@$, std::move($1), std::move($3)); }
|
||||
;
|
||||
|
||||
decl_thread
|
||||
: expr_identifier LPAREN expr_parameters RPAREN stmt_block
|
||||
{ lexer.ban_header(@$); $$ = std::make_unique<ast::decl_thread>(@$, std::move($1), std::move($3), std::move($5)); }
|
||||
;
|
||||
|
||||
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_dowhile { $$.as_dowhile = 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_breakpoint { $$.as_breakpoint = std::move($1); }
|
||||
| stmt_prof_begin { $$.as_prof_begin = std::move($1); }
|
||||
| stmt_prof_end { $$.as_prof_end = std::move($1); }
|
||||
;
|
||||
|
||||
stmt_or_dev
|
||||
: stmt { $$ = std::move($1); }
|
||||
| stmt_dev { $$.as_dev = std::move($1); }
|
||||
;
|
||||
|
||||
stmt_list
|
||||
: stmt_list stmt
|
||||
{ $$ = std::move($1); $$->list.push_back(std::move($2)); }
|
||||
| stmt
|
||||
{ $$ = std::make_unique<ast::stmt_list>(@$); $$->list.push_back(std::move($1)); }
|
||||
;
|
||||
|
||||
stmt_or_dev_list
|
||||
: stmt_or_dev_list stmt_or_dev
|
||||
{ $$ = std::move($1); $$->list.push_back(std::move($2)); }
|
||||
| stmt_or_dev
|
||||
{ $$ = std::make_unique<ast::stmt_list>(@$); $$->list.push_back(std::move($1)); }
|
||||
;
|
||||
|
||||
stmt_dev
|
||||
: DEVBEGIN stmt_list DEVEND { $$ = std::make_unique<ast::stmt_dev>(@$, std::move($2)); }
|
||||
| DEVBEGIN DEVEND { $$ = std::make_unique<ast::stmt_dev>(@$, std::make_unique<ast::stmt_list>(@$)); }
|
||||
;
|
||||
|
||||
stmt_block
|
||||
: LBRACE stmt_or_dev_list RBRACE { $$ = std::move($2); }
|
||||
| LBRACE RBRACE { $$ = std::make_unique<ast::stmt_list>(@$); }
|
||||
;
|
||||
|
||||
stmt_expr
|
||||
: expr_assign
|
||||
{ $$ = std::make_unique<ast::stmt_expr>(@$, std::move($1)); }
|
||||
| expr_increment
|
||||
{ $$ = std::make_unique<ast::stmt_expr>(@$, std::move($1)); }
|
||||
| expr_decrement
|
||||
{ $$ = std::make_unique<ast::stmt_expr>(@$, std::move($1)); }
|
||||
|
|
||||
{ $$ = std::make_unique<ast::stmt_expr>(@$, std::make_unique<ast::node>(@$)); }
|
||||
;
|
||||
|
||||
stmt_call
|
||||
: expr_call SEMICOLON
|
||||
{ $$ = std::make_unique<ast::stmt_call>(@$, ast::expr(std::move($1))); }
|
||||
| expr_method SEMICOLON
|
||||
{ $$ = std::make_unique<ast::stmt_call>(@$, ast::expr(std::move($1))); }
|
||||
;
|
||||
|
||||
stmt_assign
|
||||
: expr_assign SEMICOLON
|
||||
{ $$ = std::make_unique<ast::stmt_assign>(@$, std::move($1)); }
|
||||
| expr_increment SEMICOLON
|
||||
{ $$ = std::make_unique<ast::stmt_assign>(@$, std::move($1)); }
|
||||
| expr_decrement SEMICOLON
|
||||
{ $$ = std::make_unique<ast::stmt_assign>(@$, std::move($1)); }
|
||||
;
|
||||
|
||||
stmt_endon
|
||||
: expr_object ENDON LPAREN expr RPAREN SEMICOLON
|
||||
{ $$ = std::make_unique<ast::stmt_endon>(@$, std::move($1), std::move($4)); }
|
||||
;
|
||||
|
||||
stmt_notify
|
||||
: expr_object NOTIFY LPAREN expr COMMA expr_arguments_no_empty RPAREN SEMICOLON
|
||||
{ $$ = std::make_unique<ast::stmt_notify>(@$, std::move($1), std::move($4), std::move($6)); }
|
||||
| expr_object NOTIFY LPAREN expr RPAREN SEMICOLON
|
||||
{ $$ = std::make_unique<ast::stmt_notify>(@$, std::move($1), std::move($4), std::make_unique<ast::expr_arguments>(@$)); }
|
||||
;
|
||||
|
||||
stmt_wait
|
||||
: WAIT expr SEMICOLON
|
||||
{ $$ = std::make_unique<ast::stmt_wait>(@$, std::move($2)); }
|
||||
;
|
||||
|
||||
stmt_waittill
|
||||
: expr_object WAITTILL LPAREN expr COMMA expr_arguments_no_empty RPAREN SEMICOLON
|
||||
{ $$ = std::make_unique<ast::stmt_waittill>(@$, std::move($1), std::move($4), std::move($6)); }
|
||||
| expr_object WAITTILL LPAREN expr RPAREN SEMICOLON
|
||||
{ $$ = std::make_unique<ast::stmt_waittill>(@$, std::move($1), std::move($4), std::make_unique<ast::expr_arguments>(@$)); }
|
||||
;
|
||||
|
||||
stmt_waittillmatch
|
||||
: expr_object WAITTILLMATCH LPAREN expr COMMA expr_arguments_no_empty RPAREN SEMICOLON
|
||||
{ $$ = std::make_unique<ast::stmt_waittillmatch>(@$, std::move($1), std::move($4), std::move($6)); }
|
||||
| expr_object WAITTILLMATCH LPAREN expr RPAREN SEMICOLON
|
||||
{ $$ = std::make_unique<ast::stmt_waittillmatch>(@$, std::move($1), std::move($4), std::make_unique<ast::expr_arguments>(@$)); }
|
||||
;
|
||||
|
||||
stmt_waittillframeend
|
||||
: WAITTILLFRAMEEND SEMICOLON
|
||||
{ $$ = std::make_unique<ast::stmt_waittillframeend>(@$); }
|
||||
;
|
||||
|
||||
stmt_waitframe
|
||||
: WAITFRAME SEMICOLON
|
||||
{ $$ = std::make_unique<ast::stmt_waitframe>(@$); }
|
||||
| WAITFRAME LPAREN RPAREN SEMICOLON
|
||||
{ $$ = std::make_unique<ast::stmt_waitframe>(@$); }
|
||||
;
|
||||
|
||||
stmt_if
|
||||
: IF LPAREN expr RPAREN stmt %prec THEN
|
||||
{ $$ = std::make_unique<ast::stmt_if>(@$, std::move($3), std::move($5)); }
|
||||
;
|
||||
|
||||
stmt_ifelse
|
||||
: IF LPAREN expr RPAREN stmt ELSE stmt
|
||||
{ $$ = std::make_unique<ast::stmt_ifelse>(@$, std::move($3), std::move($5), std::move($7)); }
|
||||
;
|
||||
|
||||
stmt_while
|
||||
: WHILE LPAREN expr RPAREN stmt
|
||||
{ $$ = std::make_unique<ast::stmt_while>(@$, std::move($3), std::move($5)); }
|
||||
;
|
||||
|
||||
stmt_dowhile
|
||||
: DO stmt WHILE LPAREN expr RPAREN SEMICOLON
|
||||
{ $$ = std::make_unique<ast::stmt_dowhile>(@$, std::move($5), std::move($2)); }
|
||||
;
|
||||
|
||||
stmt_for
|
||||
: FOR LPAREN stmt_expr SEMICOLON expr_or_empty SEMICOLON stmt_expr RPAREN stmt
|
||||
{ $$ = std::make_unique<ast::stmt_for>(@$, ast::stmt(std::move($3)), std::move($5), ast::stmt(std::move($7)), std::move($9)); }
|
||||
;
|
||||
|
||||
stmt_foreach
|
||||
: FOREACH LPAREN expr_identifier IN expr RPAREN stmt
|
||||
{ $$ = std::make_unique<ast::stmt_foreach>(@$, ast::expr(std::move($3)), std::move($5), std::move($7)); }
|
||||
| FOREACH LPAREN expr_identifier COMMA expr_identifier IN expr RPAREN stmt
|
||||
{ $$ = std::make_unique<ast::stmt_foreach>(@$, ast::expr(std::move($3)), ast::expr(std::move($5)), std::move($7), std::move($9)); }
|
||||
;
|
||||
|
||||
stmt_switch
|
||||
: SWITCH LPAREN expr RPAREN stmt_block
|
||||
{ $$ = std::make_unique<ast::stmt_switch>(@$, std::move($3), std::move($5)); }
|
||||
;
|
||||
|
||||
stmt_case
|
||||
: CASE expr_integer COLON
|
||||
{ $$ = std::make_unique<ast::stmt_case>(@$, ast::expr(std::move($2)), std::make_unique<ast::stmt_list>(@$)); }
|
||||
| CASE expr_string COLON
|
||||
{ $$ = std::make_unique<ast::stmt_case>(@$, ast::expr(std::move($2)), std::make_unique<ast::stmt_list>(@$)); }
|
||||
;
|
||||
|
||||
stmt_default
|
||||
: DEFAULT COLON
|
||||
{ $$ = std::make_unique<ast::stmt_default>(@$, std::make_unique<ast::stmt_list>(@$)); }
|
||||
;
|
||||
|
||||
stmt_break
|
||||
: BREAK SEMICOLON
|
||||
{ $$ = std::make_unique<ast::stmt_break>(@$); }
|
||||
;
|
||||
|
||||
stmt_continue
|
||||
: CONTINUE SEMICOLON
|
||||
{ $$ = std::make_unique<ast::stmt_continue>(@$); }
|
||||
;
|
||||
|
||||
stmt_return
|
||||
: RETURN expr SEMICOLON
|
||||
{ $$ = std::make_unique<ast::stmt_return>(@$, std::move($2)); }
|
||||
| RETURN SEMICOLON
|
||||
{ $$ = std::make_unique<ast::stmt_return>(@$, std::make_unique<ast::node>(@$)); }
|
||||
;
|
||||
|
||||
stmt_breakpoint
|
||||
: BREAKPOINT SEMICOLON
|
||||
{ $$ = std::make_unique<ast::stmt_breakpoint>(@$); }
|
||||
;
|
||||
|
||||
stmt_prof_begin
|
||||
: PROFBEGIN LPAREN expr_arguments RPAREN SEMICOLON
|
||||
{ $$ = std::make_unique<ast::stmt_prof_begin>(@$, std::move($3)); }
|
||||
;
|
||||
|
||||
stmt_prof_end
|
||||
: PROFEND LPAREN expr_arguments RPAREN SEMICOLON
|
||||
{ $$ = std::make_unique<ast::stmt_prof_end>(@$, std::move($3)); }
|
||||
;
|
||||
|
||||
expr
|
||||
: expr_ternary { $$ = std::move($1); }
|
||||
| expr_binary { $$ = std::move($1); }
|
||||
| expr_primitive { $$ = std::move($1); }
|
||||
;
|
||||
|
||||
expr_or_empty
|
||||
: expr { $$ = std::move($1); }
|
||||
| { $$.as_node = std::make_unique<ast::node>(@$); }
|
||||
;
|
||||
|
||||
expr_assign
|
||||
: expr_tuple ASSIGN expr
|
||||
{ $$.as_node = std::make_unique<ast::expr_assign_equal>(@$, std::move($1), std::move($3)); }
|
||||
| expr_object ASSIGN expr
|
||||
{ $$.as_node = std::make_unique<ast::expr_assign_equal>(@$, std::move($1), std::move($3)); }
|
||||
| expr_object ASSIGN_BW_OR expr
|
||||
{ $$.as_node = std::make_unique<ast::expr_assign_bitwise_or>(@$, std::move($1), std::move($3)); }
|
||||
| expr_object ASSIGN_BW_AND expr
|
||||
{ $$.as_node = std::make_unique<ast::expr_assign_bitwise_and>(@$, std::move($1), std::move($3)); }
|
||||
| expr_object ASSIGN_BW_EXOR expr
|
||||
{ $$.as_node = std::make_unique<ast::expr_assign_bitwise_exor>(@$, std::move($1), std::move($3)); }
|
||||
| expr_object ASSIGN_LSHIFT expr
|
||||
{ $$.as_node = std::make_unique<ast::expr_assign_shift_left>(@$, std::move($1),std::move( $3)); }
|
||||
| expr_object ASSIGN_RSHIFT expr
|
||||
{ $$.as_node = std::make_unique<ast::expr_assign_shift_right>(@$, std::move($1), std::move($3)); }
|
||||
| expr_object ASSIGN_ADD expr
|
||||
{ $$.as_node = std::make_unique<ast::expr_assign_add>(@$, std::move($1), std::move($3)); }
|
||||
| expr_object ASSIGN_SUB expr
|
||||
{ $$.as_node = std::make_unique<ast::expr_assign_sub>(@$, std::move($1), std::move($3)); }
|
||||
| expr_object ASSIGN_MUL expr
|
||||
{ $$.as_node = std::make_unique<ast::expr_assign_mul>(@$, std::move($1), std::move($3)); }
|
||||
| expr_object ASSIGN_DIV expr
|
||||
{ $$.as_node = std::make_unique<ast::expr_assign_div>(@$, std::move($1), std::move($3)); }
|
||||
| expr_object ASSIGN_MOD expr
|
||||
{ $$.as_node = std::make_unique<ast::expr_assign_mod>(@$, std::move($1), std::move($3)); }
|
||||
;
|
||||
|
||||
expr_increment
|
||||
: INCREMENT expr_object %prec PREINC
|
||||
{ $$.as_node = std::make_unique<ast::expr_increment>(@$, std::move($2), true); }
|
||||
| expr_object INCREMENT %prec POSTINC
|
||||
{ $$.as_node = std::make_unique<ast::expr_increment>(@$, std::move($1), false); }
|
||||
;
|
||||
|
||||
expr_decrement
|
||||
: DECREMENT expr_object %prec PREDEC
|
||||
{ $$.as_node = std::make_unique<ast::expr_decrement>(@$, std::move($2), true); }
|
||||
| expr_object DECREMENT %prec POSTDEC
|
||||
{ $$.as_node = std::make_unique<ast::expr_decrement>(@$, std::move($1), false); }
|
||||
;
|
||||
|
||||
expr_ternary
|
||||
: expr QMARK expr COLON expr %prec TERN
|
||||
{ $$.as_node = std::make_unique<ast::expr_ternary>(@$, std::move($1), std::move($3), std::move($5)); }
|
||||
;
|
||||
|
||||
expr_binary
|
||||
: expr OR expr
|
||||
{ $$.as_node = std::make_unique<ast::expr_or>(@$, std::move($1), std::move($3)); }
|
||||
| expr AND expr
|
||||
{ $$.as_node = std::make_unique<ast::expr_and>(@$, std::move($1), std::move($3)); }
|
||||
| expr EQUALITY expr
|
||||
{ $$.as_node = std::make_unique<ast::expr_equality>(@$, std::move($1), std::move($3)); }
|
||||
| expr INEQUALITY expr
|
||||
{ $$.as_node = std::make_unique<ast::expr_inequality>(@$, std::move($1), std::move($3)); }
|
||||
| expr LESS_EQUAL expr
|
||||
{ $$.as_node = std::make_unique<ast::expr_less_equal>(@$, std::move($1), std::move($3)); }
|
||||
| expr GREATER_EQUAL expr
|
||||
{ $$.as_node = std::make_unique<ast::expr_greater_equal>(@$, std::move($1), std::move($3)); }
|
||||
| expr LESS expr
|
||||
{ $$.as_node = std::make_unique<ast::expr_less>(@$, std::move($1), std::move($3)); }
|
||||
| expr GREATER expr
|
||||
{ $$.as_node = std::make_unique<ast::expr_greater>(@$, std::move($1), std::move($3)); }
|
||||
| expr BITWISE_OR expr
|
||||
{ $$.as_node = std::make_unique<ast::expr_bitwise_or>(@$, std::move($1), std::move($3)); }
|
||||
| expr BITWISE_AND expr
|
||||
{ $$.as_node = std::make_unique<ast::expr_bitwise_and>(@$, std::move($1), std::move($3)); }
|
||||
| expr BITWISE_EXOR expr
|
||||
{ $$.as_node = std::make_unique<ast::expr_bitwise_exor>(@$, std::move($1), std::move($3)); }
|
||||
| expr LSHIFT expr
|
||||
{ $$.as_node = std::make_unique<ast::expr_shift_left>(@$, std::move($1), std::move($3)); }
|
||||
| expr RSHIFT expr
|
||||
{ $$.as_node = std::make_unique<ast::expr_shift_right>(@$, std::move($1), std::move($3)); }
|
||||
| expr ADD expr
|
||||
{ $$.as_node = std::make_unique<ast::expr_add>(@$, std::move($1), std::move($3)); }
|
||||
| expr SUB expr
|
||||
{ $$.as_node = std::make_unique<ast::expr_sub>(@$, std::move($1), std::move($3)); }
|
||||
| expr MUL expr
|
||||
{ $$.as_node = std::make_unique<ast::expr_mul>(@$, std::move($1), std::move($3)); }
|
||||
| expr DIV expr
|
||||
{ $$.as_node = std::make_unique<ast::expr_div>(@$, std::move($1), std::move($3)); }
|
||||
| expr MOD expr
|
||||
{ $$.as_node = std::make_unique<ast::expr_mod>(@$, std::move($1), std::move($3)); }
|
||||
;
|
||||
|
||||
expr_primitive
|
||||
: expr_complement { $$.as_node = std::move($1); }
|
||||
| expr_negate { $$.as_node = std::move($1); }
|
||||
| expr_not { $$.as_node = std::move($1); }
|
||||
| expr_call { $$.as_node = std::move($1); }
|
||||
| expr_method { $$.as_node = std::move($1); }
|
||||
| expr_add_array { $$.as_node = std::move($1); }
|
||||
| expr_isdefined { $$.as_node = std::move($1); }
|
||||
| expr_istrue { $$.as_node = std::move($1); }
|
||||
| expr_reference { $$.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); }
|
||||
| expr_paren { $$.as_node = std::move($1); }
|
||||
| expr_thisthread { $$.as_node = std::move($1); }
|
||||
| expr_empty_array { $$.as_node = std::move($1); }
|
||||
| expr_undefined { $$.as_node = std::move($1); }
|
||||
| expr_game { $$.as_node = std::move($1); }
|
||||
| expr_self { $$.as_node = std::move($1); }
|
||||
| expr_anim { $$.as_node = std::move($1); }
|
||||
| expr_level { $$.as_node = std::move($1); }
|
||||
| expr_animation { $$.as_node = std::move($1); }
|
||||
| expr_animtree { $$.as_node = std::move($1); }
|
||||
| expr_identifier { $$.as_node = std::move($1); }
|
||||
| expr_istring { $$.as_node = std::move($1); }
|
||||
| expr_string { $$.as_node = std::move($1); }
|
||||
| expr_vector { $$.as_node = std::move($1); }
|
||||
| expr_float { $$.as_node = std::move($1); }
|
||||
| expr_integer { $$.as_node = std::move($1); }
|
||||
| expr_false { $$.as_node = std::move($1); }
|
||||
| expr_true { $$.as_node = std::move($1); }
|
||||
;
|
||||
|
||||
expr_complement
|
||||
: COMPLEMENT expr
|
||||
{ $$ = std::make_unique<ast::expr_complement>(@$, std::move($2)); }
|
||||
;
|
||||
|
||||
expr_negate
|
||||
: SUB expr_identifier %prec NEG
|
||||
{ $$ = std::make_unique<ast::expr_negate>(@$, ast::expr(std::move($2))); }
|
||||
| SUB expr_paren %prec NEG
|
||||
{ $$ = std::make_unique<ast::expr_negate>(@$, ast::expr(std::move($2))); }
|
||||
| SUB expr_array %prec NEG
|
||||
{ $$ = std::make_unique<ast::expr_negate>(@$, ast::expr(std::move($2))); }
|
||||
| SUB expr_field %prec NEG
|
||||
{ $$ = std::make_unique<ast::expr_negate>(@$, ast::expr(std::move($2))); }
|
||||
;
|
||||
|
||||
expr_not
|
||||
: NOT expr
|
||||
{ $$ = std::make_unique<ast::expr_not>(@$, std::move($2)); }
|
||||
;
|
||||
|
||||
expr_call
|
||||
: expr_function { $$ = std::make_unique<ast::expr_call>(@$, std::move($1)); }
|
||||
| expr_pointer { $$ = std::make_unique<ast::expr_call>(@$, std::move($1)); }
|
||||
;
|
||||
expr_method
|
||||
: expr_object expr_function { $$ = std::make_unique<ast::expr_method>(@$, std::move($1), std::move($2)); }
|
||||
| expr_object expr_pointer { $$ = std::make_unique<ast::expr_method>(@$, std::move($1), std::move($2)); }
|
||||
;
|
||||
|
||||
expr_function
|
||||
: expr_identifier LPAREN expr_arguments RPAREN
|
||||
{ $$.as_function = std::make_unique<ast::expr_function>(@$, std::make_unique<ast::expr_path>(@$), std::move($1), std::move($3), ast::call::mode::normal); }
|
||||
| expr_path DOUBLECOLON expr_identifier LPAREN expr_arguments RPAREN
|
||||
{ $$.as_function = std::make_unique<ast::expr_function>(@$, std::move($1), std::move($3), std::move($5), ast::call::mode::normal); }
|
||||
| THREAD expr_identifier LPAREN expr_arguments RPAREN
|
||||
{ $$.as_function = std::make_unique<ast::expr_function>(@$, std::make_unique<ast::expr_path>(@$), std::move($2), std::move($4), ast::call::mode::thread); }
|
||||
| THREAD expr_path DOUBLECOLON expr_identifier LPAREN expr_arguments RPAREN
|
||||
{ $$.as_function = std::make_unique<ast::expr_function>(@$, std::move($2), std::move($4), std::move($6), ast::call::mode::thread); }
|
||||
| CHILDTHREAD expr_identifier LPAREN expr_arguments RPAREN
|
||||
{ $$.as_function = std::make_unique<ast::expr_function>(@$, std::make_unique<ast::expr_path>(@$), std::move($2), std::move($4), ast::call::mode::childthread); }
|
||||
| CHILDTHREAD expr_path DOUBLECOLON expr_identifier LPAREN expr_arguments RPAREN
|
||||
{ $$.as_function = std::make_unique<ast::expr_function>(@$, std::move($2), std::move($4), std::move($6), ast::call::mode::childthread); }
|
||||
;
|
||||
|
||||
expr_pointer
|
||||
: LBRACKET LBRACKET expr RBRACKET RBRACKET LPAREN expr_arguments RPAREN
|
||||
{ $$.as_pointer = std::make_unique<ast::expr_pointer>(@$, std::move($3), std::move($7), ast::call::mode::normal); }
|
||||
| THREAD LBRACKET LBRACKET expr RBRACKET RBRACKET LPAREN expr_arguments RPAREN
|
||||
{ $$.as_pointer = std::make_unique<ast::expr_pointer>(@$, std::move($4), std::move($8), ast::call::mode::thread); }
|
||||
| CHILDTHREAD LBRACKET LBRACKET expr RBRACKET RBRACKET LPAREN expr_arguments RPAREN
|
||||
{ $$.as_pointer = std::make_unique<ast::expr_pointer>(@$, std::move($4), std::move($8), ast::call::mode::childthread); }
|
||||
| CALL LBRACKET LBRACKET expr RBRACKET RBRACKET LPAREN expr_arguments RPAREN
|
||||
{ $$.as_pointer = std::make_unique<ast::expr_pointer>(@$, std::move($4), std::move($8), ast::call::mode::builtin); }
|
||||
;
|
||||
|
||||
expr_add_array
|
||||
: LBRACKET expr_arguments_no_empty RBRACKET
|
||||
{ $$ = std::make_unique<ast::expr_add_array>(@$, std::move($2)); }
|
||||
;
|
||||
|
||||
expr_parameters
|
||||
: expr_parameters COMMA expr_identifier
|
||||
{ $$ = std::move($1); $$->list.push_back(std::move($3)); }
|
||||
| expr_identifier
|
||||
{ $$ = std::make_unique<ast::expr_parameters>(@$); $$->list.push_back(std::move($1)); }
|
||||
|
|
||||
{ $$ = std::make_unique<ast::expr_parameters>(@$); }
|
||||
;
|
||||
|
||||
expr_arguments
|
||||
: expr_arguments_no_empty
|
||||
{ $$ = std::move($1); }
|
||||
|
|
||||
{ $$ = std::make_unique<ast::expr_arguments>(@$); }
|
||||
;
|
||||
|
||||
expr_arguments_no_empty
|
||||
: expr_arguments COMMA expr
|
||||
{ $$ = std::move($1); $$->list.push_back(std::move($3)); }
|
||||
| expr %prec ADD_ARRAY
|
||||
{ $$ = std::make_unique<ast::expr_arguments>(@$); $$->list.push_back(std::move($1)); }
|
||||
;
|
||||
|
||||
expr_isdefined
|
||||
: ISDEFINED LPAREN expr RPAREN
|
||||
{ $$ = std::make_unique<ast::expr_isdefined>(@$, std::move($3)); }
|
||||
;
|
||||
|
||||
expr_istrue
|
||||
: ISTRUE LPAREN expr RPAREN
|
||||
{ $$ = std::make_unique<ast::expr_istrue>(@$, std::move($3)); }
|
||||
;
|
||||
|
||||
expr_reference
|
||||
: DOUBLECOLON expr_identifier
|
||||
{ $$ = std::make_unique<ast::expr_reference>(@$, std::make_unique<ast::expr_path>(@$), std::move($2)); }
|
||||
| expr_path DOUBLECOLON expr_identifier
|
||||
{ $$ = std::make_unique<ast::expr_reference>(@$, std::move($1), std::move($3)); }
|
||||
;
|
||||
|
||||
expr_tuple
|
||||
: LBRACKET expr_tuple_arguments RBRACKET
|
||||
{ $$.as_node = std::move($2); }
|
||||
;
|
||||
|
||||
expr_tuple_arguments
|
||||
: expr_tuple_arguments COMMA expr_tuple_types
|
||||
{ $$ = std::move($1); $$->list.push_back(std::move($3)); }
|
||||
| expr_tuple_types
|
||||
{ $$ = std::make_unique<ast::expr_tuple>(@$); $$->list.push_back(std::move($1)); }
|
||||
;
|
||||
|
||||
expr_tuple_types
|
||||
: expr_array { $$.as_node = std::move($1); }
|
||||
| expr_field { $$.as_node = std::move($1); }
|
||||
| expr_identifier { $$.as_node = std::move($1); }
|
||||
;
|
||||
|
||||
expr_array
|
||||
: expr_object LBRACKET expr RBRACKET
|
||||
{ $$ = std::make_unique<ast::expr_array>(@$, std::move($1), std::move($3)); }
|
||||
;
|
||||
|
||||
expr_field
|
||||
: expr_object DOT expr_identifier_nosize
|
||||
{ $$ = std::make_unique<ast::expr_field>(@$, std::move($1), std::move($3)); }
|
||||
;
|
||||
|
||||
expr_size
|
||||
: expr_object DOT SIZE %prec SIZEOF
|
||||
{ $$ = std::make_unique<ast::expr_size>(@$, std::move($1)); }
|
||||
;
|
||||
|
||||
expr_paren
|
||||
: LPAREN expr RPAREN
|
||||
{ $$ = std::make_unique<ast::expr_paren>(@$, std::move($2)); }
|
||||
;
|
||||
|
||||
expr_object
|
||||
: expr_call { $$.as_node = std::move($1); }
|
||||
| expr_method { $$.as_node = std::move($1); }
|
||||
| expr_array { $$.as_node = std::move($1); }
|
||||
| expr_field { $$.as_node = std::move($1); }
|
||||
| expr_game { $$.as_node = std::move($1); }
|
||||
| expr_self { $$.as_node = std::move($1); }
|
||||
| expr_anim { $$.as_node = std::move($1); }
|
||||
| expr_level { $$.as_node = std::move($1); }
|
||||
| expr_identifier { $$.as_node = std::move($1); }
|
||||
;
|
||||
|
||||
expr_thisthread
|
||||
: THISTHREAD
|
||||
{ $$ = std::make_unique<ast::expr_thisthread>(@$); };
|
||||
;
|
||||
|
||||
expr_empty_array
|
||||
: LBRACKET RBRACKET
|
||||
{ $$ = std::make_unique<ast::expr_empty_array>(@$); };
|
||||
;
|
||||
|
||||
expr_undefined
|
||||
: UNDEFINED
|
||||
{ $$ = std::make_unique<ast::expr_undefined>(@$); };
|
||||
;
|
||||
|
||||
expr_game
|
||||
: GAME
|
||||
{ $$ = std::make_unique<ast::expr_game>(@$); };
|
||||
;
|
||||
|
||||
expr_self
|
||||
: SELF
|
||||
{ $$ = std::make_unique<ast::expr_self>(@$); };
|
||||
;
|
||||
|
||||
expr_anim
|
||||
: ANIM
|
||||
{ $$ = std::make_unique<ast::expr_anim>(@$); };
|
||||
;
|
||||
|
||||
expr_level
|
||||
: LEVEL
|
||||
{ $$ = std::make_unique<ast::expr_level>(@$); };
|
||||
;
|
||||
|
||||
expr_animation
|
||||
: MOD IDENTIFIER %prec ANIMREF
|
||||
{ $$ = std::make_unique<ast::expr_animation>(@$, $2); };
|
||||
;
|
||||
|
||||
expr_animtree
|
||||
: ANIMTREE
|
||||
{ $$ = std::make_unique<ast::expr_animtree>(@$); };
|
||||
;
|
||||
|
||||
expr_identifier_nosize
|
||||
: IDENTIFIER
|
||||
{ $$ = std::make_unique<ast::expr_identifier>(@$, $1); };
|
||||
;
|
||||
|
||||
expr_identifier
|
||||
: IDENTIFIER
|
||||
{ $$ = std::make_unique<ast::expr_identifier>(@$, $1); };
|
||||
| SIZE
|
||||
{ $$ = std::make_unique<ast::expr_identifier>(@$, "size"); };
|
||||
;
|
||||
|
||||
expr_path
|
||||
: IDENTIFIER
|
||||
{ $$ = std::make_unique<ast::expr_path>(@$, $1); };
|
||||
| PATH
|
||||
{ $$ = std::make_unique<ast::expr_path>(@$, $1); };
|
||||
;
|
||||
|
||||
expr_istring
|
||||
: ISTRING
|
||||
{ $$ = std::make_unique<ast::expr_istring>(@$, $1); };
|
||||
;
|
||||
|
||||
expr_string
|
||||
: STRING
|
||||
{ $$ = std::make_unique<ast::expr_string>(@$, $1); };
|
||||
;
|
||||
|
||||
expr_vector
|
||||
: LPAREN expr COMMA expr COMMA expr RPAREN
|
||||
{ $$ = std::make_unique<ast::expr_vector>(@$, std::move($2), std::move($4), std::move($6)); };
|
||||
;
|
||||
|
||||
expr_float
|
||||
: SUB FLOAT %prec NEG
|
||||
{ $$ = std::make_unique<ast::expr_float>(@$, "-" + $2); };
|
||||
| FLOAT
|
||||
{ $$ = std::make_unique<ast::expr_float>(@$, $1); };
|
||||
;
|
||||
|
||||
expr_integer
|
||||
: SUB INTEGER %prec NEG
|
||||
{ $$ = std::make_unique<ast::expr_integer>(@$, "-" + $2); };
|
||||
| INTEGER
|
||||
{ $$ = std::make_unique<ast::expr_integer>(@$, $1); };
|
||||
;
|
||||
|
||||
expr_false
|
||||
: FALSE
|
||||
{ $$ = std::make_unique<ast::expr_false>(@$); };
|
||||
;
|
||||
|
||||
expr_true
|
||||
: TRUE
|
||||
{ $$ = std::make_unique<ast::expr_true>(@$); };
|
||||
;
|
||||
|
||||
%%
|
||||
|
||||
void xsk::gsc::s4::parser::error(const xsk::gsc::location& loc, const std::string& msg)
|
||||
{
|
||||
throw xsk::gsc::comp_error(loc, msg);
|
||||
}
|
@ -6,4 +6,4 @@ clean:
|
||||
|
||||
t6: parser.ypp
|
||||
bison parser.ypp -Wcounterexamples
|
||||
mv parser.hpp parser.cpp ../../src/t6/xsk/
|
||||
mv parser.hpp parser.cpp ../../src/t6/
|
||||
|
@ -1,4 +1,4 @@
|
||||
/* Copyright 2022 xensik. All rights reserved.
|
||||
/* Copyright 2023 xensik. All rights reserved.
|
||||
//
|
||||
// Use of this source code is governed by a GNU GPLv3 license
|
||||
// that can be found in the LICENSE file.
|
||||
@ -36,7 +36,7 @@ namespace xsk::arc::t6 { class lexer; }
|
||||
|
||||
%code top
|
||||
{
|
||||
#include "stdafx.hpp"
|
||||
#include "stdinc.hpp"
|
||||
#include "parser.hpp"
|
||||
#include "lexer.hpp"
|
||||
using namespace xsk::arc;
|
||||
@ -215,7 +215,6 @@ xsk::arc::t6::parser::symbol_type T6lex(xsk::arc::t6::lexer& lexer);
|
||||
%type <ast::call> expr_pointer
|
||||
%type <ast::expr_parameters::ptr> expr_parameters
|
||||
%type <ast::expr> expr_parameters_default
|
||||
/* %type <ast::expr> expr_literal */
|
||||
%type <ast::expr_arguments::ptr> expr_arguments
|
||||
%type <ast::expr_arguments::ptr> expr_arguments_no_empty
|
||||
%type <ast::expr_getnextarraykey::ptr> expr_getnextarraykey
|
||||
@ -753,15 +752,6 @@ expr_parameters_default
|
||||
{ $$.as_node = std::make_unique<ast::expr_assign_equal>(@$, ast::expr(std::move($1)), std::move($3)); }
|
||||
;
|
||||
|
||||
/* expr_literal
|
||||
: expr_istring { $$.as_node = std::move($1); }
|
||||
| expr_string { $$.as_node = std::move($1); }
|
||||
| expr_float { $$.as_node = std::move($1); }
|
||||
| expr_integer { $$.as_node = std::move($1); }
|
||||
| expr_false { $$.as_node = std::move($1); }
|
||||
| expr_true { $$.as_node = std::move($1); }
|
||||
; */
|
||||
|
||||
expr_arguments
|
||||
: expr_arguments_no_empty
|
||||
{ $$ = std::move($1); }
|
||||
|
426
premake5.lua
426
premake5.lua
@ -13,7 +13,7 @@ end
|
||||
dependencies.load()
|
||||
-------------------------------------------------
|
||||
workspace "gsc-tool"
|
||||
startproject "xsk-gsc-tool"
|
||||
startproject "xsk-tool"
|
||||
location "./build"
|
||||
objdir "%{wks.location}/obj/%{cfg.buildcfg}/%{prj.name}"
|
||||
targetdir "%{wks.location}/bin/%{cfg.platform}/%{cfg.buildcfg}"
|
||||
@ -77,29 +77,30 @@ workspace "gsc-tool"
|
||||
defines { "DEBUG", "_DEBUG" }
|
||||
filter {}
|
||||
|
||||
project "xsk-gsc-tool"
|
||||
project "xsk-tool"
|
||||
kind "ConsoleApp"
|
||||
language "C++"
|
||||
targetname "gsc-tool"
|
||||
|
||||
dependson "xsk-gsc-utils"
|
||||
dependson "xsk-gsc-h1"
|
||||
dependson "xsk-gsc-h2"
|
||||
dependson "xsk-gsc-iw5"
|
||||
dependson "xsk-gsc-iw6"
|
||||
dependson "xsk-gsc-iw7"
|
||||
dependson "xsk-gsc-iw8"
|
||||
dependson "xsk-gsc-iw9"
|
||||
dependson "xsk-gsc-s1"
|
||||
dependson "xsk-gsc-s2"
|
||||
dependson "xsk-gsc-s4"
|
||||
dependson "xsk-arc-t6"
|
||||
dependson "xsk-gsc-iw5c"
|
||||
dependson "xsk-gsc-iw6c"
|
||||
dependson "xsk-gsc-s1c"
|
||||
|
||||
pchheader "stdafx.hpp"
|
||||
pchsource "src/tool/stdafx.cpp"
|
||||
dependson "xsk-utils"
|
||||
dependson "xsk-gsc"
|
||||
dependson "xsk-iw5_pc"
|
||||
dependson "xsk-iw5_ps"
|
||||
dependson "xsk-iw5_xb"
|
||||
dependson "xsk-iw6_pc"
|
||||
dependson "xsk-iw6_ps"
|
||||
dependson "xsk-iw6_xb"
|
||||
dependson "xsk-s1_pc"
|
||||
dependson "xsk-s1_ps"
|
||||
dependson "xsk-s1_xb"
|
||||
dependson "xsk-iw7"
|
||||
dependson "xsk-iw8"
|
||||
dependson "xsk-iw9"
|
||||
dependson "xsk-h1"
|
||||
dependson "xsk-h2"
|
||||
dependson "xsk-s2"
|
||||
dependson "xsk-s4"
|
||||
dependson "xsk-t6"
|
||||
|
||||
files {
|
||||
"./src/tool/**.h",
|
||||
@ -108,21 +109,25 @@ project "xsk-gsc-tool"
|
||||
}
|
||||
|
||||
links {
|
||||
"xsk-gsc-utils",
|
||||
"xsk-gsc-h1",
|
||||
"xsk-gsc-h2",
|
||||
"xsk-gsc-iw5",
|
||||
"xsk-gsc-iw6",
|
||||
"xsk-gsc-iw7",
|
||||
"xsk-gsc-iw8",
|
||||
"xsk-gsc-iw9",
|
||||
"xsk-gsc-s1",
|
||||
"xsk-gsc-s2",
|
||||
"xsk-gsc-s4",
|
||||
"xsk-arc-t6",
|
||||
"xsk-gsc-iw5c",
|
||||
"xsk-gsc-iw6c",
|
||||
"xsk-gsc-s1c"
|
||||
"xsk-utils",
|
||||
"xsk-gsc",
|
||||
"xsk-iw5_pc",
|
||||
"xsk-iw5_ps",
|
||||
"xsk-iw5_xb",
|
||||
"xsk-iw6_pc",
|
||||
"xsk-iw6_ps",
|
||||
"xsk-iw6_xb",
|
||||
"xsk-s1_pc",
|
||||
"xsk-s1_ps",
|
||||
"xsk-s1_xb",
|
||||
"xsk-iw7",
|
||||
"xsk-iw8",
|
||||
"xsk-iw9",
|
||||
"xsk-h1",
|
||||
"xsk-h2",
|
||||
"xsk-s2",
|
||||
"xsk-s4",
|
||||
"xsk-t6",
|
||||
}
|
||||
|
||||
includedirs {
|
||||
@ -130,15 +135,13 @@ project "xsk-gsc-tool"
|
||||
"./src"
|
||||
}
|
||||
|
||||
fmt:link()
|
||||
zlib:link()
|
||||
|
||||
project "xsk-gsc-utils"
|
||||
project "xsk-utils"
|
||||
kind "StaticLib"
|
||||
language "C++"
|
||||
|
||||
pchheader "stdafx.hpp"
|
||||
pchsource "src/utils/stdafx.cpp"
|
||||
|
||||
files {
|
||||
"./src/utils/**.h",
|
||||
"./src/utils/**.hpp",
|
||||
@ -150,55 +153,37 @@ project "xsk-gsc-utils"
|
||||
"./src"
|
||||
}
|
||||
|
||||
fmt:include()
|
||||
zlib:include()
|
||||
|
||||
project "xsk-gsc-h1"
|
||||
kind "StaticLib"
|
||||
language "C++"
|
||||
|
||||
pchheader "stdafx.hpp"
|
||||
pchsource "src/h1/stdafx.cpp"
|
||||
|
||||
files {
|
||||
"./src/h1/**.h",
|
||||
"./src/h1/**.hpp",
|
||||
"./src/h1/**.cpp"
|
||||
}
|
||||
|
||||
includedirs {
|
||||
"./src/h1",
|
||||
"./src"
|
||||
}
|
||||
|
||||
project "xsk-gsc-h2"
|
||||
kind "StaticLib"
|
||||
language "C++"
|
||||
|
||||
pchheader "stdafx.hpp"
|
||||
pchsource "src/h2/stdafx.cpp"
|
||||
|
||||
files {
|
||||
"./src/h2/**.h",
|
||||
"./src/h2/**.hpp",
|
||||
"./src/h2/**.cpp"
|
||||
}
|
||||
|
||||
includedirs {
|
||||
"./src/h2",
|
||||
"./src"
|
||||
}
|
||||
|
||||
project "xsk-gsc-iw5"
|
||||
project "xsk-gsc"
|
||||
kind "StaticLib"
|
||||
language "C++"
|
||||
|
||||
pchheader "stdafx.hpp"
|
||||
pchsource "src/iw5/stdafx.cpp"
|
||||
files {
|
||||
"./src/gsc/**.h",
|
||||
"./src/gsc/**.hpp",
|
||||
"./src/gsc/**.cpp"
|
||||
}
|
||||
|
||||
includedirs {
|
||||
"./src/gsc",
|
||||
"./src"
|
||||
}
|
||||
|
||||
fmt:include()
|
||||
|
||||
project "xsk-iw5_pc"
|
||||
kind "StaticLib"
|
||||
language "C++"
|
||||
|
||||
files {
|
||||
"./src/iw5/**.h",
|
||||
"./src/iw5/**.hpp",
|
||||
"./src/iw5/**.cpp"
|
||||
"./src/iw5/iw5_pc.hpp",
|
||||
"./src/iw5/iw5_pc.cpp",
|
||||
"./src/iw5/iw5_pc_code.cpp",
|
||||
"./src/iw5/iw5_pc_func.cpp",
|
||||
"./src/iw5/iw5_pc_meth.cpp",
|
||||
"./src/iw5/iw5_pc_token.cpp"
|
||||
}
|
||||
|
||||
includedirs {
|
||||
@ -206,17 +191,59 @@ project "xsk-gsc-iw5"
|
||||
"./src"
|
||||
}
|
||||
|
||||
project "xsk-gsc-iw6"
|
||||
fmt:include()
|
||||
|
||||
project "xsk-iw5_ps"
|
||||
kind "StaticLib"
|
||||
language "C++"
|
||||
|
||||
pchheader "stdafx.hpp"
|
||||
pchsource "src/iw6/stdafx.cpp"
|
||||
files {
|
||||
"./src/iw5/iw5_ps.hpp",
|
||||
"./src/iw5/iw5_ps.cpp",
|
||||
"./src/iw5/iw5_ps_code.cpp",
|
||||
"./src/iw5/iw5_ps_func.cpp",
|
||||
"./src/iw5/iw5_ps_meth.cpp",
|
||||
"./src/iw5/iw5_ps_token.cpp"
|
||||
}
|
||||
|
||||
includedirs {
|
||||
"./src/iw5",
|
||||
"./src"
|
||||
}
|
||||
|
||||
fmt:include()
|
||||
|
||||
project "xsk-iw5_xb"
|
||||
kind "StaticLib"
|
||||
language "C++"
|
||||
|
||||
files {
|
||||
"./src/iw6/**.h",
|
||||
"./src/iw6/**.hpp",
|
||||
"./src/iw6/**.cpp"
|
||||
"./src/iw5/iw5_xb.hpp",
|
||||
"./src/iw5/iw5_xb.cpp",
|
||||
"./src/iw5/iw5_xb_code.cpp",
|
||||
"./src/iw5/iw5_xb_func.cpp",
|
||||
"./src/iw5/iw5_xb_meth.cpp",
|
||||
"./src/iw5/iw5_xb_token.cpp"
|
||||
}
|
||||
|
||||
includedirs {
|
||||
"./src/iw5",
|
||||
"./src"
|
||||
}
|
||||
|
||||
fmt:include()
|
||||
|
||||
project "xsk-iw6_pc"
|
||||
kind "StaticLib"
|
||||
language "C++"
|
||||
|
||||
files {
|
||||
"./src/iw6/iw6_pc.hpp",
|
||||
"./src/iw6/iw6_pc.cpp",
|
||||
"./src/iw6/iw6_pc_code.cpp",
|
||||
"./src/iw6/iw6_pc_func.cpp",
|
||||
"./src/iw6/iw6_pc_meth.cpp",
|
||||
"./src/iw6/iw6_pc_token.cpp"
|
||||
}
|
||||
|
||||
includedirs {
|
||||
@ -224,12 +251,111 @@ project "xsk-gsc-iw6"
|
||||
"./src"
|
||||
}
|
||||
|
||||
project "xsk-gsc-iw7"
|
||||
fmt:include()
|
||||
|
||||
project "xsk-iw6_ps"
|
||||
kind "StaticLib"
|
||||
language "C++"
|
||||
|
||||
pchheader "stdafx.hpp"
|
||||
pchsource "src/iw7/stdafx.cpp"
|
||||
files {
|
||||
"./src/iw6/iw6_ps.hpp",
|
||||
"./src/iw6/iw6_ps.cpp",
|
||||
"./src/iw6/iw6_ps_code.cpp",
|
||||
"./src/iw6/iw6_ps_func.cpp",
|
||||
"./src/iw6/iw6_ps_meth.cpp",
|
||||
"./src/iw6/iw6_ps_token.cpp"
|
||||
}
|
||||
|
||||
includedirs {
|
||||
"./src/iw6",
|
||||
"./src"
|
||||
}
|
||||
|
||||
fmt:include()
|
||||
|
||||
project "xsk-iw6_xb"
|
||||
kind "StaticLib"
|
||||
language "C++"
|
||||
|
||||
files {
|
||||
"./src/iw6/iw6_xb.hpp",
|
||||
"./src/iw6/iw6_xb.cpp",
|
||||
"./src/iw6/iw6_xb_code.cpp",
|
||||
"./src/iw6/iw6_xb_func.cpp",
|
||||
"./src/iw6/iw6_xb_meth.cpp",
|
||||
"./src/iw6/iw6_xb_token.cpp"
|
||||
}
|
||||
|
||||
includedirs {
|
||||
"./src/iw6",
|
||||
"./src"
|
||||
}
|
||||
|
||||
fmt:include()
|
||||
|
||||
project "xsk-s1_pc"
|
||||
kind "StaticLib"
|
||||
language "C++"
|
||||
|
||||
files {
|
||||
"./src/s1/s1_pc.hpp",
|
||||
"./src/s1/s1_pc.cpp",
|
||||
"./src/s1/s1_pc_code.cpp",
|
||||
"./src/s1/s1_pc_func.cpp",
|
||||
"./src/s1/s1_pc_meth.cpp",
|
||||
"./src/s1/s1_pc_token.cpp"
|
||||
}
|
||||
|
||||
includedirs {
|
||||
"./src/s1",
|
||||
"./src"
|
||||
}
|
||||
|
||||
fmt:include()
|
||||
|
||||
project "xsk-s1_ps"
|
||||
kind "StaticLib"
|
||||
language "C++"
|
||||
|
||||
files {
|
||||
"./src/s1/s1_ps.hpp",
|
||||
"./src/s1/s1_ps.cpp",
|
||||
"./src/s1/s1_ps_code.cpp",
|
||||
"./src/s1/s1_ps_func.cpp",
|
||||
"./src/s1/s1_ps_meth.cpp",
|
||||
"./src/s1/s1_ps_token.cpp"
|
||||
}
|
||||
|
||||
includedirs {
|
||||
"./src/s1",
|
||||
"./src"
|
||||
}
|
||||
|
||||
fmt:include()
|
||||
|
||||
project "xsk-s1_xb"
|
||||
kind "StaticLib"
|
||||
language "C++"
|
||||
|
||||
files {
|
||||
"./src/s1/s1_xb.hpp",
|
||||
"./src/s1/s1_xb.cpp",
|
||||
"./src/s1/s1_xb_code.cpp",
|
||||
"./src/s1/s1_xb_func.cpp",
|
||||
"./src/s1/s1_xb_meth.cpp",
|
||||
"./src/s1/s1_xb_token.cpp"
|
||||
}
|
||||
|
||||
includedirs {
|
||||
"./src/s1",
|
||||
"./src"
|
||||
}
|
||||
|
||||
fmt:include()
|
||||
|
||||
project "xsk-iw7"
|
||||
kind "StaticLib"
|
||||
language "C++"
|
||||
|
||||
files {
|
||||
"./src/iw7/**.h",
|
||||
@ -242,13 +368,12 @@ project "xsk-gsc-iw7"
|
||||
"./src"
|
||||
}
|
||||
|
||||
project "xsk-gsc-iw8"
|
||||
fmt:include()
|
||||
|
||||
project "xsk-iw8"
|
||||
kind "StaticLib"
|
||||
language "C++"
|
||||
|
||||
pchheader "stdafx.hpp"
|
||||
pchsource "src/iw8/stdafx.cpp"
|
||||
|
||||
files {
|
||||
"./src/iw8/**.h",
|
||||
"./src/iw8/**.hpp",
|
||||
@ -260,13 +385,12 @@ project "xsk-gsc-iw8"
|
||||
"./src"
|
||||
}
|
||||
|
||||
project "xsk-gsc-iw9"
|
||||
fmt:include()
|
||||
|
||||
project "xsk-iw9"
|
||||
kind "StaticLib"
|
||||
language "C++"
|
||||
|
||||
pchheader "stdafx.hpp"
|
||||
pchsource "src/iw9/stdafx.cpp"
|
||||
|
||||
files {
|
||||
"./src/iw9/**.h",
|
||||
"./src/iw9/**.hpp",
|
||||
@ -278,30 +402,45 @@ project "xsk-gsc-iw9"
|
||||
"./src"
|
||||
}
|
||||
|
||||
project "xsk-gsc-s1"
|
||||
fmt:include()
|
||||
|
||||
project "xsk-h1"
|
||||
kind "StaticLib"
|
||||
language "C++"
|
||||
|
||||
pchheader "stdafx.hpp"
|
||||
pchsource "src/s1/stdafx.cpp"
|
||||
|
||||
files {
|
||||
"./src/s1/**.h",
|
||||
"./src/s1/**.hpp",
|
||||
"./src/s1/**.cpp"
|
||||
"./src/h1/**.h",
|
||||
"./src/h1/**.hpp",
|
||||
"./src/h1/**.cpp"
|
||||
}
|
||||
|
||||
includedirs {
|
||||
"./src/s1",
|
||||
"./src/h1",
|
||||
"./src"
|
||||
}
|
||||
|
||||
project "xsk-gsc-s2"
|
||||
fmt:include()
|
||||
|
||||
project "xsk-h2"
|
||||
kind "StaticLib"
|
||||
language "C++"
|
||||
|
||||
pchheader "stdafx.hpp"
|
||||
pchsource "src/s2/stdafx.cpp"
|
||||
files {
|
||||
"./src/h2/**.h",
|
||||
"./src/h2/**.hpp",
|
||||
"./src/h2/**.cpp"
|
||||
}
|
||||
|
||||
includedirs {
|
||||
"./src/h2",
|
||||
"./src"
|
||||
}
|
||||
|
||||
fmt:include()
|
||||
|
||||
project "xsk-s2"
|
||||
kind "StaticLib"
|
||||
language "C++"
|
||||
|
||||
files {
|
||||
"./src/s2/**.h",
|
||||
@ -314,13 +453,12 @@ project "xsk-gsc-s2"
|
||||
"./src"
|
||||
}
|
||||
|
||||
project "xsk-gsc-s4"
|
||||
fmt:include()
|
||||
|
||||
project "xsk-s4"
|
||||
kind "StaticLib"
|
||||
language "C++"
|
||||
|
||||
pchheader "stdafx.hpp"
|
||||
pchsource "src/s4/stdafx.cpp"
|
||||
|
||||
files {
|
||||
"./src/s4/**.h",
|
||||
"./src/s4/**.hpp",
|
||||
@ -332,13 +470,12 @@ project "xsk-gsc-s4"
|
||||
"./src"
|
||||
}
|
||||
|
||||
project "xsk-arc-t6"
|
||||
fmt:include()
|
||||
|
||||
project "xsk-t6"
|
||||
kind "StaticLib"
|
||||
language "C++"
|
||||
|
||||
pchheader "stdafx.hpp"
|
||||
pchsource "src/t6/stdafx.cpp"
|
||||
|
||||
files {
|
||||
"./src/t6/**.h",
|
||||
"./src/t6/**.hpp",
|
||||
@ -350,59 +487,8 @@ project "xsk-arc-t6"
|
||||
"./src"
|
||||
}
|
||||
|
||||
project "xsk-gsc-iw5c"
|
||||
kind "StaticLib"
|
||||
language "C++"
|
||||
|
||||
pchheader "stdafx.hpp"
|
||||
pchsource "src/experimental/iw5c/stdafx.cpp"
|
||||
|
||||
files {
|
||||
"./src/experimental/iw5c/**.h",
|
||||
"./src/experimental/iw5c/**.hpp",
|
||||
"./src/experimental/iw5c/**.cpp"
|
||||
}
|
||||
|
||||
includedirs {
|
||||
"./src/experimental/iw5c",
|
||||
"./src"
|
||||
}
|
||||
|
||||
project "xsk-gsc-iw6c"
|
||||
kind "StaticLib"
|
||||
language "C++"
|
||||
|
||||
pchheader "stdafx.hpp"
|
||||
pchsource "src/experimental/iw6c/stdafx.cpp"
|
||||
|
||||
files {
|
||||
"./src/experimental/iw6c/**.h",
|
||||
"./src/experimental/iw6c/**.hpp",
|
||||
"./src/experimental/iw6c/**.cpp"
|
||||
}
|
||||
|
||||
includedirs {
|
||||
"./src/experimental/iw6c",
|
||||
"./src"
|
||||
}
|
||||
|
||||
project "xsk-gsc-s1c"
|
||||
kind "StaticLib"
|
||||
language "C++"
|
||||
|
||||
pchheader "stdafx.hpp"
|
||||
pchsource "src/experimental/s1c/stdafx.cpp"
|
||||
|
||||
files {
|
||||
"./src/experimental/s1c/**.h",
|
||||
"./src/experimental/s1c/**.hpp",
|
||||
"./src/experimental/s1c/**.cpp"
|
||||
}
|
||||
|
||||
includedirs {
|
||||
"./src/experimental/s1c",
|
||||
"./src"
|
||||
}
|
||||
fmt:include()
|
||||
|
||||
group "Dependencies"
|
||||
fmt:project()
|
||||
zlib:project()
|
||||
|
@ -1,26 +0,0 @@
|
||||
// Copyright 2022 xensik. All rights reserved.
|
||||
//
|
||||
// Use of this source code is governed by a GNU GPLv3 license
|
||||
// that can be found in the LICENSE file.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <cstdio>
|
||||
#include <algorithm>
|
||||
#include <array>
|
||||
#include <filesystem>
|
||||
#include <fstream>
|
||||
#include <functional>
|
||||
#include <iostream>
|
||||
#include <map>
|
||||
#include <memory>
|
||||
#include <regex>
|
||||
#include <set>
|
||||
#include <sstream>
|
||||
#include <stack>
|
||||
#include <stdexcept>
|
||||
#include <string>
|
||||
#include <unordered_map>
|
||||
#include <vector>
|
||||
|
||||
using namespace std::literals;
|
@ -1,554 +0,0 @@
|
||||
// Copyright 2022 xensik. All rights reserved.
|
||||
//
|
||||
// Use of this source code is governed by a GNU GPLv3 license
|
||||
// that can be found in the LICENSE file.
|
||||
|
||||
#include "stdafx.hpp"
|
||||
#include "iw5c.hpp"
|
||||
|
||||
namespace xsk::gsc::iw5c
|
||||
{
|
||||
|
||||
auto assembler::output_script() -> std::vector<std::uint8_t>
|
||||
{
|
||||
std::vector<std::uint8_t> script;
|
||||
|
||||
if (script_ == nullptr) return script;
|
||||
|
||||
script.resize(script_->pos());
|
||||
std::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());
|
||||
std::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<function::ptr> functions;
|
||||
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<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 opdata = utils::string::parse_code(line);
|
||||
|
||||
if (switchnum)
|
||||
{
|
||||
if (opdata[0] == "case" || opdata[0] == "default")
|
||||
{
|
||||
for (auto& entry : opdata)
|
||||
{
|
||||
func->instructions.back()->data.push_back(entry);
|
||||
}
|
||||
switchnum--;
|
||||
continue;
|
||||
}
|
||||
|
||||
throw asm_error("invalid instruction inside endswitch \""s + line + "\"!");
|
||||
}
|
||||
else
|
||||
{
|
||||
auto inst = std::make_unique<instruction>();
|
||||
inst->index = index;
|
||||
inst->opcode = resolver::opcode_id(opdata[0]);
|
||||
inst->size = opcode_size(inst->opcode);
|
||||
opdata.erase(opdata.begin());
|
||||
inst->data = std::move(opdata);
|
||||
|
||||
switch (static_cast<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[0] = inst->data[0].substr(4);
|
||||
break;
|
||||
case opcode::OP_endswitch:
|
||||
switchnum = static_cast<std::uint16_t>(std::stoi(inst->data[0]));
|
||||
inst->size += 7 * switchnum;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
index += inst->size;
|
||||
func->instructions.push_back(std::move(inst));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
assemble(file, functions);
|
||||
}
|
||||
|
||||
void assembler::assemble(const std::string& file, std::vector<function::ptr>& funcs)
|
||||
{
|
||||
script_ = std::make_unique<utils::byte_buffer>(0x100000);
|
||||
stack_ = std::make_unique<utils::byte_buffer>(0x100000);
|
||||
filename_ = file;
|
||||
functions_ = std::move(funcs);
|
||||
|
||||
script_->write_endian<std::uint8_t>(static_cast<std::uint8_t>(opcode::OP_End));
|
||||
|
||||
for (const auto& func : functions_)
|
||||
{
|
||||
assemble_function(func);
|
||||
}
|
||||
}
|
||||
|
||||
void assembler::assemble_function(const function::ptr& func)
|
||||
{
|
||||
labels_ = func->labels;
|
||||
|
||||
func->id = resolver::token_id(func->name);
|
||||
|
||||
stack_->write_endian<std::uint32_t>(func->size);
|
||||
stack_->write_endian<std::uint16_t>(static_cast<std::uint16_t>(func->id));
|
||||
|
||||
if (func->id == 0)
|
||||
{
|
||||
stack_->write_c_string(func->name);
|
||||
}
|
||||
|
||||
for (const auto& inst : func->instructions)
|
||||
{
|
||||
assemble_instruction(inst);
|
||||
}
|
||||
}
|
||||
|
||||
void assembler::assemble_instruction(const instruction::ptr& inst)
|
||||
{
|
||||
script_->write_endian<std::uint8_t>(static_cast<std::uint8_t>(inst->opcode));
|
||||
|
||||
switch (static_cast<opcode>(inst->opcode))
|
||||
{
|
||||
case opcode::OP_End:
|
||||
case opcode::OP_Return:
|
||||
case opcode::OP_GetUndefined:
|
||||
case opcode::OP_GetZero:
|
||||
case opcode::OP_waittillFrameEnd:
|
||||
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_EvalArray:
|
||||
case opcode::OP_EvalArrayRef:
|
||||
case opcode::OP_EvalLocalArrayRefCached0:
|
||||
case opcode::OP_ClearArray:
|
||||
case opcode::OP_EmptyArray:
|
||||
case opcode::OP_AddArray:
|
||||
case opcode::OP_PreScriptCall:
|
||||
case opcode::OP_ScriptFunctionCallPointer:
|
||||
case opcode::OP_ScriptMethodCallPointer:
|
||||
case opcode::OP_GetLevelObject:
|
||||
case opcode::OP_GetAnimObject:
|
||||
case opcode::OP_GetSelf:
|
||||
case opcode::OP_GetThisthread:
|
||||
case opcode::OP_GetLevel:
|
||||
case opcode::OP_GetGame:
|
||||
case opcode::OP_GetAnim:
|
||||
case opcode::OP_GetGameRef:
|
||||
case opcode::OP_inc:
|
||||
case opcode::OP_dec:
|
||||
case opcode::OP_bit_or:
|
||||
case opcode::OP_bit_ex_or:
|
||||
case opcode::OP_bit_and:
|
||||
case opcode::OP_equality:
|
||||
case opcode::OP_inequality:
|
||||
case opcode::OP_less:
|
||||
case opcode::OP_greater:
|
||||
case opcode::OP_less_equal:
|
||||
case opcode::OP_waittillmatch2:
|
||||
case opcode::OP_waittill:
|
||||
case opcode::OP_notify:
|
||||
case opcode::OP_endon:
|
||||
case opcode::OP_voidCodepos:
|
||||
case opcode::OP_vector:
|
||||
case opcode::OP_greater_equal:
|
||||
case opcode::OP_shift_left:
|
||||
case opcode::OP_shift_right:
|
||||
case opcode::OP_plus:
|
||||
case opcode::OP_minus:
|
||||
case opcode::OP_multiply:
|
||||
case opcode::OP_divide:
|
||||
case opcode::OP_mod:
|
||||
case opcode::OP_size:
|
||||
case opcode::OP_GetSelfObject:
|
||||
case opcode::OP_SafeSetVariableFieldCached0:
|
||||
case opcode::OP_clearparams:
|
||||
case opcode::OP_checkclearparams:
|
||||
case opcode::OP_EvalLocalVariableRefCached0:
|
||||
case opcode::OP_EvalNewLocalVariableRefCached0:
|
||||
case opcode::OP_SetVariableField:
|
||||
case opcode::OP_ClearVariableField:
|
||||
case opcode::OP_SetLocalVariableFieldCached0:
|
||||
case opcode::OP_ClearLocalVariableFieldCached0:
|
||||
case opcode::OP_wait:
|
||||
case opcode::OP_DecTop:
|
||||
case opcode::OP_CastFieldObject:
|
||||
case opcode::OP_CastBool:
|
||||
case opcode::OP_BoolNot:
|
||||
case opcode::OP_BoolComplement:
|
||||
break;
|
||||
case opcode::OP_GetByte:
|
||||
case opcode::OP_GetNegByte:
|
||||
script_->write_endian<std::uint8_t>(static_cast<std::uint8_t>(std::stoi(inst->data[0])));
|
||||
break;
|
||||
case opcode::OP_GetUnsignedShort:
|
||||
case opcode::OP_GetNegUnsignedShort:
|
||||
script_->write_endian<std::uint16_t>(static_cast<std::uint16_t>(std::stoi(inst->data[0])));
|
||||
break;
|
||||
case opcode::OP_GetInteger:
|
||||
script_->write_endian<std::int32_t>(std::stoi(inst->data[0]));
|
||||
break;
|
||||
case opcode::OP_GetFloat:
|
||||
script_->write_endian<float>(std::stof(inst->data[0]));
|
||||
break;
|
||||
case opcode::OP_GetVector:
|
||||
inst->size += script_->align(4);
|
||||
script_->write_endian<float>(std::stof(inst->data[0]));
|
||||
script_->write_endian<float>(std::stof(inst->data[1]));
|
||||
script_->write_endian<float>(std::stof(inst->data[2]));
|
||||
break;
|
||||
case opcode::OP_GetString:
|
||||
case opcode::OP_GetIString:
|
||||
script_->write_endian<std::uint16_t>(0);
|
||||
stack_->write_c_string(inst->data[0]);
|
||||
break;
|
||||
case opcode::OP_GetAnimation:
|
||||
script_->write_endian<std::uint32_t>(0);
|
||||
stack_->write_c_string(inst->data[0]);
|
||||
stack_->write_c_string(inst->data[1]);
|
||||
break;
|
||||
case opcode::OP_GetAnimTree:
|
||||
script_->write_endian<std::uint8_t>(0);
|
||||
stack_->write_c_string(inst->data[0]);
|
||||
break;
|
||||
case opcode::OP_waittillmatch:
|
||||
script_->write_endian<std::uint8_t>(static_cast<std::uint8_t>(std::stoi(inst->data[0])));
|
||||
break;
|
||||
case opcode::OP_CreateLocalVariable:
|
||||
case opcode::OP_RemoveLocalVariables:
|
||||
case opcode::OP_EvalLocalVariableCached:
|
||||
case opcode::OP_EvalLocalArrayCached:
|
||||
case opcode::OP_EvalNewLocalArrayRefCached0:
|
||||
case opcode::OP_EvalLocalArrayRefCached:
|
||||
case opcode::OP_SafeCreateVariableFieldCached:
|
||||
case opcode::OP_SafeSetVariableFieldCached:
|
||||
case opcode::OP_SafeSetWaittillVariableFieldCached:
|
||||
case opcode::OP_EvalLocalVariableRefCached:
|
||||
case opcode::OP_SetNewLocalVariableFieldCached0:
|
||||
case opcode::OP_SetLocalVariableFieldCached:
|
||||
case opcode::OP_ClearLocalVariableFieldCached:
|
||||
case opcode::OP_EvalLocalVariableObjectCached:
|
||||
script_->write_endian<std::uint8_t>(static_cast<std::uint8_t>(std::stoi(inst->data[0])));
|
||||
break;
|
||||
case opcode::OP_EvalLevelFieldVariable:
|
||||
case opcode::OP_EvalAnimFieldVariable:
|
||||
case opcode::OP_EvalSelfFieldVariable:
|
||||
case opcode::OP_EvalFieldVariable:
|
||||
case opcode::OP_EvalLevelFieldVariableRef:
|
||||
case opcode::OP_EvalAnimFieldVariableRef:
|
||||
case opcode::OP_EvalSelfFieldVariableRef:
|
||||
case opcode::OP_EvalFieldVariableRef:
|
||||
case opcode::OP_ClearFieldVariable:
|
||||
case opcode::OP_SetLevelFieldVariableField:
|
||||
case opcode::OP_SetAnimFieldVariableField:
|
||||
case opcode::OP_SetSelfFieldVariableField:
|
||||
assemble_field_variable(inst);
|
||||
break;
|
||||
case opcode::OP_ScriptThreadCallPointer:
|
||||
case opcode::OP_ScriptChildThreadCallPointer:
|
||||
case opcode::OP_ScriptMethodThreadCallPointer:
|
||||
case opcode::OP_ScriptMethodChildThreadCallPointer:
|
||||
case opcode::OP_CallBuiltinPointer:
|
||||
case opcode::OP_CallBuiltinMethodPointer:
|
||||
script_->write_endian<std::uint8_t>(static_cast<std::uint8_t>(std::stoi(inst->data[0])));
|
||||
break;
|
||||
case opcode::OP_ScriptLocalFunctionCall2:
|
||||
case opcode::OP_ScriptLocalFunctionCall:
|
||||
case opcode::OP_ScriptLocalMethodCall:
|
||||
case opcode::OP_GetLocalFunction:
|
||||
assemble_local_call(inst, false);
|
||||
break;
|
||||
case opcode::OP_ScriptLocalThreadCall:
|
||||
case opcode::OP_ScriptLocalMethodThreadCall:
|
||||
case opcode::OP_ScriptLocalChildThreadCall:
|
||||
case opcode::OP_ScriptLocalMethodChildThreadCall:
|
||||
assemble_local_call(inst, true);
|
||||
break;
|
||||
case opcode::OP_ScriptFarFunctionCall2:
|
||||
case opcode::OP_ScriptFarFunctionCall:
|
||||
case opcode::OP_ScriptFarMethodCall:
|
||||
case opcode::OP_GetFarFunction:
|
||||
assemble_far_call(inst, false);
|
||||
break;
|
||||
case opcode::OP_ScriptFarThreadCall:
|
||||
case opcode::OP_ScriptFarChildThreadCall:
|
||||
case opcode::OP_ScriptFarMethodThreadCall:
|
||||
case opcode::OP_ScriptFarMethodChildThreadCall:
|
||||
assemble_far_call(inst, true);
|
||||
break;
|
||||
case opcode::OP_CallBuiltin:
|
||||
assemble_builtin_call(inst, false, true);
|
||||
break;
|
||||
case opcode::OP_CallBuiltinMethod:
|
||||
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:
|
||||
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:
|
||||
assemble_builtin_call(inst, true, false);
|
||||
break;
|
||||
case opcode::OP_JumpOnFalseExpr:
|
||||
case opcode::OP_JumpOnTrueExpr:
|
||||
case opcode::OP_JumpOnFalse:
|
||||
case opcode::OP_JumpOnTrue:
|
||||
assemble_jump(inst, true, false);
|
||||
break;
|
||||
case opcode::OP_jumpback:
|
||||
assemble_jump(inst, false, true);
|
||||
break;
|
||||
case opcode::OP_jump:
|
||||
assemble_jump(inst, false, false);
|
||||
break;
|
||||
case opcode::OP_switch:
|
||||
assemble_switch(inst);
|
||||
break;
|
||||
case opcode::OP_endswitch:
|
||||
assemble_end_switch(inst);
|
||||
break;
|
||||
default:
|
||||
throw asm_error(utils::string::va("unhandled opcode 0x%X at index '%04X'!", inst->opcode, inst->index));
|
||||
}
|
||||
}
|
||||
|
||||
void assembler::assemble_builtin_call(const instruction::ptr& inst, bool method, bool args)
|
||||
{
|
||||
if (args)
|
||||
{
|
||||
script_->write_endian<std::uint8_t>(static_cast<std::uint8_t>(std::stoi(inst->data[1])));
|
||||
}
|
||||
|
||||
const auto id = method ? resolver::method_id(inst->data[0]) : resolver::function_id(inst->data[0]);
|
||||
|
||||
script_->write_endian<std::uint16_t>(id);
|
||||
}
|
||||
|
||||
void assembler::assemble_local_call(const instruction::ptr& inst, bool thread)
|
||||
{
|
||||
const auto addr = resolve_function(inst->data[0]);
|
||||
const auto offset = static_cast<std::int32_t>(addr - inst->index - 1);
|
||||
|
||||
assemble_offset(offset);
|
||||
|
||||
if (thread)
|
||||
{
|
||||
script_->write_endian<std::uint8_t>(static_cast<std::uint8_t>(std::stoi(inst->data[1])));
|
||||
}
|
||||
}
|
||||
|
||||
void assembler::assemble_far_call(const instruction::ptr& inst, bool thread)
|
||||
{
|
||||
script_->write_endian<std::uint8_t>(0);
|
||||
script_->write_endian<std::uint16_t>(0);
|
||||
|
||||
if (thread)
|
||||
{
|
||||
script_->write_endian<std::uint8_t>(static_cast<std::uint8_t>(std::stoi(inst->data[2])));
|
||||
}
|
||||
|
||||
const auto file_id = resolver::token_id(inst->data[0]);
|
||||
const auto func_id = resolver::token_id(inst->data[1]);
|
||||
|
||||
stack_->write_endian<std::uint16_t>(file_id);
|
||||
if (file_id == 0) stack_->write_c_string(inst->data[0]);
|
||||
stack_->write_endian<std::uint16_t>(func_id);
|
||||
if (func_id == 0) stack_->write_c_string(inst->data[1]);
|
||||
}
|
||||
|
||||
void assembler::assemble_switch(const instruction::ptr& inst)
|
||||
{
|
||||
const auto addr = resolve_label(inst->data[0]);
|
||||
|
||||
script_->write_endian<std::int32_t>(addr - inst->index - 4);
|
||||
}
|
||||
|
||||
void assembler::assemble_end_switch(const instruction::ptr& inst)
|
||||
{
|
||||
const auto count = std::stoul(inst->data[0]);
|
||||
|
||||
script_->write_endian<std::uint16_t>(static_cast<std::uint16_t>(count));
|
||||
|
||||
std::uint32_t index = inst->index + 3;
|
||||
|
||||
for (auto i = 0u; i < count; i++)
|
||||
{
|
||||
if (inst->data[1 + (3 * i)] == "case")
|
||||
{
|
||||
if (utils::string::is_number(inst->data[1 + (3 * i) + 1]))
|
||||
{
|
||||
script_->write_endian<uint32_t>((std::stoi(inst->data[1 + (3 * i) + 1]) & 0xFFFFFF) + 0x800000);
|
||||
}
|
||||
else
|
||||
{
|
||||
script_->write_endian<uint32_t>(i + 1);
|
||||
stack_->write_c_string(inst->data[1 + (3 * i) + 1]);
|
||||
}
|
||||
|
||||
index += 4;
|
||||
|
||||
const auto addr = resolve_label(inst->data[1 + (3 * i) + 2]);
|
||||
|
||||
assemble_offset(addr - index);
|
||||
|
||||
index += 3;
|
||||
}
|
||||
else if (inst->data[1 + (3 * i)] == "default")
|
||||
{
|
||||
script_->write_endian<uint32_t>(0);
|
||||
stack_->write_c_string("\x01");
|
||||
|
||||
index += 4;
|
||||
|
||||
const auto addr = resolve_label(inst->data[1 + (3 * i) + 1]);
|
||||
|
||||
assemble_offset(addr - index);
|
||||
|
||||
index += 3;
|
||||
}
|
||||
else
|
||||
{
|
||||
throw asm_error("invalid switch case '" + inst->data[1 + (3 * i)] + "'!");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void assembler::assemble_field_variable(const instruction::ptr& inst)
|
||||
{
|
||||
auto id = resolver::token_id(inst->data[0]);
|
||||
|
||||
if (id == 0) id = 0xFFFF;
|
||||
|
||||
script_->write_endian<std::uint16_t>(id);
|
||||
|
||||
if (id > max_string_id)
|
||||
{
|
||||
stack_->write_endian<std::uint16_t>(0);
|
||||
stack_->write_c_string(inst->data[0]);
|
||||
}
|
||||
}
|
||||
|
||||
void assembler::assemble_jump(const instruction::ptr& inst, bool expr, bool back)
|
||||
{
|
||||
const auto addr = resolve_label(inst->data[0]);
|
||||
|
||||
if (expr)
|
||||
{
|
||||
script_->write_endian<std::int16_t>(static_cast<std::int16_t>(addr - inst->index - 3));
|
||||
}
|
||||
else if (back)
|
||||
{
|
||||
script_->write_endian<std::int16_t>(static_cast<std::int16_t>((inst->index + 3) - addr));
|
||||
}
|
||||
else
|
||||
{
|
||||
script_->write_endian<std::int32_t>(static_cast<std::int32_t>(addr - inst->index - 5));
|
||||
}
|
||||
}
|
||||
|
||||
void assembler::assemble_offset(std::int32_t offset)
|
||||
{
|
||||
std::array<std::uint8_t, 4> bytes = {};
|
||||
|
||||
offset = (offset << 10) >> 8;
|
||||
|
||||
*reinterpret_cast<std::int32_t*>(bytes.data()) = offset;
|
||||
|
||||
script_->write_endian<std::uint8_t>(bytes[2]);
|
||||
script_->write_endian<std::uint8_t>(bytes[1]);
|
||||
script_->write_endian<std::uint8_t>(bytes[0]);
|
||||
}
|
||||
|
||||
auto assembler::resolve_function(const std::string& name) -> std::int32_t
|
||||
{
|
||||
for (const auto& entry : functions_)
|
||||
{
|
||||
if (entry->name == name)
|
||||
{
|
||||
return entry->index;
|
||||
}
|
||||
}
|
||||
|
||||
throw asm_error("couldn't resolve local function address of '" + name + "'!");
|
||||
}
|
||||
|
||||
auto assembler::resolve_label(const std::string& name) -> std::int32_t
|
||||
{
|
||||
for (const auto& entry : labels_)
|
||||
{
|
||||
if (entry.second == name)
|
||||
{
|
||||
return entry.first;
|
||||
}
|
||||
}
|
||||
|
||||
throw asm_error("couldn't resolve label address of '" + name + "'!");
|
||||
}
|
||||
|
||||
} // namespace xsk::gsc::iw5c
|
@ -1,40 +0,0 @@
|
||||
// Copyright 2022 xensik. All rights reserved.
|
||||
//
|
||||
// Use of this source code is governed by a GNU GPLv3 license
|
||||
// that can be found in the LICENSE file.
|
||||
|
||||
#pragma once
|
||||
|
||||
namespace xsk::gsc::iw5c
|
||||
{
|
||||
|
||||
class assembler : public gsc::assembler
|
||||
{
|
||||
std::string filename_;
|
||||
utils::byte_buffer::ptr script_;
|
||||
utils::byte_buffer::ptr stack_;
|
||||
std::vector<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<function::ptr>& funcs);
|
||||
|
||||
private:
|
||||
void assemble_function(const function::ptr& func);
|
||||
void assemble_instruction(const instruction::ptr& inst);
|
||||
void assemble_builtin_call(const instruction::ptr& inst, bool method, bool args);
|
||||
void assemble_local_call(const instruction::ptr& inst, bool thread);
|
||||
void assemble_far_call(const instruction::ptr& inst, bool thread);
|
||||
void assemble_switch(const instruction::ptr& inst);
|
||||
void assemble_end_switch(const instruction::ptr& inst);
|
||||
void assemble_field_variable(const instruction::ptr& inst);
|
||||
void assemble_jump(const instruction::ptr& inst, bool expr, bool back);
|
||||
void assemble_offset(std::int32_t offset);
|
||||
auto resolve_function(const std::string& name) -> std::int32_t;
|
||||
auto resolve_label(const std::string& name) -> std::int32_t;
|
||||
};
|
||||
|
||||
} // namespace xsk::gsc::iw5c
|
File diff suppressed because it is too large
Load Diff
@ -1,159 +0,0 @@
|
||||
// Copyright 2022 xensik. All rights reserved.
|
||||
//
|
||||
// Use of this source code is governed by a GNU GPLv3 license
|
||||
// that can be found in the LICENSE file.
|
||||
|
||||
#pragma once
|
||||
|
||||
namespace xsk::gsc::iw5c
|
||||
{
|
||||
|
||||
enum class opcode : std::uint8_t;
|
||||
|
||||
class compiler : public gsc::compiler
|
||||
{
|
||||
build mode_;
|
||||
std::string filename_;
|
||||
std::vector<function::ptr> assembly_;
|
||||
function::ptr function_;
|
||||
std::uint32_t index_;
|
||||
std::uint32_t label_idx_;
|
||||
std::uint8_t stack_idx_;
|
||||
std::vector<std::string> local_stack_;
|
||||
std::vector<std::string> local_functions_;
|
||||
std::vector<include_t> includes_;
|
||||
std::vector<animtree_t> animtrees_;
|
||||
std::unordered_map<std::string, ast::expr> constants_;
|
||||
std::vector<block*> break_blks_;
|
||||
std::vector<block*> continue_blks_;
|
||||
bool can_break_;
|
||||
bool can_continue_;
|
||||
bool developer_thread_;
|
||||
|
||||
public:
|
||||
auto output() -> std::vector<function::ptr>;
|
||||
void compile(const std::string& file, std::vector<std::uint8_t>& data);
|
||||
void mode(build mode);
|
||||
|
||||
private:
|
||||
auto parse_buffer(const std::string& file, const char* data, size_t size) -> ast::program::ptr;
|
||||
auto parse_file(const std::string& file) -> ast::program::ptr;
|
||||
void compile_program(const ast::program::ptr& program);
|
||||
void emit_include(const ast::include::ptr& include);
|
||||
void emit_declaration(const ast::decl& decl);
|
||||
void emit_decl_usingtree(const ast::decl_usingtree::ptr& animtree);
|
||||
void emit_decl_constant(const ast::decl_constant::ptr& constant);
|
||||
void emit_decl_thread(const ast::decl_thread::ptr& thread);
|
||||
void emit_stmt(const ast::stmt& stmt, const block::ptr& blk, bool last);
|
||||
void emit_stmt_list(const ast::stmt_list::ptr& stmt, const block::ptr& blk, bool last);
|
||||
void emit_stmt_dev(const ast::stmt_dev::ptr& stmt, const block::ptr& blk, bool last);
|
||||
void emit_stmt_expr(const ast::stmt_expr::ptr& stmt, const block::ptr& blk);
|
||||
void emit_stmt_call(const ast::stmt_call::ptr& stmt, const block::ptr& blk);
|
||||
void emit_stmt_assign(const ast::stmt_assign::ptr& stmt, const block::ptr& blk);
|
||||
void emit_stmt_endon(const ast::stmt_endon::ptr& stmt, const block::ptr& blk);
|
||||
void emit_stmt_notify(const ast::stmt_notify::ptr& stmt, const block::ptr& blk);
|
||||
void emit_stmt_wait(const ast::stmt_wait::ptr& stmt, const block::ptr& blk);
|
||||
void emit_stmt_waittill(const ast::stmt_waittill::ptr& stmt, const block::ptr& blk);
|
||||
void emit_stmt_waittillmatch(const ast::stmt_waittillmatch::ptr& stmt, const block::ptr& blk);
|
||||
void emit_stmt_waittillframeend(const ast::stmt_waittillframeend::ptr& stmt, const block::ptr& blk);
|
||||
void emit_stmt_if(const ast::stmt_if::ptr& stmt, const block::ptr& blk, bool last);
|
||||
void emit_stmt_ifelse(const ast::stmt_ifelse::ptr& stmt, const block::ptr& blk, bool last);
|
||||
void emit_stmt_while(const ast::stmt_while::ptr& stmt, const block::ptr& blk);
|
||||
void emit_stmt_dowhile(const ast::stmt_dowhile::ptr& stmt, const block::ptr& blk);
|
||||
void emit_stmt_for(const ast::stmt_for::ptr& stmt, const block::ptr& blk);
|
||||
void emit_stmt_foreach(const ast::stmt_foreach::ptr& stmt, const block::ptr& blk);
|
||||
void emit_stmt_switch(const ast::stmt_switch::ptr& stmt, const block::ptr& blk);
|
||||
void emit_stmt_case(const ast::stmt_case::ptr& stmt, const block::ptr& blk);
|
||||
void emit_stmt_default(const ast::stmt_default::ptr& stmt, const block::ptr& blk);
|
||||
void emit_stmt_break(const ast::stmt_break::ptr& stmt, const block::ptr& blk);
|
||||
void emit_stmt_continue(const ast::stmt_continue::ptr& stmt, const block::ptr& blk);
|
||||
void emit_stmt_return(const ast::stmt_return::ptr& stmt, const block::ptr& blk);
|
||||
void emit_stmt_breakpoint(const ast::stmt_breakpoint::ptr& stmt, const block::ptr& blk);
|
||||
void emit_stmt_prof_begin(const ast::stmt_prof_begin::ptr& stmt, const block::ptr& blk);
|
||||
void emit_stmt_prof_end(const ast::stmt_prof_end::ptr& stmt, const block::ptr& blk);
|
||||
void emit_expr(const ast::expr& expr, const block::ptr& blk);
|
||||
void emit_expr_assign(const ast::expr_assign::ptr& expr, const block::ptr& blk);
|
||||
void emit_expr_clear(const ast::expr& expr, const block::ptr& blk);
|
||||
void emit_expr_clear_local(const ast::expr_identifier::ptr& expr, const block::ptr& blk);
|
||||
void emit_expr_increment(const ast::expr_increment::ptr& expr, const block::ptr& blk, bool is_stmt);
|
||||
void emit_expr_decrement(const ast::expr_decrement::ptr& expr, const block::ptr& blk, bool is_stmt);
|
||||
void emit_expr_ternary(const ast::expr_ternary::ptr& expr, const block::ptr& blk);
|
||||
void emit_expr_binary(const ast::expr_binary::ptr& expr, const block::ptr& blk);
|
||||
void emit_expr_and(const ast::expr_and::ptr& expr, const block::ptr& blk);
|
||||
void emit_expr_or(const ast::expr_or::ptr& expr, const block::ptr& blk);
|
||||
void emit_expr_complement(const ast::expr_complement::ptr& expr, const block::ptr& blk);
|
||||
void emit_expr_negate(const ast::expr_negate::ptr& expr, const block::ptr& blk);
|
||||
void emit_expr_not(const ast::expr_not::ptr& expr, const block::ptr& blk);
|
||||
void emit_expr_call(const ast::expr_call::ptr& expr, const block::ptr& blk, bool is_stmt);
|
||||
void emit_expr_call_pointer(const ast::expr_pointer::ptr& expr, const block::ptr& blk, bool is_stmt);
|
||||
void emit_expr_call_function(const ast::expr_function::ptr& expr, const block::ptr& blk, bool is_stmt);
|
||||
void emit_expr_method(const ast::expr_method::ptr& expr, const block::ptr& blk, bool is_stmt);
|
||||
void emit_expr_method_pointer(const ast::expr_pointer::ptr& expr, const ast::expr& obj, const block::ptr& blk, bool is_stmt);
|
||||
void emit_expr_method_function(const ast::expr_function::ptr& expr, const ast::expr& obj, const block::ptr& blk, bool is_stmt);
|
||||
void emit_expr_add_array(const ast::expr_add_array::ptr& expr, const block::ptr& blk);
|
||||
void emit_expr_parameters(const ast::expr_parameters::ptr& expr, const block::ptr& blk);
|
||||
void emit_expr_arguments(const ast::expr_arguments::ptr& expr, const block::ptr& blk);
|
||||
void emit_expr_reference(const ast::expr_reference::ptr& expr, const block::ptr& blk);
|
||||
void emit_expr_size(const ast::expr_size::ptr& expr, const block::ptr& blk);
|
||||
void emit_expr_tuple(const ast::expr_tuple::ptr& expr, const block::ptr& blk);
|
||||
void emit_expr_variable_ref(const ast::expr& expr, const block::ptr& blk, bool set);
|
||||
void emit_expr_array_ref(const ast::expr_array::ptr& expr, const block::ptr& blk, bool set);
|
||||
void emit_expr_field_ref(const ast::expr_field::ptr& expr, const block::ptr& blk, bool set);
|
||||
void emit_expr_local_ref(const ast::expr_identifier::ptr& expr, const block::ptr& blk, bool set);
|
||||
void emit_expr_variable(const ast::expr& expr, const block::ptr& blk);
|
||||
void emit_expr_array(const ast::expr_array::ptr& expr, const block::ptr& blk);
|
||||
void emit_expr_field(const ast::expr_field::ptr& expr, const block::ptr& blk);
|
||||
void emit_expr_local(const ast::expr_identifier::ptr& expr, const block::ptr& blk);
|
||||
void emit_expr_object(const ast::expr& expr, const block::ptr& blk);
|
||||
void emit_expr_vector(const ast::expr_vector::ptr& expr, const block::ptr& blk);
|
||||
void emit_expr_animation(const ast::expr_animation::ptr& expr);
|
||||
void emit_expr_animtree(const ast::expr_animtree::ptr& expr);
|
||||
void emit_expr_istring(const ast::expr_istring::ptr& expr);
|
||||
void emit_expr_string(const ast::expr_string::ptr& expr);
|
||||
void emit_expr_float(const ast::expr_float::ptr& expr);
|
||||
void emit_expr_integer(const ast::expr_integer::ptr& expr);
|
||||
void emit_expr_false(const ast::expr_false::ptr& expr);
|
||||
void emit_expr_true(const ast::expr_true::ptr& expr);
|
||||
void emit_create_local_vars(const block::ptr& blk);
|
||||
void emit_remove_local_vars(const block::ptr& blk);
|
||||
void emit_opcode(opcode op);
|
||||
void emit_opcode(opcode op, const std::string& data);
|
||||
void emit_opcode(opcode op, const std::vector<std::string>& data);
|
||||
void process_thread(const ast::decl_thread::ptr& decl, const block::ptr& blk);
|
||||
void process_stmt(const ast::stmt& stmt, const block::ptr& blk);
|
||||
void process_stmt_list(const ast::stmt_list::ptr& stmt, const block::ptr& blk);
|
||||
void process_stmt_dev(const ast::stmt_dev::ptr& stmt, const block::ptr& blk);
|
||||
void process_stmt_expr(const ast::stmt_expr::ptr& stmt, const block::ptr& blk);
|
||||
void process_stmt_assign(const ast::stmt_assign::ptr& stmt, const block::ptr& blk);
|
||||
void process_stmt_waittill(const ast::stmt_waittill::ptr& stmt, const block::ptr& blk);
|
||||
void process_stmt_if(const ast::stmt_if::ptr& stmt, const block::ptr& blk);
|
||||
void process_stmt_ifelse(const ast::stmt_ifelse::ptr& stmt, const block::ptr& blk);
|
||||
void process_stmt_while(const ast::stmt_while::ptr& stmt, const block::ptr& blk);
|
||||
void process_stmt_dowhile(const ast::stmt_dowhile::ptr& stmt, const block::ptr& blk);
|
||||
void process_stmt_for(const ast::stmt_for::ptr& stmt, const block::ptr& blk);
|
||||
void process_stmt_foreach(const ast::stmt_foreach::ptr& stmt, const block::ptr& blk);
|
||||
void process_stmt_switch(const ast::stmt_switch::ptr& stmt, const block::ptr& blk);
|
||||
void process_stmt_break(const ast::stmt_break::ptr& stmt, const block::ptr& blk);
|
||||
void process_stmt_continue(const ast::stmt_continue::ptr& stmt, const block::ptr& blk);
|
||||
void process_stmt_return(const ast::stmt_return::ptr& stmt, const block::ptr& blk);
|
||||
void process_expr(const ast::expr& expr, const block::ptr& blk);
|
||||
void process_expr_tuple(const ast::expr_tuple::ptr& expr, const block::ptr& blk);
|
||||
void process_expr_parameters(const ast::expr_parameters::ptr& decl, const block::ptr& blk);
|
||||
void variable_register(const std::string& name, const block::ptr& blk);
|
||||
void variable_initialize(const ast::expr_identifier::ptr& name, const block::ptr& blk);
|
||||
void variable_create(const ast::expr_identifier::ptr& name, const block::ptr& blk);
|
||||
auto variable_stack_index(const ast::expr_identifier::ptr& name, const block::ptr& blk) -> std::uint8_t;
|
||||
auto variable_create_index(const ast::expr_identifier::ptr& name, const block::ptr& blk) -> std::string;
|
||||
auto variable_access_index(const ast::expr_identifier::ptr& name, const block::ptr& blk) -> std::string;
|
||||
auto variable_initialized(const ast::expr_identifier::ptr& name, const block::ptr& blk) -> bool;
|
||||
auto resolve_function_type(const ast::expr_function::ptr& expr) -> ast::call::type;
|
||||
auto resolve_reference_type(const ast::expr_reference::ptr& expr, bool& method) -> ast::call::type;
|
||||
auto is_constant_condition(const ast::expr& expr) -> bool;
|
||||
auto create_label() -> std::string;
|
||||
auto insert_label() -> std::string;
|
||||
void insert_label(const std::string& label);
|
||||
|
||||
auto map_known_includes(const std::string& include) -> bool;
|
||||
};
|
||||
|
||||
} // namespace xsk::gsc::iw5c
|
@ -1,23 +0,0 @@
|
||||
// Copyright 2022 xensik. All rights reserved.
|
||||
//
|
||||
// Use of this source code is governed by a GNU GPLv3 license
|
||||
// that can be found in the LICENSE file.
|
||||
|
||||
#include "stdafx.hpp"
|
||||
#include "iw5c.hpp"
|
||||
|
||||
namespace xsk::gsc::iw5c
|
||||
{
|
||||
|
||||
void context::init(build mode, read_cb_type callback)
|
||||
{
|
||||
compiler_.mode(mode);
|
||||
resolver::init(callback);
|
||||
}
|
||||
|
||||
void context::cleanup()
|
||||
{
|
||||
resolver::cleanup();
|
||||
}
|
||||
|
||||
} // namespace xsk::gsc::iw5c
|
@ -1,28 +0,0 @@
|
||||
// Copyright 2022 xensik. All rights reserved.
|
||||
//
|
||||
// Use of this source code is governed by a GNU GPLv3 license
|
||||
// that can be found in the LICENSE file.
|
||||
|
||||
#pragma once
|
||||
|
||||
namespace xsk::gsc::iw5c
|
||||
{
|
||||
|
||||
class context : public gsc::context
|
||||
{
|
||||
iw5c::assembler assembler_;
|
||||
iw5c::disassembler disassembler_;
|
||||
iw5c::compiler compiler_;
|
||||
iw5c::decompiler decompiler_;
|
||||
|
||||
public:
|
||||
void init(build mode, read_cb_type callback);
|
||||
void cleanup();
|
||||
|
||||
auto assembler() -> gsc::assembler& { return assembler_; }
|
||||
auto disassembler() -> gsc::disassembler& { return disassembler_; }
|
||||
auto compiler() -> gsc::compiler& { return compiler_; }
|
||||
auto decompiler() -> gsc::decompiler& { return decompiler_; }
|
||||
};
|
||||
|
||||
} // namespace xsk::gsc::iw5c
|
File diff suppressed because it is too large
Load Diff
@ -1,101 +0,0 @@
|
||||
// Copyright 2022 xensik. All rights reserved.
|
||||
//
|
||||
// Use of this source code is governed by a GNU GPLv3 license
|
||||
// that can be found in the LICENSE file.
|
||||
|
||||
#pragma once
|
||||
|
||||
namespace xsk::gsc::iw5c
|
||||
{
|
||||
|
||||
class decompiler : public gsc::decompiler
|
||||
{
|
||||
std::string filename_;
|
||||
ast::program::ptr program_;
|
||||
ast::decl_thread::ptr func_;
|
||||
std::unordered_map<std::uint32_t, std::string> labels_;
|
||||
std::vector<std::string> expr_labels_;
|
||||
std::vector<std::string> tern_labels_;
|
||||
std::stack<ast::node::ptr> stack_;
|
||||
std::vector<block> blocks_;
|
||||
bool in_waittill_;
|
||||
|
||||
public:
|
||||
auto output() -> std::vector<std::uint8_t>;
|
||||
void decompile(const std::string& file, std::vector<function::ptr>& funcs);
|
||||
|
||||
private:
|
||||
void decompile_function(const function::ptr& func);
|
||||
void decompile_instruction(const instruction::ptr& inst);
|
||||
void decompile_expressions(const instruction::ptr& inst);
|
||||
void decompile_statements(const ast::stmt_list::ptr& stmt);
|
||||
void decompile_loops(const ast::stmt_list::ptr& stmt);
|
||||
void decompile_switches(const ast::stmt_list::ptr& stmt);
|
||||
void decompile_ifelses(const ast::stmt_list::ptr& stmt);
|
||||
void decompile_aborts(const ast::stmt_list::ptr& stmt);
|
||||
void decompile_tuples(const ast::stmt_list::ptr& stmt);
|
||||
void decompile_if(const ast::stmt_list::ptr& stmt, std::size_t begin, std::size_t end);
|
||||
void decompile_ifelse(const ast::stmt_list::ptr& stmt, std::size_t begin, std::size_t end);
|
||||
void decompile_ifelse_end(const ast::stmt_list::ptr& stmt, std::size_t begin, std::size_t end);
|
||||
void decompile_inf(const ast::stmt_list::ptr& stmt, std::size_t begin, std::size_t end);
|
||||
void decompile_loop(const ast::stmt_list::ptr& stmt, std::size_t begin, std::size_t end);
|
||||
void decompile_while(const ast::stmt_list::ptr& stmt, std::size_t begin, std::size_t end);
|
||||
void decompile_dowhile(const ast::stmt_list::ptr& stmt, std::size_t begin, std::size_t end);
|
||||
void decompile_for(const ast::stmt_list::ptr& stmt, std::size_t begin, std::size_t end);
|
||||
void decompile_foreach(const ast::stmt_list::ptr& stmt, std::size_t begin, std::size_t end);
|
||||
void decompile_switch(const ast::stmt_list::ptr& stmt, std::size_t begin);
|
||||
auto find_location_reference(const ast::stmt_list::ptr& stmt, std::size_t begin, std::size_t end, const std::string& location) -> bool;
|
||||
auto find_location_index(const ast::stmt_list::ptr& stmt, const std::string& location) -> std::size_t;
|
||||
auto last_location_index(const ast::stmt_list::ptr& stmt, std::size_t index) -> bool;
|
||||
void process_stack(const ast::decl_thread::ptr& thread);
|
||||
void process_parameters(const ast::expr_parameters::ptr& params, const block::ptr& blk);
|
||||
void process_stmt(const ast::stmt& stmt, const block::ptr& blk);
|
||||
void process_stmt_list(const ast::stmt_list::ptr& stmt, const block::ptr& blk);
|
||||
void process_stmt_expr(const ast::stmt_expr::ptr& stmt, const block::ptr& blk);
|
||||
void process_stmt_call(const ast::stmt_call::ptr& stmt, const block::ptr& blk);
|
||||
void process_stmt_assign(const ast::stmt_assign::ptr& stmt, const block::ptr& blk);
|
||||
void process_stmt_endon(const ast::stmt_endon::ptr& stmt, const block::ptr& blk);
|
||||
void process_stmt_notify(const ast::stmt_notify::ptr& stmt, const block::ptr& blk);
|
||||
void process_stmt_wait(const ast::stmt_wait::ptr& stmt, const block::ptr& blk);
|
||||
void process_stmt_waittill(const ast::stmt_waittill::ptr& stmt, const block::ptr& blk);
|
||||
void process_stmt_waittillmatch(const ast::stmt_waittillmatch::ptr& stmt, const block::ptr& blk);
|
||||
void process_stmt_if(const ast::stmt_if::ptr& stmt, const block::ptr& blk);
|
||||
void process_stmt_ifelse(const ast::stmt_ifelse::ptr& stmt, const block::ptr& blk);
|
||||
void process_stmt_while(const ast::stmt_while::ptr& stmt, const block::ptr& blk);
|
||||
void process_stmt_dowhile(const ast::stmt_dowhile::ptr& stmt, const block::ptr& blk);
|
||||
void process_stmt_for(const ast::stmt_for::ptr& stmt, const block::ptr& blk);
|
||||
void process_stmt_foreach(const ast::stmt_foreach::ptr& stmt, const block::ptr& blk);
|
||||
void process_stmt_switch(const ast::stmt_switch::ptr& stmt, const block::ptr& blk);
|
||||
void process_stmt_cases(const ast::stmt_list::ptr& stmt, const block::ptr& blk);
|
||||
void process_stmt_break(const ast::stmt_break::ptr& stmt, const block::ptr& blk);
|
||||
void process_stmt_continue(const ast::stmt_continue::ptr& stmt, const block::ptr& blk);
|
||||
void process_stmt_return(const ast::stmt_return::ptr& stmt, const block::ptr& blk);
|
||||
void process_expr(ast::expr& expr, const block::ptr& blk);
|
||||
void process_expr_assign(ast::expr_assign::ptr& expr, const block::ptr& blk);
|
||||
void process_expr_increment(const ast::expr_increment::ptr& expr, const block::ptr& blk);
|
||||
void process_expr_decrement(const ast::expr_decrement::ptr& expr, const block::ptr& blk);
|
||||
void process_expr_ternary(const ast::expr_ternary::ptr& expr, const block::ptr& blk);
|
||||
void process_expr_binary(const ast::expr_binary::ptr& expr, const block::ptr& blk);
|
||||
void process_expr_and(const ast::expr_and::ptr& expr, const block::ptr& blk);
|
||||
void process_expr_or(const ast::expr_or::ptr& expr, const block::ptr& blk);
|
||||
void process_expr_complement(const ast::expr_complement::ptr& expr, const block::ptr& blk);
|
||||
void process_expr_not(const ast::expr_not::ptr& expr, const block::ptr& blk);
|
||||
void process_expr_call(const ast::expr_call::ptr& expr, const block::ptr& blk);
|
||||
void process_expr_method(const ast::expr_method::ptr& expr, const block::ptr& blk);
|
||||
void process_expr_call_pointer(const ast::expr_pointer::ptr& expr, const block::ptr& blk);
|
||||
void process_expr_call_function(const ast::expr_function::ptr& expr, const block::ptr& blk);
|
||||
void process_expr_method_pointer(const ast::expr_pointer::ptr& expr, ast::expr& obj, const block::ptr& blk);
|
||||
void process_expr_method_function(const ast::expr_function::ptr& expr, ast::expr& obj, const block::ptr& blk);
|
||||
void process_expr_arguments(const ast::expr_arguments::ptr& expr, const block::ptr& blk);
|
||||
void process_expr_add_array(const ast::expr_add_array::ptr& expr, const block::ptr& blk);
|
||||
void process_expr_size(const ast::expr_size::ptr& expr, const block::ptr& blk);
|
||||
void process_expr_tuple(const ast::expr_tuple::ptr& expr, const block::ptr& blk);
|
||||
void process_expr_array(const ast::expr_array::ptr& expr, const block::ptr& blk);
|
||||
void process_expr_field(const ast::expr_field::ptr& expr, const block::ptr& blk);
|
||||
void process_expr_vector(const ast::expr_vector::ptr& vec, const block::ptr& blk);
|
||||
void process_var_create(ast::expr& expr, const block::ptr& blk, bool fromstmt = false);
|
||||
void process_var_access(ast::expr& expr, const block::ptr& blk);
|
||||
void process_var_remove(const ast::asm_remove::ptr& expr, const block::ptr& blk);
|
||||
};
|
||||
|
||||
} // namespace xsk::gsc::iw5c
|
@ -1,573 +0,0 @@
|
||||
// Copyright 2022 xensik. All rights reserved.
|
||||
//
|
||||
// Use of this source code is governed by a GNU GPLv3 license
|
||||
// that can be found in the LICENSE file.
|
||||
|
||||
#include "stdafx.hpp"
|
||||
#include "iw5c.hpp"
|
||||
|
||||
namespace xsk::gsc::iw5c
|
||||
{
|
||||
|
||||
auto disassembler::output() -> std::vector<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("// IW5 GSC ASSEMBLY\n");
|
||||
output_->write_string("// Disassembled by https://github.com/xensik/gsc-tool\n");
|
||||
|
||||
for (const auto& func : functions_)
|
||||
{
|
||||
print_function(func);
|
||||
}
|
||||
|
||||
std::vector<std::uint8_t> output;
|
||||
|
||||
output.resize(output_->pos());
|
||||
std::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<function>());
|
||||
const auto& func = functions_.back();
|
||||
|
||||
func->index = static_cast<std::uint32_t>(script_->pos());
|
||||
func->size = stack_->read_endian<std::uint32_t>();
|
||||
func->id = stack_->read_endian<std::uint16_t>();
|
||||
func->name = func->id == 0 ? stack_->read_c_string() : resolver::token_name(static_cast<std::uint16_t>(func->id));
|
||||
|
||||
dissasemble_function(func);
|
||||
|
||||
func->labels = labels_;
|
||||
labels_.clear();
|
||||
}
|
||||
|
||||
resolve_local_functions();
|
||||
}
|
||||
|
||||
void disassembler::dissasemble_function(const function::ptr& func)
|
||||
{
|
||||
auto size = func->size;
|
||||
|
||||
while (size > 0)
|
||||
{
|
||||
func->instructions.push_back(std::make_unique<instruction>());
|
||||
|
||||
const auto& inst = func->instructions.back();
|
||||
inst->index = static_cast<std::uint32_t>(script_->pos());
|
||||
inst->opcode = script_->read_endian<std::uint8_t>();
|
||||
inst->size = opcode_size(inst->opcode);
|
||||
|
||||
dissasemble_instruction(inst);
|
||||
|
||||
size -= inst->size;
|
||||
}
|
||||
}
|
||||
|
||||
void disassembler::dissasemble_instruction(const instruction::ptr& inst)
|
||||
{
|
||||
switch (static_cast<opcode>(inst->opcode))
|
||||
{
|
||||
case opcode::OP_End:
|
||||
case opcode::OP_Return:
|
||||
case opcode::OP_GetUndefined:
|
||||
case opcode::OP_GetZero:
|
||||
case opcode::OP_waittillFrameEnd:
|
||||
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_EvalArray:
|
||||
case opcode::OP_EvalArrayRef:
|
||||
case opcode::OP_EvalLocalArrayRefCached0:
|
||||
case opcode::OP_ClearArray:
|
||||
case opcode::OP_EmptyArray:
|
||||
case opcode::OP_AddArray:
|
||||
case opcode::OP_PreScriptCall:
|
||||
case opcode::OP_ScriptFunctionCallPointer:
|
||||
case opcode::OP_ScriptMethodCallPointer:
|
||||
case opcode::OP_GetLevelObject:
|
||||
case opcode::OP_GetAnimObject:
|
||||
case opcode::OP_GetSelf:
|
||||
case opcode::OP_GetThisthread:
|
||||
case opcode::OP_GetLevel:
|
||||
case opcode::OP_GetGame:
|
||||
case opcode::OP_GetAnim:
|
||||
case opcode::OP_GetGameRef:
|
||||
case opcode::OP_inc:
|
||||
case opcode::OP_dec:
|
||||
case opcode::OP_bit_or:
|
||||
case opcode::OP_bit_ex_or:
|
||||
case opcode::OP_bit_and:
|
||||
case opcode::OP_equality:
|
||||
case opcode::OP_inequality:
|
||||
case opcode::OP_less:
|
||||
case opcode::OP_greater:
|
||||
case opcode::OP_less_equal:
|
||||
case opcode::OP_waittillmatch2:
|
||||
case opcode::OP_waittill:
|
||||
case opcode::OP_notify:
|
||||
case opcode::OP_endon:
|
||||
case opcode::OP_voidCodepos:
|
||||
case opcode::OP_vector:
|
||||
case opcode::OP_greater_equal:
|
||||
case opcode::OP_shift_left:
|
||||
case opcode::OP_shift_right:
|
||||
case opcode::OP_plus:
|
||||
case opcode::OP_minus:
|
||||
case opcode::OP_multiply:
|
||||
case opcode::OP_divide:
|
||||
case opcode::OP_mod:
|
||||
case opcode::OP_size:
|
||||
case opcode::OP_GetSelfObject:
|
||||
case opcode::OP_SafeSetVariableFieldCached0:
|
||||
case opcode::OP_clearparams:
|
||||
case opcode::OP_checkclearparams:
|
||||
case opcode::OP_EvalLocalVariableRefCached0:
|
||||
case opcode::OP_EvalNewLocalVariableRefCached0:
|
||||
case opcode::OP_SetVariableField:
|
||||
case opcode::OP_ClearVariableField:
|
||||
case opcode::OP_SetLocalVariableFieldCached0:
|
||||
case opcode::OP_ClearLocalVariableFieldCached0:
|
||||
case opcode::OP_wait:
|
||||
case opcode::OP_DecTop:
|
||||
case opcode::OP_CastFieldObject:
|
||||
case opcode::OP_CastBool:
|
||||
case opcode::OP_BoolNot:
|
||||
case opcode::OP_BoolComplement:
|
||||
break;
|
||||
case opcode::OP_GetByte:
|
||||
case opcode::OP_GetNegByte:
|
||||
inst->data.push_back(utils::string::va("%i", script_->read_endian<std::uint8_t>()));
|
||||
break;
|
||||
case opcode::OP_GetUnsignedShort:
|
||||
case opcode::OP_GetNegUnsignedShort:
|
||||
inst->data.push_back(utils::string::va("%i", script_->read_endian<std::uint16_t>()));
|
||||
break;
|
||||
case opcode::OP_GetInteger:
|
||||
inst->data.push_back(utils::string::va("%i", script_->read_endian<std::int32_t>()));
|
||||
break;
|
||||
case opcode::OP_GetFloat:
|
||||
inst->data.push_back(utils::string::float_string(script_->read_endian<float>()));
|
||||
break;
|
||||
case opcode::OP_GetVector:
|
||||
inst->size += script_->align(4);
|
||||
inst->data.push_back(utils::string::float_string(script_->read_endian<float>()));
|
||||
inst->data.push_back(utils::string::float_string(script_->read_endian<float>()));
|
||||
inst->data.push_back(utils::string::float_string(script_->read_endian<float>()));
|
||||
break;
|
||||
case opcode::OP_GetString:
|
||||
case opcode::OP_GetIString:
|
||||
script_->seek(2);
|
||||
inst->data.push_back(utils::string::to_literal(stack_->read_c_string()));
|
||||
break;
|
||||
case opcode::OP_GetAnimation:
|
||||
script_->seek(4);
|
||||
inst->data.push_back(utils::string::quote(stack_->read_c_string(), false));
|
||||
inst->data.push_back(utils::string::quote(stack_->read_c_string(), false));
|
||||
break;
|
||||
case opcode::OP_GetAnimTree:
|
||||
script_->seek(1);
|
||||
inst->data.push_back(utils::string::quote(stack_->read_c_string(), false));
|
||||
break;
|
||||
case opcode::OP_waittillmatch:
|
||||
inst->data.push_back(utils::string::va("%i", script_->read_endian<std::uint8_t>()));
|
||||
break;
|
||||
case opcode::OP_CreateLocalVariable:
|
||||
case opcode::OP_RemoveLocalVariables:
|
||||
case opcode::OP_EvalLocalVariableCached:
|
||||
case opcode::OP_EvalLocalArrayCached:
|
||||
case opcode::OP_EvalNewLocalArrayRefCached0:
|
||||
case opcode::OP_EvalLocalArrayRefCached:
|
||||
case opcode::OP_SafeCreateVariableFieldCached:
|
||||
case opcode::OP_SafeSetVariableFieldCached:
|
||||
case opcode::OP_SafeSetWaittillVariableFieldCached:
|
||||
case opcode::OP_EvalLocalVariableRefCached:
|
||||
case opcode::OP_SetNewLocalVariableFieldCached0:
|
||||
case opcode::OP_SetLocalVariableFieldCached:
|
||||
case opcode::OP_ClearLocalVariableFieldCached:
|
||||
case opcode::OP_EvalLocalVariableObjectCached:
|
||||
inst->data.push_back(utils::string::va("%i", script_->read_endian<std::uint8_t>()));
|
||||
break;
|
||||
case opcode::OP_EvalLevelFieldVariable:
|
||||
case opcode::OP_EvalAnimFieldVariable:
|
||||
case opcode::OP_EvalSelfFieldVariable:
|
||||
case opcode::OP_EvalFieldVariable:
|
||||
case opcode::OP_EvalLevelFieldVariableRef:
|
||||
case opcode::OP_EvalAnimFieldVariableRef:
|
||||
case opcode::OP_EvalSelfFieldVariableRef:
|
||||
case opcode::OP_EvalFieldVariableRef:
|
||||
case opcode::OP_ClearFieldVariable:
|
||||
case opcode::OP_SetLevelFieldVariableField:
|
||||
case opcode::OP_SetAnimFieldVariableField:
|
||||
case opcode::OP_SetSelfFieldVariableField:
|
||||
disassemble_field_variable(inst);
|
||||
break;
|
||||
case opcode::OP_ScriptThreadCallPointer:
|
||||
case opcode::OP_ScriptChildThreadCallPointer:
|
||||
case opcode::OP_ScriptMethodThreadCallPointer:
|
||||
case opcode::OP_ScriptMethodChildThreadCallPointer:
|
||||
case opcode::OP_CallBuiltinPointer:
|
||||
case opcode::OP_CallBuiltinMethodPointer:
|
||||
inst->data.push_back(utils::string::va("%i", script_->read_endian<std::uint8_t>()));
|
||||
break;
|
||||
case opcode::OP_GetLocalFunction:
|
||||
case opcode::OP_ScriptLocalFunctionCall2:
|
||||
case opcode::OP_ScriptLocalFunctionCall:
|
||||
case opcode::OP_ScriptLocalMethodCall:
|
||||
disassemble_local_call(inst, false);
|
||||
break;
|
||||
case opcode::OP_ScriptLocalThreadCall:
|
||||
case opcode::OP_ScriptLocalChildThreadCall:
|
||||
case opcode::OP_ScriptLocalMethodThreadCall:
|
||||
case opcode::OP_ScriptLocalMethodChildThreadCall:
|
||||
disassemble_local_call(inst, true);
|
||||
break;
|
||||
case opcode::OP_GetFarFunction:
|
||||
case opcode::OP_ScriptFarFunctionCall2:
|
||||
case opcode::OP_ScriptFarFunctionCall:
|
||||
case opcode::OP_ScriptFarMethodCall:
|
||||
disassemble_far_call(inst, false);
|
||||
break;
|
||||
case opcode::OP_ScriptFarThreadCall:
|
||||
case opcode::OP_ScriptFarChildThreadCall:
|
||||
case opcode::OP_ScriptFarMethodThreadCall:
|
||||
case opcode::OP_ScriptFarMethodChildThreadCall:
|
||||
disassemble_far_call(inst, true);
|
||||
break;
|
||||
case opcode::OP_CallBuiltin:
|
||||
disassemble_builtin_call(inst, false, true);
|
||||
break;
|
||||
case opcode::OP_CallBuiltinMethod:
|
||||
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:
|
||||
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:
|
||||
disassemble_builtin_call(inst, true, false);
|
||||
break;
|
||||
case opcode::OP_jump:
|
||||
disassemble_jump(inst, false, false);
|
||||
break;
|
||||
case opcode::OP_jumpback:
|
||||
disassemble_jump(inst, false, true);
|
||||
break;
|
||||
case opcode::OP_JumpOnFalse:
|
||||
case opcode::OP_JumpOnTrue:
|
||||
case opcode::OP_JumpOnFalseExpr:
|
||||
case opcode::OP_JumpOnTrueExpr:
|
||||
disassemble_jump(inst, true, false);
|
||||
break;
|
||||
case opcode::OP_switch:
|
||||
disassemble_switch(inst);
|
||||
break;
|
||||
case opcode::OP_endswitch:
|
||||
disassemble_end_switch(inst);
|
||||
break;
|
||||
default:
|
||||
throw disasm_error(utils::string::va("unhandled opcode 0x%X at index '%04X'!", inst->opcode, inst->index));
|
||||
}
|
||||
}
|
||||
|
||||
void disassembler::disassemble_builtin_call(const instruction::ptr& inst, bool method, bool args)
|
||||
{
|
||||
if (args)
|
||||
{
|
||||
inst->data.push_back(utils::string::va("%i", script_->read_endian<std::uint8_t>()));
|
||||
}
|
||||
|
||||
const auto id = script_->read_endian<std::uint16_t>();
|
||||
const auto name = method ? resolver::method_name(id) : resolver::function_name(id);
|
||||
inst->data.emplace(inst->data.begin(), name);
|
||||
}
|
||||
|
||||
void disassembler::disassemble_local_call(const instruction::ptr& inst, bool thread)
|
||||
{
|
||||
const auto offset = 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_endian<std::uint8_t>()));
|
||||
}
|
||||
}
|
||||
|
||||
void disassembler::disassemble_far_call(const instruction::ptr& inst, bool thread)
|
||||
{
|
||||
script_->seek(3);
|
||||
|
||||
if (thread)
|
||||
{
|
||||
inst->data.push_back(utils::string::va("%i", script_->read_endian<std::uint8_t>()));
|
||||
}
|
||||
|
||||
const auto file_id = stack_->read_endian<std::uint16_t>();
|
||||
const auto file_name = file_id == 0 ? stack_->read_c_string() : resolver::token_name(file_id);
|
||||
const auto func_id = stack_->read_endian<std::uint16_t>();
|
||||
const auto func_name = func_id == 0 ? stack_->read_c_string() : resolver::token_name(func_id);
|
||||
|
||||
inst->data.emplace(inst->data.begin(), func_name);
|
||||
inst->data.emplace(inst->data.begin(), file_name);
|
||||
}
|
||||
|
||||
void disassembler::disassemble_switch(const instruction::ptr& inst)
|
||||
{
|
||||
const auto addr = inst->index + 4 + script_->read_endian<std::int32_t>();
|
||||
const auto label = utils::string::va("loc_%X", addr);
|
||||
|
||||
inst->data.push_back(label);
|
||||
labels_.insert({ addr, label });
|
||||
}
|
||||
|
||||
void disassembler::disassemble_end_switch(const instruction::ptr& inst)
|
||||
{
|
||||
const auto count = script_->read_endian<std::uint16_t>();
|
||||
inst->data.push_back(utils::string::va("%i", count));
|
||||
|
||||
std::uint32_t index = inst->index + 3;
|
||||
|
||||
if (count)
|
||||
{
|
||||
for (auto i = count; i > 0; i--)
|
||||
{
|
||||
const auto value = script_->read_endian<std::uint32_t>();
|
||||
|
||||
if (value < 0x40000)
|
||||
{
|
||||
const auto data = stack_->read_c_string();
|
||||
|
||||
if (data.data()[0] != 0x01)
|
||||
{
|
||||
inst->data.push_back("case");
|
||||
inst->data.push_back(utils::string::quote(data, false));
|
||||
}
|
||||
else
|
||||
inst->data.push_back("default");
|
||||
}
|
||||
else
|
||||
{
|
||||
inst->data.push_back("case");
|
||||
inst->data.push_back(utils::string::va("%i", (value - 0x800000) & 0xFFFFFF));
|
||||
}
|
||||
|
||||
index += 4;
|
||||
|
||||
const auto addr = disassemble_offset() + index;
|
||||
const auto label = utils::string::va("loc_%X", addr);
|
||||
|
||||
inst->data.push_back(label);
|
||||
labels_.insert({ addr, label });
|
||||
|
||||
index += 3;
|
||||
inst->size += 7;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void disassembler::disassemble_field_variable(const instruction::ptr& inst)
|
||||
{
|
||||
const auto id = script_->read_endian<std::uint16_t>();
|
||||
std::string name;
|
||||
|
||||
if (id > max_string_id)
|
||||
{
|
||||
auto temp = stack_->read_endian<std::uint16_t>();
|
||||
name = temp == 0 ? stack_->read_c_string() : std::to_string(temp);
|
||||
}
|
||||
else
|
||||
{
|
||||
name = resolver::token_name(id);
|
||||
}
|
||||
|
||||
inst->data.push_back(name);
|
||||
}
|
||||
|
||||
void disassembler::disassemble_jump(const instruction::ptr& inst, bool expr, bool back)
|
||||
{
|
||||
std::int32_t addr;
|
||||
|
||||
if (expr)
|
||||
{
|
||||
addr = inst->index + 3 + script_->read_endian<std::int16_t>();
|
||||
}
|
||||
else if (back)
|
||||
{
|
||||
addr = inst->index + 3 - script_->read_endian<std::uint16_t>();
|
||||
}
|
||||
else
|
||||
{
|
||||
addr = inst->index + 5 + script_->read_endian<std::int32_t>();
|
||||
}
|
||||
|
||||
const auto label = utils::string::va("loc_%X", addr);
|
||||
|
||||
inst->data.push_back(label);
|
||||
labels_.insert({ addr, label });
|
||||
}
|
||||
|
||||
auto disassembler::disassemble_offset() -> std::int32_t
|
||||
{
|
||||
std::array<std::uint8_t, 4> bytes = {};
|
||||
|
||||
for (auto i = 0; i < 3; i++)
|
||||
{
|
||||
bytes[2 - i] = script_->read_endian<std::uint8_t>();
|
||||
}
|
||||
|
||||
auto offset = *reinterpret_cast<std::int32_t*>(bytes.data());
|
||||
|
||||
offset = (offset << 8) >> 10;
|
||||
|
||||
return offset;
|
||||
}
|
||||
|
||||
void disassembler::resolve_local_functions()
|
||||
{
|
||||
for (const auto& func : functions_)
|
||||
{
|
||||
for (const auto& inst : func->instructions)
|
||||
{
|
||||
switch (static_cast<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[0] = 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 (const auto& func : functions_)
|
||||
{
|
||||
if (func->index == idx)
|
||||
{
|
||||
return func->name;
|
||||
}
|
||||
}
|
||||
|
||||
throw disasm_error(utils::string::va("couldn't resolve function name at index '0x%04X'!", idx));
|
||||
}
|
||||
|
||||
throw disasm_error(utils::string::va("\"%s\" is not valid function address!", index.data()));
|
||||
}
|
||||
|
||||
void disassembler::print_function(const function::ptr& func)
|
||||
{
|
||||
output_->write_string("\n");
|
||||
output_->write_string(utils::string::va("sub_%s\n", func->name.data()));
|
||||
|
||||
for (const auto& inst : func->instructions)
|
||||
{
|
||||
const auto itr = func->labels.find(inst->index);
|
||||
|
||||
if (itr != func->labels.end())
|
||||
{
|
||||
output_->write_string(utils::string::va("\t%s\n", itr->second.data()));
|
||||
}
|
||||
|
||||
print_instruction(inst);
|
||||
}
|
||||
|
||||
output_->write_string(utils::string::va("end_%s\n", func->name.data()));
|
||||
}
|
||||
|
||||
void disassembler::print_instruction(const instruction::ptr& inst)
|
||||
{
|
||||
output_->write_string(utils::string::va("\t\t%s", resolver::opcode_name(inst->opcode).data()));
|
||||
|
||||
switch (static_cast<opcode>(inst->opcode))
|
||||
{
|
||||
case opcode::OP_GetLocalFunction:
|
||||
case opcode::OP_ScriptLocalFunctionCall:
|
||||
case opcode::OP_ScriptLocalFunctionCall2:
|
||||
case opcode::OP_ScriptLocalMethodCall:
|
||||
output_->write_string(utils::string::va(" sub_%s\n", inst->data[0].data()));
|
||||
break;
|
||||
case opcode::OP_ScriptLocalThreadCall:
|
||||
case opcode::OP_ScriptLocalChildThreadCall:
|
||||
case opcode::OP_ScriptLocalMethodThreadCall:
|
||||
case opcode::OP_ScriptLocalMethodChildThreadCall:
|
||||
output_->write_string(utils::string::va(" sub_%s %s\n", inst->data[0].data(), inst->data[1].data()));
|
||||
break;
|
||||
case opcode::OP_endswitch:
|
||||
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;
|
||||
}
|
||||
|
||||
output_->write_string("\n");
|
||||
}
|
||||
}
|
||||
break;
|
||||
default:
|
||||
for (const auto& data : inst->data)
|
||||
{
|
||||
output_->write_string(utils::string::va(" %s", data.data()));
|
||||
}
|
||||
|
||||
output_->write_string("\n");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace xsk::gsc::iw5c
|
@ -1,42 +0,0 @@
|
||||
// Copyright 2022 xensik. All rights reserved.
|
||||
//
|
||||
// Use of this source code is governed by a GNU GPLv3 license
|
||||
// that can be found in the LICENSE file.
|
||||
|
||||
#pragma once
|
||||
|
||||
namespace xsk::gsc::iw5c
|
||||
{
|
||||
|
||||
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<function::ptr> functions_;
|
||||
std::unordered_map<std::uint32_t, std::string> labels_;
|
||||
|
||||
public:
|
||||
auto output() -> std::vector<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 function::ptr& func);
|
||||
void dissasemble_instruction(const instruction::ptr& inst);
|
||||
void disassemble_builtin_call(const instruction::ptr& inst, bool method, bool args);
|
||||
void disassemble_local_call(const instruction::ptr& inst, bool thread);
|
||||
void disassemble_far_call(const instruction::ptr& inst, bool thread);
|
||||
void disassemble_switch(const instruction::ptr& inst);
|
||||
void disassemble_end_switch(const instruction::ptr& inst);
|
||||
void disassemble_field_variable(const instruction::ptr& inst);
|
||||
void disassemble_jump(const instruction::ptr& inst, bool expr, bool back);
|
||||
auto disassemble_offset() -> std::int32_t;
|
||||
void resolve_local_functions();
|
||||
auto resolve_function(const std::string& index) -> std::string;
|
||||
void print_function(const function::ptr& func);
|
||||
void print_instruction(const instruction::ptr& inst);
|
||||
};
|
||||
|
||||
} // namespace xsk::gsc::iw5c
|
@ -1,179 +0,0 @@
|
||||
// Copyright 2022 xensik. All rights reserved.
|
||||
//
|
||||
// Use of this source code is governed by a GNU GPLv3 license
|
||||
// that can be found in the LICENSE file.
|
||||
|
||||
#include "stdafx.hpp"
|
||||
#include "iw5c.hpp"
|
||||
|
||||
namespace xsk::gsc::iw5c
|
||||
{
|
||||
|
||||
auto opcode_size(std::uint8_t id) -> std::uint32_t
|
||||
{
|
||||
switch (static_cast<opcode>(id))
|
||||
{
|
||||
case opcode::OP_End:
|
||||
case opcode::OP_Return:
|
||||
case opcode::OP_GetUndefined:
|
||||
case opcode::OP_GetZero:
|
||||
case opcode::OP_waittillFrameEnd:
|
||||
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_EvalArray:
|
||||
case opcode::OP_EvalArrayRef:
|
||||
case opcode::OP_EvalLocalArrayRefCached0:
|
||||
case opcode::OP_ClearArray:
|
||||
case opcode::OP_EmptyArray:
|
||||
case opcode::OP_AddArray:
|
||||
case opcode::OP_PreScriptCall:
|
||||
case opcode::OP_ScriptFunctionCallPointer:
|
||||
case opcode::OP_ScriptMethodCallPointer:
|
||||
case opcode::OP_GetLevelObject:
|
||||
case opcode::OP_GetAnimObject:
|
||||
case opcode::OP_GetSelf:
|
||||
case opcode::OP_GetThisthread:
|
||||
case opcode::OP_GetLevel:
|
||||
case opcode::OP_GetGame:
|
||||
case opcode::OP_GetAnim:
|
||||
case opcode::OP_GetGameRef:
|
||||
case opcode::OP_inc:
|
||||
case opcode::OP_dec:
|
||||
case opcode::OP_bit_or:
|
||||
case opcode::OP_bit_ex_or:
|
||||
case opcode::OP_bit_and:
|
||||
case opcode::OP_equality:
|
||||
case opcode::OP_inequality:
|
||||
case opcode::OP_less:
|
||||
case opcode::OP_greater:
|
||||
case opcode::OP_less_equal:
|
||||
case opcode::OP_waittillmatch2:
|
||||
case opcode::OP_waittill:
|
||||
case opcode::OP_notify:
|
||||
case opcode::OP_endon:
|
||||
case opcode::OP_voidCodepos:
|
||||
case opcode::OP_vector:
|
||||
case opcode::OP_greater_equal:
|
||||
case opcode::OP_shift_left:
|
||||
case opcode::OP_shift_right:
|
||||
case opcode::OP_plus:
|
||||
case opcode::OP_minus:
|
||||
case opcode::OP_multiply:
|
||||
case opcode::OP_divide:
|
||||
case opcode::OP_mod:
|
||||
case opcode::OP_size:
|
||||
case opcode::OP_GetSelfObject:
|
||||
case opcode::OP_SafeSetVariableFieldCached0:
|
||||
case opcode::OP_clearparams:
|
||||
case opcode::OP_checkclearparams:
|
||||
case opcode::OP_EvalLocalVariableRefCached0:
|
||||
case opcode::OP_EvalNewLocalVariableRefCached0:
|
||||
case opcode::OP_SetVariableField:
|
||||
case opcode::OP_ClearVariableField:
|
||||
case opcode::OP_SetLocalVariableFieldCached0:
|
||||
case opcode::OP_ClearLocalVariableFieldCached0:
|
||||
case opcode::OP_wait:
|
||||
case opcode::OP_DecTop:
|
||||
case opcode::OP_CastFieldObject:
|
||||
case opcode::OP_CastBool:
|
||||
case opcode::OP_BoolNot:
|
||||
case opcode::OP_BoolComplement:
|
||||
return 1;
|
||||
case opcode::OP_GetByte:
|
||||
case opcode::OP_GetNegByte:
|
||||
case opcode::OP_CreateLocalVariable:
|
||||
case opcode::OP_RemoveLocalVariables:
|
||||
case opcode::OP_EvalLocalVariableCached:
|
||||
case opcode::OP_EvalLocalArrayCached:
|
||||
case opcode::OP_EvalNewLocalArrayRefCached0:
|
||||
case opcode::OP_EvalLocalArrayRefCached:
|
||||
case opcode::OP_ScriptThreadCallPointer:
|
||||
case opcode::OP_ScriptMethodThreadCallPointer:
|
||||
case opcode::OP_ScriptMethodChildThreadCallPointer:
|
||||
case opcode::OP_CallBuiltinPointer:
|
||||
case opcode::OP_CallBuiltinMethodPointer:
|
||||
case opcode::OP_waittillmatch:
|
||||
case opcode::OP_SafeCreateVariableFieldCached:
|
||||
case opcode::OP_SafeSetVariableFieldCached:
|
||||
case opcode::OP_SafeSetWaittillVariableFieldCached:
|
||||
case opcode::OP_GetAnimTree:
|
||||
case opcode::OP_EvalLocalVariableRefCached:
|
||||
case opcode::OP_SetNewLocalVariableFieldCached0:
|
||||
case opcode::OP_SetLocalVariableFieldCached:
|
||||
case opcode::OP_ClearLocalVariableFieldCached:
|
||||
case opcode::OP_EvalLocalVariableObjectCached:
|
||||
return 2;
|
||||
case opcode::OP_GetUnsignedShort:
|
||||
case opcode::OP_GetNegUnsignedShort:
|
||||
case opcode::OP_GetBuiltinFunction:
|
||||
case opcode::OP_GetBuiltinMethod:
|
||||
case opcode::OP_GetString:
|
||||
case opcode::OP_GetIString:
|
||||
case opcode::OP_JumpOnFalseExpr:
|
||||
case opcode::OP_JumpOnTrueExpr:
|
||||
case opcode::OP_jumpback:
|
||||
case opcode::OP_endswitch:
|
||||
case opcode::OP_JumpOnFalse:
|
||||
case opcode::OP_JumpOnTrue:
|
||||
case opcode::OP_EvalLevelFieldVariable:
|
||||
case opcode::OP_EvalAnimFieldVariable:
|
||||
case opcode::OP_EvalSelfFieldVariable:
|
||||
case opcode::OP_EvalFieldVariable:
|
||||
case opcode::OP_EvalLevelFieldVariableRef:
|
||||
case opcode::OP_EvalAnimFieldVariableRef:
|
||||
case opcode::OP_EvalSelfFieldVariableRef:
|
||||
case opcode::OP_EvalFieldVariableRef:
|
||||
case opcode::OP_ClearFieldVariable:
|
||||
case opcode::OP_SetLevelFieldVariableField:
|
||||
case opcode::OP_SetAnimFieldVariableField:
|
||||
case opcode::OP_SetSelfFieldVariableField:
|
||||
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_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_ScriptLocalFunctionCall2:
|
||||
case opcode::OP_ScriptLocalFunctionCall:
|
||||
case opcode::OP_ScriptLocalMethodCall:
|
||||
case opcode::OP_GetLocalFunction:
|
||||
case opcode::OP_CallBuiltin:
|
||||
case opcode::OP_CallBuiltinMethod:
|
||||
case opcode::OP_ScriptFarFunctionCall2:
|
||||
case opcode::OP_ScriptFarFunctionCall:
|
||||
case opcode::OP_ScriptFarMethodCall:
|
||||
case opcode::OP_GetFarFunction:
|
||||
return 4;
|
||||
case opcode::OP_GetInteger:
|
||||
case opcode::OP_GetFloat:
|
||||
case opcode::OP_ScriptLocalThreadCall:
|
||||
case opcode::OP_ScriptLocalChildThreadCall:
|
||||
case opcode::OP_ScriptLocalMethodThreadCall:
|
||||
case opcode::OP_ScriptLocalMethodChildThreadCall:
|
||||
case opcode::OP_ScriptFarThreadCall:
|
||||
case opcode::OP_ScriptFarChildThreadCall:
|
||||
case opcode::OP_ScriptFarMethodThreadCall:
|
||||
case opcode::OP_ScriptFarMethodChildThreadCall:
|
||||
case opcode::OP_GetAnimation:
|
||||
case opcode::OP_switch:
|
||||
case opcode::OP_jump:
|
||||
return 5;
|
||||
case opcode::OP_GetVector:
|
||||
return 13;
|
||||
default:
|
||||
throw std::runtime_error("couldn't resolve instruction size for " + std::to_string(id));
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace xsk::gsc::iw5c
|
@ -1,182 +0,0 @@
|
||||
// Copyright 2022 xensik. All rights reserved.
|
||||
//
|
||||
// Use of this source code is governed by a GNU GPLv3 license
|
||||
// that can be found in the LICENSE file.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "utils/xsk/utils.hpp"
|
||||
|
||||
#include "assembler.hpp"
|
||||
#include "disassembler.hpp"
|
||||
#include "compiler.hpp"
|
||||
#include "decompiler.hpp"
|
||||
#include "resolver.hpp"
|
||||
#include "context.hpp"
|
||||
|
||||
namespace xsk::gsc::iw5c
|
||||
{
|
||||
|
||||
constexpr std::uint16_t max_string_id = 0x8250;
|
||||
|
||||
enum class opcode : std::uint8_t
|
||||
{
|
||||
OP_End = 0,
|
||||
OP_Return = 1,
|
||||
OP_GetUndefined = 2,
|
||||
OP_GetZero = 3,
|
||||
OP_GetByte = 4,
|
||||
OP_GetAnimTree = 5,
|
||||
OP_GetNegByte = 6,
|
||||
OP_GetUnsignedShort = 7,
|
||||
OP_GetNegUnsignedShort = 8,
|
||||
OP_GetInteger = 9,
|
||||
OP_GetBuiltinFunction = 0xA,
|
||||
OP_GetBuiltinMethod = 0xB,
|
||||
OP_GetFloat = 0xC,
|
||||
OP_GetString = 0xD,
|
||||
OP_GetIString = 0xE,
|
||||
OP_GetVector = 0xF,
|
||||
OP_GetLevelObject = 0x10,
|
||||
OP_GetAnimObject = 0x11,
|
||||
OP_GetSelf = 0x12,
|
||||
OP_GetThisthread = 0x13,
|
||||
OP_GetLevel = 0x14,
|
||||
OP_GetGame = 0x15,
|
||||
OP_GetAnim = 0x16,
|
||||
OP_GetAnimation = 0x17,
|
||||
OP_GetGameRef = 0x18,
|
||||
OP_GetLocalFunction = 0x19,
|
||||
OP_GetFarFunction = 0x1A,
|
||||
OP_CreateLocalVariable = 0x1B,
|
||||
OP_RemoveLocalVariables = 0x1C,
|
||||
OP_EvalLocalVariableCached0 = 0x1D,
|
||||
OP_EvalLocalVariableCached1 = 0x1E,
|
||||
OP_EvalLocalVariableCached2 = 0x1F,
|
||||
OP_EvalLocalVariableCached3 = 0x20,
|
||||
OP_EvalLocalVariableCached4 = 0x21,
|
||||
OP_EvalLocalVariableCached5 = 0x22,
|
||||
OP_EvalLocalVariableCached = 0x23,
|
||||
OP_EvalLocalArrayCached = 0x24,
|
||||
OP_EvalArray = 0x25,
|
||||
OP_EvalLocalArrayRefCached0 = 0x26,
|
||||
OP_EvalNewLocalArrayRefCached0 = 0x27,
|
||||
OP_EvalLocalArrayRefCached = 0x28,
|
||||
OP_EvalArrayRef = 0x29,
|
||||
OP_ClearArray = 0x2A,
|
||||
OP_EmptyArray = 0x2B,
|
||||
OP_AddArray = 0x2C,
|
||||
OP_GetSelfObject = 0x2D,
|
||||
OP_EvalLevelFieldVariable = 0x2E,
|
||||
OP_EvalAnimFieldVariable = 0x2F,
|
||||
OP_EvalSelfFieldVariable = 0x30,
|
||||
OP_EvalFieldVariable = 0x31,
|
||||
OP_EvalLevelFieldVariableRef = 0x32,
|
||||
OP_EvalAnimFieldVariableRef = 0x33,
|
||||
OP_EvalSelfFieldVariableRef = 0x34,
|
||||
OP_EvalFieldVariableRef = 0x35,
|
||||
OP_ClearFieldVariable = 0x36,
|
||||
OP_SafeCreateVariableFieldCached = 0x37,
|
||||
OP_SafeSetVariableFieldCached0 = 0x38,
|
||||
OP_SafeSetVariableFieldCached = 0x39,
|
||||
OP_SafeSetWaittillVariableFieldCached = 0x3A,
|
||||
OP_clearparams = 0x3B,
|
||||
OP_checkclearparams = 0x3C,
|
||||
OP_EvalLocalVariableRefCached0 = 0x3D,
|
||||
OP_EvalNewLocalVariableRefCached0 = 0x3E,
|
||||
OP_EvalLocalVariableRefCached = 0x3F,
|
||||
OP_SetLevelFieldVariableField = 0x40,
|
||||
OP_SetVariableField = 0x41,
|
||||
OP_ClearVariableField = 0x42,
|
||||
OP_SetAnimFieldVariableField = 0x43,
|
||||
OP_SetSelfFieldVariableField = 0x44,
|
||||
OP_SetLocalVariableFieldCached0 = 0x45,
|
||||
OP_SetNewLocalVariableFieldCached0 = 0x46,
|
||||
OP_SetLocalVariableFieldCached = 0x47,
|
||||
OP_ClearLocalVariableFieldCached = 0x48,
|
||||
OP_ClearLocalVariableFieldCached0 = 0x49,
|
||||
OP_CallBuiltin0 = 0x4A,
|
||||
OP_CallBuiltin1 = 0x4B,
|
||||
OP_CallBuiltin2 = 0x4C,
|
||||
OP_CallBuiltin3 = 0x4D,
|
||||
OP_CallBuiltin4 = 0x4E,
|
||||
OP_CallBuiltin5 = 0x4F,
|
||||
OP_CallBuiltin = 0x50,
|
||||
OP_CallBuiltinMethod0 = 0x51,
|
||||
OP_CallBuiltinMethod1 = 0x52,
|
||||
OP_CallBuiltinMethod2 = 0x53,
|
||||
OP_CallBuiltinMethod3 = 0x54,
|
||||
OP_CallBuiltinMethod4 = 0x55,
|
||||
OP_CallBuiltinMethod5 = 0x56,
|
||||
OP_CallBuiltinMethod = 0x57,
|
||||
OP_wait = 0x58,
|
||||
OP_waittillFrameEnd = 0x59,
|
||||
OP_PreScriptCall = 0x5A,
|
||||
OP_ScriptLocalFunctionCall2 = 0x5B,
|
||||
OP_ScriptLocalFunctionCall = 0x5C,
|
||||
OP_ScriptLocalMethodCall = 0x5D,
|
||||
OP_ScriptLocalThreadCall = 0x5E,
|
||||
OP_ScriptLocalChildThreadCall = 0x5F,
|
||||
OP_ScriptLocalMethodThreadCall = 0x60,
|
||||
OP_ScriptLocalMethodChildThreadCall = 0x61,
|
||||
OP_ScriptFarFunctionCall2 = 0x62,
|
||||
OP_ScriptFarFunctionCall = 0x63,
|
||||
OP_ScriptFarMethodCall = 0x64,
|
||||
OP_ScriptFarThreadCall = 0x65,
|
||||
OP_ScriptFarChildThreadCall = 0x66,
|
||||
OP_ScriptFarMethodThreadCall = 0x67,
|
||||
OP_ScriptFarMethodChildThreadCall = 0x68,
|
||||
OP_ScriptFunctionCallPointer = 0x69,
|
||||
OP_ScriptMethodCallPointer = 0x6A,
|
||||
OP_ScriptThreadCallPointer = 0x6B,
|
||||
OP_ScriptChildThreadCallPointer = 0x6C,
|
||||
OP_ScriptMethodThreadCallPointer = 0x6D,
|
||||
OP_ScriptMethodChildThreadCallPointer = 0x6E,
|
||||
OP_CallBuiltinPointer = 0x6F,
|
||||
OP_CallBuiltinMethodPointer = 0x70,
|
||||
OP_DecTop = 0x71,
|
||||
OP_CastFieldObject = 0x72,
|
||||
OP_EvalLocalVariableObjectCached = 0x73,
|
||||
OP_CastBool = 0x74,
|
||||
OP_BoolNot = 0x75,
|
||||
OP_BoolComplement = 0x76,
|
||||
OP_JumpOnFalse = 0x77,
|
||||
OP_JumpOnTrue = 0x78,
|
||||
OP_JumpOnFalseExpr = 0x79,
|
||||
OP_JumpOnTrueExpr = 0x7A,
|
||||
OP_jump = 0x7B,
|
||||
OP_jumpback = 0x7C,
|
||||
OP_inc = 0x7D,
|
||||
OP_dec = 0x7E,
|
||||
OP_bit_or = 0x7F,
|
||||
OP_bit_ex_or = 0x80,
|
||||
OP_bit_and = 0x81,
|
||||
OP_equality = 0x82,
|
||||
OP_inequality = 0x83,
|
||||
OP_less = 0x84,
|
||||
OP_greater = 0x85,
|
||||
OP_less_equal = 0x86,
|
||||
OP_greater_equal = 0x87,
|
||||
OP_shift_left = 0x88,
|
||||
OP_shift_right = 0x89,
|
||||
OP_plus = 0x8A,
|
||||
OP_minus = 0x8B,
|
||||
OP_multiply = 0x8C,
|
||||
OP_divide = 0x8D,
|
||||
OP_mod = 0x8E,
|
||||
OP_size = 0x8F,
|
||||
OP_waittillmatch = 0x90,
|
||||
OP_waittillmatch2 = 0x91,
|
||||
OP_waittill = 0x92,
|
||||
OP_notify = 0x93,
|
||||
OP_endon = 0x94,
|
||||
OP_voidCodepos = 0x95,
|
||||
OP_switch = 0x96,
|
||||
OP_endswitch = 0x97,
|
||||
OP_vector = 0x98,
|
||||
OP_Count = 0x99,
|
||||
};
|
||||
|
||||
auto opcode_size(std::uint8_t id) -> std::uint32_t;
|
||||
|
||||
} // namespace xsk::gsc::iw5c
|
@ -1,848 +0,0 @@
|
||||
// Copyright 2022 xensik. All rights reserved.
|
||||
//
|
||||
// Use of this source code is governed by a GNU GPLv3 license
|
||||
// that can be found in the LICENSE file.
|
||||
|
||||
#include "stdafx.hpp"
|
||||
#include "iw5c.hpp"
|
||||
#include "parser.hpp"
|
||||
#include "lexer.hpp"
|
||||
|
||||
xsk::gsc::iw5c::parser::symbol_type IW5Clex(xsk::gsc::iw5c::lexer& lexer)
|
||||
{
|
||||
return lexer.lex();
|
||||
}
|
||||
|
||||
namespace xsk::gsc::iw5c
|
||||
{
|
||||
|
||||
const std::unordered_map<std::string_view, parser::token::token_kind_type> keyword_map
|
||||
{{
|
||||
{ "#define", parser::token::SH_DEFINE },
|
||||
{ "#undef", parser::token::SH_UNDEF },
|
||||
{ "#ifdef", parser::token::SH_IFDEF },
|
||||
{ "#ifndef", parser::token::SH_IFNDEF },
|
||||
{ "#if", parser::token::SH_IF },
|
||||
{ "#elif", parser::token::SH_ELIF },
|
||||
{ "#else", parser::token::SH_ELSE },
|
||||
{ "#endif", parser::token::SH_ENDIF },
|
||||
{ "#inline", parser::token::INLINE },
|
||||
{ "#include", parser::token::INCLUDE },
|
||||
{ "#using_animtree", parser::token::USINGTREE },
|
||||
{ "#animtree", parser::token::ANIMTREE },
|
||||
{ "endon", parser::token::ENDON },
|
||||
{ "notify", parser::token::NOTIFY },
|
||||
{ "wait", parser::token::WAIT },
|
||||
{ "waittill", parser::token::WAITTILL },
|
||||
{ "waittillmatch", parser::token::WAITTILLMATCH },
|
||||
{ "waittillframeend", parser::token::WAITTILLFRAMEEND },
|
||||
{ "if", parser::token::IF },
|
||||
{ "else", parser::token::ELSE },
|
||||
{ "do", parser::token::DO },
|
||||
{ "while", parser::token::WHILE },
|
||||
{ "for", parser::token::FOR },
|
||||
{ "foreach", parser::token::FOREACH },
|
||||
{ "in", parser::token::IN },
|
||||
{ "switch", parser::token::SWITCH },
|
||||
{ "case", parser::token::CASE },
|
||||
{ "default", parser::token::DEFAULT },
|
||||
{ "break", parser::token::BREAK },
|
||||
{ "continue", parser::token::CONTINUE },
|
||||
{ "return", parser::token::RETURN },
|
||||
{ "breakpoint", parser::token::BREAKPOINT },
|
||||
{ "prof_begin", parser::token::PROFBEGIN },
|
||||
{ "prof_end", parser::token::PROFEND },
|
||||
{ "thread", parser::token::THREAD },
|
||||
{ "childthread", parser::token::CHILDTHREAD },
|
||||
{ "thisthread", parser::token::THISTHREAD },
|
||||
{ "call", parser::token::CALL },
|
||||
{ "true", parser::token::TRUE },
|
||||
{ "false", parser::token::FALSE },
|
||||
{ "undefined", parser::token::UNDEFINED },
|
||||
{ "size", parser::token::SIZE },
|
||||
{ "game", parser::token::GAME },
|
||||
{ "self", parser::token::SELF },
|
||||
{ "anim", parser::token::ANIM },
|
||||
{ "level", parser::token::LEVEL },
|
||||
}};
|
||||
|
||||
buffer::buffer() : length(0)
|
||||
{
|
||||
data = static_cast<char*>(std::malloc(max_buf_size));
|
||||
}
|
||||
|
||||
buffer::~buffer()
|
||||
{
|
||||
if (data) std::free(data);
|
||||
}
|
||||
|
||||
bool buffer::push(char c)
|
||||
{
|
||||
if (length >= max_buf_size)
|
||||
return false;
|
||||
|
||||
data[length++] = c;
|
||||
return true;
|
||||
}
|
||||
|
||||
reader::reader() : buffer_pos(0), bytes_remaining(0), last_byte(0), current_byte(0), state(reader::end)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
void reader::init(const char* data, size_t size)
|
||||
{
|
||||
if (data && size)
|
||||
{
|
||||
state = reader::ok;
|
||||
buffer_pos = data;
|
||||
bytes_remaining = static_cast<std::uint32_t>(size);
|
||||
last_byte = 0;
|
||||
current_byte = *data;
|
||||
}
|
||||
else
|
||||
{
|
||||
state = reader::end;
|
||||
buffer_pos = 0;
|
||||
bytes_remaining = 0;
|
||||
last_byte = 0;
|
||||
current_byte = 0;
|
||||
}
|
||||
}
|
||||
|
||||
void reader::advance()
|
||||
{
|
||||
++buffer_pos;
|
||||
|
||||
if (bytes_remaining-- == 1)
|
||||
{
|
||||
state = reader::end;
|
||||
bytes_remaining = 0;
|
||||
last_byte = current_byte;
|
||||
current_byte = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
last_byte = current_byte;
|
||||
current_byte = *buffer_pos;
|
||||
}
|
||||
}
|
||||
|
||||
lexer::lexer(build mode, const std::string& name, const char* data, size_t size) : loc_(location(&name)),
|
||||
locs_(std::stack<location>()), readers_(std::stack<reader>()), header_top_(0), mode_(mode), indev_(false), clean_(true)
|
||||
{
|
||||
reader_.init(data, size);
|
||||
}
|
||||
|
||||
void lexer::push_header(const std::string& file)
|
||||
{
|
||||
try
|
||||
{
|
||||
if (header_top_++ >= 10)
|
||||
throw comp_error(loc_, "maximum gsh depth exceeded '10'");
|
||||
|
||||
auto data = resolver::file_data(file + ".gsh");
|
||||
|
||||
readers_.push(reader_);
|
||||
locs_.push(loc_);
|
||||
loc_.initialize(std::get<0>(data));
|
||||
reader_.init(std::get<1>(data), std::get<2>(data));
|
||||
clean_ = true;
|
||||
}
|
||||
catch (const std::exception& e)
|
||||
{
|
||||
throw error("parsing header file '" + file + "': " + e.what());
|
||||
}
|
||||
}
|
||||
|
||||
void lexer::pop_header()
|
||||
{
|
||||
header_top_--;
|
||||
loc_ = locs_.top();
|
||||
locs_.pop();
|
||||
reader_ = readers_.top();
|
||||
readers_.pop();
|
||||
}
|
||||
|
||||
void lexer::ban_header(const location& loc)
|
||||
{
|
||||
if (header_top_ > 0)
|
||||
{
|
||||
throw comp_error(loc, "not allowed inside a gsh file");
|
||||
}
|
||||
}
|
||||
|
||||
auto lexer::lex() -> parser::symbol_type
|
||||
{
|
||||
buffer_.length = 0;
|
||||
state_ = state::start;
|
||||
|
||||
while (true)
|
||||
{
|
||||
const auto& state = reader_.state;
|
||||
auto& last = reader_.last_byte;
|
||||
auto& curr = reader_.current_byte;
|
||||
auto path = false;
|
||||
loc_.step();
|
||||
|
||||
if (state == reader::end)
|
||||
{
|
||||
if (indev_)
|
||||
throw comp_error(loc_, "unmatched devblock start ('/#')");
|
||||
|
||||
if (header_top_ > 0)
|
||||
pop_header();
|
||||
else
|
||||
return parser::make_IW5CEOF(loc_);
|
||||
}
|
||||
|
||||
if (clean_ && last != 0 && last != ' ' && last != '\t' && last != '\n')
|
||||
clean_ = false;
|
||||
|
||||
advance();
|
||||
|
||||
switch (last)
|
||||
{
|
||||
case ' ':
|
||||
case '\t':
|
||||
case '\r':
|
||||
loc_.step();
|
||||
continue;
|
||||
case '\n':
|
||||
loc_.lines();
|
||||
loc_.step();
|
||||
clean_ = true;
|
||||
continue;
|
||||
case '\\':
|
||||
throw comp_error(loc_, "invalid token ('\\')");
|
||||
case '/':
|
||||
if (curr != '=' && curr != '#' && curr != '@' && curr != '*' && curr != '/')
|
||||
return parser::make_DIV(loc_);
|
||||
|
||||
advance();
|
||||
|
||||
if (last == '=')
|
||||
return parser::make_ASSIGN_DIV(loc_);
|
||||
|
||||
if (last == '#')
|
||||
{
|
||||
if (indev_)
|
||||
throw comp_error(loc_, "cannot recurse devblock ('/#')");
|
||||
|
||||
if (mode_ == build::dev)
|
||||
{
|
||||
indev_ = true;
|
||||
return parser::make_DEVBEGIN(loc_);
|
||||
}
|
||||
else
|
||||
{
|
||||
while (true)
|
||||
{
|
||||
if (state == reader::end)
|
||||
throw comp_error(loc_, "unmatched devblock start ('/#')");
|
||||
|
||||
if (curr == '\n')
|
||||
{
|
||||
loc_.lines();
|
||||
loc_.step();
|
||||
}
|
||||
else if (last == '#' && curr == '/')
|
||||
{
|
||||
advance();
|
||||
break;
|
||||
}
|
||||
|
||||
advance();
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (last == '@')
|
||||
{
|
||||
while (true)
|
||||
{
|
||||
if (state == reader::end)
|
||||
throw comp_error(loc_, "unmatched script doc comment start ('/@')");
|
||||
|
||||
if (curr == '\n')
|
||||
{
|
||||
loc_.lines();
|
||||
loc_.step();
|
||||
}
|
||||
else if (last == '@' && curr == '/')
|
||||
{
|
||||
advance();
|
||||
break;
|
||||
}
|
||||
|
||||
advance();
|
||||
}
|
||||
}
|
||||
else if (last == '*')
|
||||
{
|
||||
while (true)
|
||||
{
|
||||
if (state == reader::end)
|
||||
throw comp_error(loc_, "unmatched multiline comment start ('/*')");
|
||||
|
||||
if (curr == '\n')
|
||||
{
|
||||
loc_.lines();
|
||||
loc_.step();
|
||||
}
|
||||
else if (last == '*' && curr == '/')
|
||||
{
|
||||
advance();
|
||||
break;
|
||||
}
|
||||
|
||||
advance();
|
||||
}
|
||||
}
|
||||
else if (last == '/')
|
||||
{
|
||||
while (true)
|
||||
{
|
||||
if (state == reader::end)
|
||||
break;
|
||||
|
||||
if (curr == '\n')
|
||||
break;
|
||||
|
||||
advance();
|
||||
}
|
||||
}
|
||||
continue;
|
||||
case '#':
|
||||
if (curr == '/')
|
||||
{
|
||||
if (!indev_)
|
||||
throw comp_error(loc_, "unmatched devblock end ('#/')");
|
||||
|
||||
advance();
|
||||
indev_ = false;
|
||||
return parser::make_DEVEND(loc_);
|
||||
}
|
||||
|
||||
buffer_.push(last);
|
||||
advance();
|
||||
|
||||
while (state == reader::ok)
|
||||
{
|
||||
if (last != ' ' || last != '\t')
|
||||
break;
|
||||
|
||||
advance();
|
||||
}
|
||||
|
||||
if (state == reader::end || !((last > 64 && last < 91) || (last > 96 && last < 123)))
|
||||
throw comp_error(loc_, "invalid preprocessor directive ('#')");
|
||||
|
||||
state_ = state::preprocessor;
|
||||
goto lex_name;
|
||||
case '*':
|
||||
if (curr != '=' && curr != '/')
|
||||
return parser::make_MUL(loc_);
|
||||
|
||||
advance();
|
||||
|
||||
if (last == '=')
|
||||
return parser::make_ASSIGN_MUL(loc_);
|
||||
|
||||
throw comp_error(loc_, "unmatched multiline comment end ('*/')");
|
||||
case '"':
|
||||
state_ = state::string;
|
||||
goto lex_string;
|
||||
case '.':
|
||||
if (curr < '0' || curr > '9')
|
||||
return parser::make_DOT(loc_);
|
||||
goto lex_number;
|
||||
case '(':
|
||||
return parser::make_LPAREN(loc_);
|
||||
case ')':
|
||||
return parser::make_RPAREN(loc_);
|
||||
case '{':
|
||||
return parser::make_LBRACE(loc_);
|
||||
case '}':
|
||||
return parser::make_RBRACE(loc_);
|
||||
case '[':
|
||||
return parser::make_LBRACKET(loc_);
|
||||
case ']':
|
||||
return parser::make_RBRACKET(loc_);
|
||||
case ',':
|
||||
return parser::make_COMMA(loc_);
|
||||
case ';':
|
||||
return parser::make_SEMICOLON(loc_);
|
||||
case ':':
|
||||
if (curr != ':')
|
||||
return parser::make_COLON(loc_);
|
||||
|
||||
advance();
|
||||
return parser::make_DOUBLECOLON(loc_);
|
||||
case '?':
|
||||
return parser::make_QMARK(loc_);
|
||||
case '=':
|
||||
if (curr != '=')
|
||||
return parser::make_ASSIGN(loc_);
|
||||
|
||||
advance();
|
||||
return parser::make_EQUALITY(loc_);
|
||||
case '+':
|
||||
if (curr != '+' && curr != '=')
|
||||
return parser::make_ADD(loc_);
|
||||
|
||||
advance();
|
||||
|
||||
if (last == '+')
|
||||
return parser::make_INCREMENT(loc_);
|
||||
|
||||
return parser::make_ASSIGN_ADD(loc_);
|
||||
case '-':
|
||||
if (curr != '-' && curr != '=')
|
||||
return parser::make_SUB(loc_);
|
||||
|
||||
advance();
|
||||
|
||||
if (last == '-')
|
||||
return parser::make_DECREMENT(loc_);
|
||||
|
||||
return parser::make_ASSIGN_SUB(loc_);
|
||||
case '%':
|
||||
if (curr != '=')
|
||||
return parser::make_MOD(loc_);
|
||||
|
||||
advance();
|
||||
|
||||
return parser::make_ASSIGN_MOD(loc_);
|
||||
case '|':
|
||||
if (curr != '|' && curr != '=')
|
||||
return parser::make_BITWISE_OR(loc_);
|
||||
|
||||
advance();
|
||||
|
||||
if (last == '|')
|
||||
return parser::make_OR(loc_);
|
||||
|
||||
return parser::make_ASSIGN_BW_OR(loc_);
|
||||
case '&':
|
||||
if (curr != '&' && curr != '=' && curr != '"')
|
||||
return parser::make_BITWISE_AND(loc_);
|
||||
|
||||
advance();
|
||||
|
||||
if (last == '&')
|
||||
return parser::make_AND(loc_);
|
||||
|
||||
if (last == '=')
|
||||
return parser::make_ASSIGN_BW_AND(loc_);
|
||||
|
||||
state_ = state::localize;
|
||||
goto lex_string;
|
||||
case '^':
|
||||
if (curr != '=')
|
||||
return parser::make_BITWISE_EXOR(loc_);
|
||||
|
||||
advance();
|
||||
return parser::make_ASSIGN_BW_EXOR(loc_);
|
||||
case '!':
|
||||
if (curr != '=')
|
||||
return parser::make_NOT(loc_);
|
||||
|
||||
advance();
|
||||
return parser::make_INEQUALITY(loc_);
|
||||
case '~':
|
||||
return parser::make_COMPLEMENT(loc_);
|
||||
case '<':
|
||||
if (curr != '<' && curr != '=')
|
||||
return parser::make_LESS(loc_);
|
||||
|
||||
advance();
|
||||
if (last == '=')
|
||||
return parser::make_LESS_EQUAL(loc_);
|
||||
|
||||
if (curr != '=')
|
||||
return parser::make_LSHIFT(loc_);
|
||||
|
||||
advance();
|
||||
return parser::make_ASSIGN_LSHIFT(loc_);
|
||||
case '>':
|
||||
if (curr != '>' && curr != '=')
|
||||
return parser::make_GREATER(loc_);
|
||||
|
||||
advance();
|
||||
|
||||
if (last == '=')
|
||||
return parser::make_GREATER_EQUAL(loc_);
|
||||
|
||||
if (curr != '=')
|
||||
return parser::make_RSHIFT(loc_);
|
||||
|
||||
advance();
|
||||
return parser::make_ASSIGN_RSHIFT(loc_);
|
||||
default:
|
||||
if (last >= '0' && last <= '9')
|
||||
goto lex_number;
|
||||
else if (last == '_' || (last >= 'A' && last <= 'Z') || (last >= 'a' && last <= 'z'))
|
||||
goto lex_name;
|
||||
|
||||
throw comp_error(loc_, utils::string::va("bad token: \'%c\'", last));
|
||||
}
|
||||
|
||||
lex_string:
|
||||
while (true)
|
||||
{
|
||||
if (state == reader::end)
|
||||
throw comp_error(loc_, "unmatched string start ('\"')");
|
||||
|
||||
if (curr == '"')
|
||||
{
|
||||
advance();
|
||||
break;
|
||||
}
|
||||
|
||||
if (curr == '\n')
|
||||
throw comp_error(loc_, "unterminated string literal");
|
||||
|
||||
if (curr == '\\')
|
||||
{
|
||||
advance();
|
||||
|
||||
if (state == reader::end)
|
||||
throw comp_error(loc_, "invalid token ('\')");
|
||||
|
||||
char c = curr;
|
||||
switch (curr)
|
||||
{
|
||||
case 't': c = '\t'; break;
|
||||
case 'r': c = '\r'; break;
|
||||
case 'n': c = '\n'; break;
|
||||
case '"': c = '\"'; break;
|
||||
case '\\': c = '\\'; break;
|
||||
default: break;
|
||||
}
|
||||
|
||||
if (!buffer_.push(c))
|
||||
throw comp_error(loc_, "max string size exceeded");
|
||||
}
|
||||
else if (!buffer_.push(curr))
|
||||
throw comp_error(loc_, "max string size exceeded");
|
||||
|
||||
advance();
|
||||
}
|
||||
|
||||
if (state_ == state::localize)
|
||||
return parser::make_ISTRING(std::string(buffer_.data, buffer_.length), loc_);
|
||||
|
||||
return parser::make_STRING(std::string(buffer_.data, buffer_.length), loc_);
|
||||
|
||||
lex_name:
|
||||
buffer_.push(last);
|
||||
|
||||
while (true)
|
||||
{
|
||||
if (state == reader::end)
|
||||
break;
|
||||
|
||||
if (!(curr == '\\' || curr == '_' || (curr > 64 && curr < 91) || (curr > 96 && curr < 123) || (curr > 47 && curr < 58)))
|
||||
break;
|
||||
|
||||
if (curr == '\\')
|
||||
{
|
||||
if (last == '\\')
|
||||
throw comp_error(loc_, "invalid path '\\\\'");
|
||||
|
||||
path = true;
|
||||
if (!buffer_.push('/'))
|
||||
throw comp_error(loc_, "max string size exceeded");
|
||||
}
|
||||
else if (!buffer_.push(curr))
|
||||
throw comp_error(loc_, "max string size exceeded");
|
||||
|
||||
advance();
|
||||
}
|
||||
|
||||
if (state_ == state::preprocessor)
|
||||
{
|
||||
auto token = parser::token::IW5CUNDEF;
|
||||
|
||||
if (buffer_.length < 16)
|
||||
{
|
||||
const auto itr = keyword_map.find(std::string_view(buffer_.data, buffer_.length));
|
||||
|
||||
if (itr != keyword_map.end())
|
||||
{
|
||||
if (itr->second > parser::token::SH_ENDIF)
|
||||
return parser::symbol_type(itr->second, loc_);
|
||||
|
||||
token = itr->second;
|
||||
}
|
||||
}
|
||||
|
||||
preprocessor_run(token);
|
||||
|
||||
state_ = state::start;
|
||||
continue;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (buffer_.length < 17)
|
||||
{
|
||||
const auto itr = keyword_map.find(std::string_view(buffer_.data, buffer_.length));
|
||||
|
||||
if (itr != keyword_map.end())
|
||||
return parser::symbol_type(itr->second, loc_);
|
||||
}
|
||||
|
||||
if (path)
|
||||
{
|
||||
if (buffer_.data[buffer_.length - 1] == '/')
|
||||
throw comp_error(loc_, "invalid path end '\\'");
|
||||
|
||||
return parser::make_PATH(resolver::make_token(std::string_view(buffer_.data, buffer_.length)), loc_);
|
||||
}
|
||||
|
||||
return parser::make_IDENTIFIER(resolver::make_token(std::string_view(buffer_.data, buffer_.length)), loc_);
|
||||
}
|
||||
|
||||
lex_number:
|
||||
if (last == '.' || last != '0' || (last == '0' && (curr != 'o' && curr != 'b' && curr != 'x')))
|
||||
{
|
||||
buffer_.push(last);
|
||||
|
||||
auto dot = last == '.' ? 1 : 0;
|
||||
auto flt = 0;
|
||||
|
||||
while (true)
|
||||
{
|
||||
if (state == reader::end)
|
||||
break;
|
||||
|
||||
if (curr == '\'' && (last == '\'' || last == 'f' || last == '.'))
|
||||
throw comp_error(loc_, "invalid number literal");
|
||||
|
||||
if ((curr == '.' || curr == 'f') && last == '\'')
|
||||
throw comp_error(loc_, "invalid number literal");
|
||||
|
||||
if (curr == '\'')
|
||||
{
|
||||
advance();
|
||||
continue;
|
||||
}
|
||||
|
||||
if (curr == 'f')
|
||||
flt++;
|
||||
else if (curr == '.')
|
||||
dot++;
|
||||
else if (!(curr > 47 && curr < 58))
|
||||
break;
|
||||
|
||||
if (!buffer_.push(curr))
|
||||
throw comp_error(loc_, "number literal size exceeded");
|
||||
|
||||
advance();
|
||||
}
|
||||
|
||||
if (last == '\'')
|
||||
throw comp_error(loc_, "invalid number literal");
|
||||
|
||||
if (dot > 1 || flt > 1 || (flt && buffer_.data[buffer_.length - 1] != 'f'))
|
||||
throw comp_error(loc_, "invalid number literal");
|
||||
|
||||
if (dot || flt)
|
||||
return parser::make_FLOAT(std::string(buffer_.data, buffer_.length), loc_);
|
||||
|
||||
return parser::make_INTEGER(std::string(buffer_.data, buffer_.length), loc_);
|
||||
}
|
||||
else if (curr == 'o')
|
||||
{
|
||||
advance();
|
||||
|
||||
while (true)
|
||||
{
|
||||
if (state == reader::end)
|
||||
break;
|
||||
|
||||
if ((curr == '\'' && (last == '\'' || last == 'o')) || (curr == 'o' && last == '\''))
|
||||
throw comp_error(loc_, "invalid octal literal");
|
||||
|
||||
if (curr == '\'')
|
||||
{
|
||||
advance();
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!(curr > 47 && curr < 56))
|
||||
break;
|
||||
|
||||
if (!buffer_.push(curr))
|
||||
throw error("gsc lexer: out of memory!");
|
||||
|
||||
advance();
|
||||
}
|
||||
|
||||
if (last == '\'' || buffer_.length <= 0)
|
||||
throw comp_error(loc_, "invalid octal literal");
|
||||
|
||||
return parser::make_INTEGER(utils::string::oct_to_dec(buffer_.data), loc_);
|
||||
}
|
||||
else if (curr == 'b')
|
||||
{
|
||||
buffer_.push(last);
|
||||
buffer_.push(curr);
|
||||
advance();
|
||||
|
||||
while (true)
|
||||
{
|
||||
if (state == reader::end)
|
||||
break;
|
||||
|
||||
if ((curr == '\'' && (last == '\'' || last == 'b')) || (curr == 'b' && last == '\''))
|
||||
throw comp_error(loc_, "invalid binary literal");
|
||||
|
||||
if (curr == '\'')
|
||||
{
|
||||
advance();
|
||||
continue;
|
||||
}
|
||||
|
||||
if (curr != '0' && curr != '1')
|
||||
break;
|
||||
|
||||
if (!buffer_.push(curr))
|
||||
throw comp_error(loc_, "number literal size exceeded");
|
||||
|
||||
advance();
|
||||
}
|
||||
|
||||
if (last == '\'' || buffer_.length < 3)
|
||||
throw comp_error(loc_, "invalid binary literal");
|
||||
|
||||
return parser::make_INTEGER(utils::string::bin_to_dec(buffer_.data), loc_);
|
||||
}
|
||||
else if (curr == 'x')
|
||||
{
|
||||
buffer_.push(last);
|
||||
buffer_.push(curr);
|
||||
advance();
|
||||
|
||||
while (true)
|
||||
{
|
||||
if (state == reader::end)
|
||||
break;
|
||||
|
||||
if ((curr == '\'' && (last == '\'' || last == 'x')) || (curr == 'x' && last == '\''))
|
||||
throw comp_error(loc_, "invalid hexadecimal literal");
|
||||
|
||||
if (curr == '\'')
|
||||
{
|
||||
advance();
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!((curr > 47 && curr < 58) || (curr > 64 && curr < 71) || (curr > 96 && curr < 103)))
|
||||
break;
|
||||
|
||||
if (!buffer_.push(curr))
|
||||
throw error("gsc lexer: out of memory!");
|
||||
|
||||
advance();
|
||||
}
|
||||
|
||||
if (last == '\'' || buffer_.length < 3)
|
||||
throw comp_error(loc_, "invalid hexadecimal literal");
|
||||
|
||||
return parser::make_INTEGER(utils::string::hex_to_dec(buffer_.data), loc_);
|
||||
}
|
||||
|
||||
throw error("UNEXPECTED LEXER INTERNAL ERROR!");
|
||||
}
|
||||
}
|
||||
|
||||
void lexer::advance()
|
||||
{
|
||||
reader_.advance();
|
||||
loc_.end.column++;
|
||||
|
||||
if (reader_.current_byte == '\\') [[unlikely]]
|
||||
preprocessor_wrap();
|
||||
}
|
||||
|
||||
void lexer::preprocessor_wrap()
|
||||
{
|
||||
while (reader_.current_byte == '\\')
|
||||
{
|
||||
if (reader_.bytes_remaining == 1)
|
||||
throw comp_error(loc_, "invalid token ('\\')");
|
||||
|
||||
if (reader_.buffer_pos[1] != '\r' && reader_.buffer_pos[1] != '\n')
|
||||
break;
|
||||
|
||||
if (reader_.buffer_pos[1] == '\r')
|
||||
{
|
||||
if (reader_.bytes_remaining <= 3 || reader_.buffer_pos[2] != '\n')
|
||||
throw comp_error(loc_, "invalid token ('\\')");
|
||||
|
||||
reader_.buffer_pos += 3;
|
||||
reader_.bytes_remaining -= 3;
|
||||
}
|
||||
|
||||
if ((reader_.buffer_pos[1] == '\n'))
|
||||
{
|
||||
if (reader_.bytes_remaining == 2)
|
||||
throw comp_error(loc_, "invalid token ('\\')");
|
||||
|
||||
reader_.buffer_pos += 2;
|
||||
reader_.bytes_remaining -= 2;
|
||||
}
|
||||
|
||||
if (reader_.bytes_remaining == 0)
|
||||
{
|
||||
reader_.state = reader::end;
|
||||
reader_.current_byte = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
reader_.current_byte = *reader_.buffer_pos;
|
||||
}
|
||||
|
||||
loc_.lines();
|
||||
loc_.step();
|
||||
}
|
||||
}
|
||||
|
||||
void lexer::preprocessor_run(parser::token::token_kind_type token)
|
||||
{
|
||||
if (!clean_)
|
||||
throw comp_error(loc_, "invalid token ('#')");
|
||||
|
||||
switch (token)
|
||||
{
|
||||
case parser::token::SH_DEFINE:
|
||||
throw comp_error(loc_, "unimplemented preprocessor directive");
|
||||
break;
|
||||
case parser::token::SH_UNDEF:
|
||||
throw comp_error(loc_, "unimplemented preprocessor directive");
|
||||
break;
|
||||
case parser::token::SH_IFDEF:
|
||||
throw comp_error(loc_, "unimplemented preprocessor directive");
|
||||
break;
|
||||
case parser::token::SH_IFNDEF:
|
||||
throw comp_error(loc_, "unimplemented preprocessor directive");
|
||||
break;
|
||||
case parser::token::SH_IF:
|
||||
throw comp_error(loc_, "unimplemented preprocessor directive");
|
||||
break;
|
||||
case parser::token::SH_ELIF:
|
||||
throw comp_error(loc_, "unimplemented preprocessor directive");
|
||||
break;
|
||||
case parser::token::SH_ELSE:
|
||||
throw comp_error(loc_, "unimplemented preprocessor directive");
|
||||
break;
|
||||
case parser::token::SH_ENDIF:
|
||||
throw comp_error(loc_, "unimplemented preprocessor directive");
|
||||
break;
|
||||
default:
|
||||
throw comp_error(loc_, "unknown preprocessor directive");
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace xsk::gsc::iw5c
|
@ -1,78 +0,0 @@
|
||||
// Copyright 2022 xensik. All rights reserved.
|
||||
//
|
||||
// Use of this source code is governed by a GNU GPLv3 license
|
||||
// that can be found in the LICENSE file.
|
||||
|
||||
#pragma once
|
||||
|
||||
namespace xsk::gsc::iw5c
|
||||
{
|
||||
|
||||
constexpr size_t max_buf_size = 0x2000;
|
||||
|
||||
struct buffer
|
||||
{
|
||||
char* data;
|
||||
size_t length;
|
||||
|
||||
buffer();
|
||||
~buffer();
|
||||
bool push(char c);
|
||||
};
|
||||
|
||||
struct reader
|
||||
{
|
||||
enum state_type : std::uint8_t { end, ok };
|
||||
|
||||
const char* buffer_pos;
|
||||
std::uint32_t bytes_remaining;
|
||||
char last_byte;
|
||||
char current_byte;
|
||||
state_type state;
|
||||
|
||||
reader();
|
||||
|
||||
reader(const reader& obj)
|
||||
{
|
||||
std::memcpy(this, &obj, sizeof(reader));
|
||||
}
|
||||
|
||||
reader& operator=(const reader& obj)
|
||||
{
|
||||
std::memcpy(this, &obj, sizeof(reader));
|
||||
return *this;
|
||||
}
|
||||
|
||||
void init(const char* data, size_t size);
|
||||
void advance();
|
||||
};
|
||||
|
||||
class lexer
|
||||
{
|
||||
enum class state : std::uint8_t { start, string, localize, preprocessor };
|
||||
|
||||
reader reader_;
|
||||
buffer buffer_;
|
||||
location loc_;
|
||||
std::stack<location> locs_;
|
||||
std::stack<reader> readers_;
|
||||
std::uint32_t header_top_;
|
||||
state state_;
|
||||
build mode_;
|
||||
bool indev_;
|
||||
bool clean_;
|
||||
|
||||
public:
|
||||
lexer(build mode, const std::string& name, const char* data, size_t size);
|
||||
auto lex() -> parser::symbol_type;
|
||||
void push_header(const std::string& file);
|
||||
void pop_header();
|
||||
void ban_header(const location& loc);
|
||||
|
||||
private:
|
||||
void advance();
|
||||
void preprocessor_wrap();
|
||||
void preprocessor_run(parser::token::token_kind_type token);
|
||||
};
|
||||
|
||||
} // namespace xsk::gsc::iw5c
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@ -1,40 +0,0 @@
|
||||
// Copyright 2022 xensik. All rights reserved.
|
||||
//
|
||||
// Use of this source code is governed by a GNU GPLv3 license
|
||||
// that can be found in the LICENSE file.
|
||||
|
||||
#pragma once
|
||||
|
||||
namespace xsk::gsc::iw5c
|
||||
{
|
||||
|
||||
class resolver
|
||||
{
|
||||
public:
|
||||
static void init(read_cb_type callback);
|
||||
static void cleanup();
|
||||
|
||||
static auto opcode_id(const std::string& name) -> std::uint8_t;
|
||||
static auto opcode_name(std::uint8_t id) -> std::string;
|
||||
|
||||
static auto 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 token_id(const std::string& name) -> std::uint16_t;
|
||||
static auto token_name(std::uint16_t id) -> std::string;
|
||||
|
||||
static auto find_function(const std::string& name) -> bool;
|
||||
static auto find_method(const std::string& name) -> bool;
|
||||
|
||||
static void add_function(const std::string& name, std::uint16_t id);
|
||||
static void add_method(const std::string& name, std::uint16_t id);
|
||||
|
||||
static auto make_token(std::string_view str) -> std::string;
|
||||
static auto file_data(const std::string& name) -> std::tuple<const std::string*, const char*, size_t>;
|
||||
static auto fs_to_game_path(const std::filesystem::path& file) -> std::filesystem::path;
|
||||
};
|
||||
|
||||
} // namespace xsk::gsc::iw5c
|
@ -1,26 +0,0 @@
|
||||
// Copyright 2022 xensik. All rights reserved.
|
||||
//
|
||||
// Use of this source code is governed by a GNU GPLv3 license
|
||||
// that can be found in the LICENSE file.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <cstdio>
|
||||
#include <algorithm>
|
||||
#include <array>
|
||||
#include <filesystem>
|
||||
#include <fstream>
|
||||
#include <functional>
|
||||
#include <iostream>
|
||||
#include <map>
|
||||
#include <memory>
|
||||
#include <regex>
|
||||
#include <set>
|
||||
#include <sstream>
|
||||
#include <stack>
|
||||
#include <stdexcept>
|
||||
#include <string>
|
||||
#include <unordered_map>
|
||||
#include <vector>
|
||||
|
||||
using namespace std::literals;
|
@ -1,554 +0,0 @@
|
||||
// Copyright 2022 xensik. All rights reserved.
|
||||
//
|
||||
// Use of this source code is governed by a GNU GPLv3 license
|
||||
// that can be found in the LICENSE file.
|
||||
|
||||
#include "stdafx.hpp"
|
||||
#include "iw6c.hpp"
|
||||
|
||||
namespace xsk::gsc::iw6c
|
||||
{
|
||||
|
||||
auto assembler::output_script() -> std::vector<std::uint8_t>
|
||||
{
|
||||
std::vector<std::uint8_t> script;
|
||||
|
||||
if (script_ == nullptr) return script;
|
||||
|
||||
script.resize(script_->pos());
|
||||
std::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());
|
||||
std::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<function::ptr> functions;
|
||||
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<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 opdata = utils::string::parse_code(line);
|
||||
|
||||
if (switchnum)
|
||||
{
|
||||
if (opdata[0] == "case" || opdata[0] == "default")
|
||||
{
|
||||
for (auto& entry : opdata)
|
||||
{
|
||||
func->instructions.back()->data.push_back(entry);
|
||||
}
|
||||
switchnum--;
|
||||
continue;
|
||||
}
|
||||
|
||||
throw asm_error("invalid instruction inside endswitch \""s + line + "\"!");
|
||||
}
|
||||
else
|
||||
{
|
||||
auto inst = std::make_unique<instruction>();
|
||||
inst->index = index;
|
||||
inst->opcode = resolver::opcode_id(opdata[0]);
|
||||
inst->size = opcode_size(inst->opcode);
|
||||
opdata.erase(opdata.begin());
|
||||
inst->data = std::move(opdata);
|
||||
|
||||
switch (static_cast<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[0] = inst->data[0].substr(4);
|
||||
break;
|
||||
case opcode::OP_endswitch:
|
||||
switchnum = static_cast<std::uint16_t>(std::stoi(inst->data[0]));
|
||||
inst->size += 7 * switchnum;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
index += inst->size;
|
||||
func->instructions.push_back(std::move(inst));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
assemble(file, functions);
|
||||
}
|
||||
|
||||
void assembler::assemble(const std::string& file, std::vector<function::ptr>& funcs)
|
||||
{
|
||||
script_ = std::make_unique<utils::byte_buffer>(0x100000);
|
||||
stack_ = std::make_unique<utils::byte_buffer>(0x100000);
|
||||
filename_ = file;
|
||||
functions_ = std::move(funcs);
|
||||
|
||||
script_->write_endian<std::uint8_t>(static_cast<std::uint8_t>(opcode::OP_End));
|
||||
|
||||
for (const auto& func : functions_)
|
||||
{
|
||||
assemble_function(func);
|
||||
}
|
||||
}
|
||||
|
||||
void assembler::assemble_function(const function::ptr& func)
|
||||
{
|
||||
labels_ = func->labels;
|
||||
|
||||
func->id = resolver::token_id(func->name);
|
||||
|
||||
stack_->write_endian<std::uint32_t>(func->size);
|
||||
stack_->write_endian<std::uint16_t>(static_cast<std::uint16_t>(func->id));
|
||||
|
||||
if (func->id == 0)
|
||||
{
|
||||
stack_->write_c_string(func->name);
|
||||
}
|
||||
|
||||
for (const auto& inst : func->instructions)
|
||||
{
|
||||
assemble_instruction(inst);
|
||||
}
|
||||
}
|
||||
|
||||
void assembler::assemble_instruction(const instruction::ptr& inst)
|
||||
{
|
||||
script_->write_endian<std::uint8_t>(static_cast<std::uint8_t>(inst->opcode));
|
||||
|
||||
switch (static_cast<opcode>(inst->opcode))
|
||||
{
|
||||
case opcode::OP_Return:
|
||||
case opcode::OP_BoolNot:
|
||||
case opcode::OP_CastBool:
|
||||
case opcode::OP_inequality:
|
||||
case opcode::OP_GetThisthread:
|
||||
case opcode::OP_ClearLocalVariableFieldCached0:
|
||||
case opcode::OP_checkclearparams:
|
||||
case opcode::OP_CastFieldObject:
|
||||
case opcode::OP_End:
|
||||
case opcode::OP_size:
|
||||
case opcode::OP_EmptyArray:
|
||||
case opcode::OP_bit_and:
|
||||
case opcode::OP_less_equal:
|
||||
case opcode::OP_voidCodepos:
|
||||
// case opcode::OP_ClearVariableField:
|
||||
case opcode::OP_divide:
|
||||
case opcode::OP_GetSelf:
|
||||
case opcode::OP_SetLocalVariableFieldCached0:
|
||||
case opcode::OP_plus:
|
||||
case opcode::OP_BoolComplement:
|
||||
case opcode::OP_ScriptMethodCallPointer:
|
||||
case opcode::OP_inc:
|
||||
case opcode::OP_clearparams:
|
||||
case opcode::OP_EvalLocalVariableRefCached0:
|
||||
case opcode::OP_ScriptFunctionCallPointer:
|
||||
case opcode::OP_endon:
|
||||
case opcode::OP_greater_equal:
|
||||
case opcode::OP_GetSelfObject:
|
||||
case opcode::OP_SetVariableField:
|
||||
case opcode::OP_EvalLocalArrayRefCached0:
|
||||
case opcode::OP_less:
|
||||
case opcode::OP_GetGameRef:
|
||||
case opcode::OP_waittillFrameEnd:
|
||||
case opcode::OP_SafeSetVariableFieldCached0:
|
||||
case opcode::OP_GetLevel:
|
||||
case opcode::OP_notify:
|
||||
case opcode::OP_DecTop:
|
||||
case opcode::OP_shift_left:
|
||||
case opcode::OP_greater:
|
||||
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_GetZero:
|
||||
case opcode::OP_wait:
|
||||
case opcode::OP_minus:
|
||||
// case opcode::OP_EvalNewLocalVariableRefCached0:
|
||||
case opcode::OP_multiply:
|
||||
case opcode::OP_mod:
|
||||
case opcode::OP_GetGame:
|
||||
case opcode::OP_waittill:
|
||||
case opcode::OP_dec:
|
||||
case opcode::OP_PreScriptCall:
|
||||
case opcode::OP_GetAnim:
|
||||
case opcode::OP_GetUndefined:
|
||||
case opcode::OP_GetAnimObject:
|
||||
case opcode::OP_GetLevelObject:
|
||||
case opcode::OP_bit_ex_or:
|
||||
case opcode::OP_equality:
|
||||
case opcode::OP_ClearArray:
|
||||
case opcode::OP_EvalArrayRef:
|
||||
case opcode::OP_EvalArray:
|
||||
case opcode::OP_vector:
|
||||
case opcode::OP_bit_or:
|
||||
case opcode::OP_AddArray:
|
||||
case opcode::OP_waittillmatch2:
|
||||
case opcode::OP_shift_right:
|
||||
break;
|
||||
case opcode::OP_GetByte:
|
||||
case opcode::OP_GetNegByte:
|
||||
script_->write_endian<std::uint8_t>(static_cast<std::uint8_t>(std::stoi(inst->data[0])));
|
||||
break;
|
||||
case opcode::OP_GetUnsignedShort:
|
||||
case opcode::OP_GetNegUnsignedShort:
|
||||
script_->write_endian<std::uint16_t>(static_cast<std::uint16_t>(std::stoi(inst->data[0])));
|
||||
break;
|
||||
case opcode::OP_GetInteger:
|
||||
script_->write_endian<std::int32_t>(std::stoi(inst->data[0]));
|
||||
break;
|
||||
case opcode::OP_GetFloat:
|
||||
script_->write_endian<float>(std::stof(inst->data[0]));
|
||||
break;
|
||||
case opcode::OP_GetVector:
|
||||
inst->size += script_->align(4);
|
||||
script_->write_endian<float>(std::stof(inst->data[0]));
|
||||
script_->write_endian<float>(std::stof(inst->data[1]));
|
||||
script_->write_endian<float>(std::stof(inst->data[2]));
|
||||
break;
|
||||
case opcode::OP_GetString:
|
||||
case opcode::OP_GetIString:
|
||||
script_->write_endian<std::uint16_t>(0);
|
||||
stack_->write_c_string(inst->data[0]);
|
||||
break;
|
||||
case opcode::OP_GetAnimation:
|
||||
script_->write_endian<std::uint32_t>(0);
|
||||
stack_->write_c_string(inst->data[0]);
|
||||
stack_->write_c_string(inst->data[1]);
|
||||
break;
|
||||
case opcode::OP_GetAnimTree:
|
||||
script_->write_endian<std::uint8_t>(0);
|
||||
stack_->write_c_string(inst->data[0]);
|
||||
break;
|
||||
case opcode::OP_waittillmatch:
|
||||
script_->write_endian<std::uint8_t>(static_cast<std::uint8_t>(std::stoi(inst->data[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_endian<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:
|
||||
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_endian<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:
|
||||
assemble_local_call(inst, false);
|
||||
break;
|
||||
case opcode::OP_ScriptLocalThreadCall:
|
||||
case opcode::OP_ScriptLocalChildThreadCall:
|
||||
case opcode::OP_ScriptLocalMethodThreadCall:
|
||||
case opcode::OP_ScriptLocalMethodChildThreadCall:
|
||||
assemble_local_call(inst, true);
|
||||
break;
|
||||
case opcode::OP_GetFarFunction:
|
||||
case opcode::OP_ScriptFarFunctionCall2:
|
||||
case opcode::OP_ScriptFarFunctionCall:
|
||||
case opcode::OP_ScriptFarMethodCall:
|
||||
assemble_far_call(inst, false);
|
||||
break;
|
||||
case opcode::OP_ScriptFarThreadCall:
|
||||
case opcode::OP_ScriptFarChildThreadCall:
|
||||
case opcode::OP_ScriptFarMethodThreadCall:
|
||||
case opcode::OP_ScriptFarMethodChildThreadCall:
|
||||
assemble_far_call(inst, true);
|
||||
break;
|
||||
case opcode::OP_CallBuiltin:
|
||||
assemble_builtin_call(inst, false, true);
|
||||
break;
|
||||
case opcode::OP_CallBuiltinMethod:
|
||||
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:
|
||||
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:
|
||||
assemble_builtin_call(inst, true, false);
|
||||
break;
|
||||
case opcode::OP_JumpOnFalseExpr:
|
||||
case opcode::OP_JumpOnTrueExpr:
|
||||
case opcode::OP_JumpOnFalse:
|
||||
case opcode::OP_JumpOnTrue:
|
||||
assemble_jump(inst, true, false);
|
||||
break;
|
||||
case opcode::OP_jumpback:
|
||||
assemble_jump(inst, false, true);
|
||||
break;
|
||||
case opcode::OP_jump:
|
||||
assemble_jump(inst, false, false);
|
||||
break;
|
||||
case opcode::OP_switch:
|
||||
assemble_switch(inst);
|
||||
break;
|
||||
case opcode::OP_endswitch:
|
||||
assemble_end_switch(inst);
|
||||
break;
|
||||
default:
|
||||
throw asm_error(utils::string::va("unhandled opcode 0x%X at index '%04X'!", inst->opcode, inst->index));
|
||||
}
|
||||
}
|
||||
|
||||
void assembler::assemble_builtin_call(const instruction::ptr& inst, bool method, bool args)
|
||||
{
|
||||
if (args)
|
||||
{
|
||||
script_->write_endian<std::uint8_t>(static_cast<std::uint8_t>(std::stoi(inst->data[1])));
|
||||
}
|
||||
|
||||
const auto id = method ? resolver::method_id(inst->data[0]) : resolver::function_id(inst->data[0]);
|
||||
|
||||
script_->write_endian<std::uint16_t>(id);
|
||||
}
|
||||
|
||||
void assembler::assemble_local_call(const instruction::ptr& inst, bool thread)
|
||||
{
|
||||
const auto addr = resolve_function(inst->data[0]);
|
||||
const auto offset = static_cast<std::int32_t>(addr - inst->index - 1);
|
||||
|
||||
assemble_offset(offset);
|
||||
|
||||
if (thread)
|
||||
{
|
||||
script_->write_endian<std::uint8_t>(static_cast<std::uint8_t>(std::stoi(inst->data[1])));
|
||||
}
|
||||
}
|
||||
|
||||
void assembler::assemble_far_call(const instruction::ptr& inst, bool thread)
|
||||
{
|
||||
script_->write_endian<std::uint8_t>(0);
|
||||
script_->write_endian<std::uint16_t>(0);
|
||||
|
||||
if (thread)
|
||||
{
|
||||
script_->write_endian<std::uint8_t>(static_cast<std::uint8_t>(std::stoi(inst->data[2])));
|
||||
}
|
||||
|
||||
const auto file_id = resolver::token_id(inst->data[0]);
|
||||
const auto func_id = resolver::token_id(inst->data[1]);
|
||||
|
||||
stack_->write_endian<std::uint16_t>(file_id);
|
||||
if (file_id == 0) stack_->write_c_string(inst->data[0]);
|
||||
stack_->write_endian<std::uint16_t>(func_id);
|
||||
if (func_id == 0) stack_->write_c_string(inst->data[1]);
|
||||
}
|
||||
|
||||
void assembler::assemble_switch(const instruction::ptr& inst)
|
||||
{
|
||||
const auto addr = resolve_label(inst->data[0]);
|
||||
|
||||
script_->write_endian<std::int32_t>(addr - inst->index - 4);
|
||||
}
|
||||
|
||||
void assembler::assemble_end_switch(const instruction::ptr& inst)
|
||||
{
|
||||
const auto count = std::stoul(inst->data[0]);
|
||||
|
||||
script_->write_endian<std::uint16_t>(static_cast<std::uint16_t>(count));
|
||||
|
||||
std::uint32_t index = inst->index + 3;
|
||||
|
||||
for (auto i = 0u; i < count; i++)
|
||||
{
|
||||
if (inst->data[1 + (3 * i)] == "case")
|
||||
{
|
||||
if (utils::string::is_number(inst->data[1 + (3 * i) + 1]))
|
||||
{
|
||||
script_->write_endian<uint32_t>((std::stoi(inst->data[1 + (3 * i) + 1]) & 0xFFFFFF) + 0x800000);
|
||||
}
|
||||
else
|
||||
{
|
||||
script_->write_endian<uint32_t>(i + 1);
|
||||
stack_->write_c_string(inst->data[1 + (3 * i) + 1]);
|
||||
}
|
||||
|
||||
index += 4;
|
||||
|
||||
const auto addr = resolve_label(inst->data[1 + (3 * i) + 2]);
|
||||
|
||||
assemble_offset(addr - index);
|
||||
|
||||
index += 3;
|
||||
}
|
||||
else if (inst->data[1 + (3 * i)] == "default")
|
||||
{
|
||||
script_->write_endian<uint32_t>(0);
|
||||
stack_->write_c_string("\x01");
|
||||
|
||||
index += 4;
|
||||
|
||||
const auto addr = resolve_label(inst->data[1 + (3 * i) + 1]);
|
||||
|
||||
assemble_offset(addr - index);
|
||||
|
||||
index += 3;
|
||||
}
|
||||
else
|
||||
{
|
||||
throw asm_error("invalid switch case '" + inst->data[1 + (3 * i)] + "'!");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void assembler::assemble_field_variable(const instruction::ptr& inst)
|
||||
{
|
||||
auto id = resolver::token_id(inst->data[0]);
|
||||
|
||||
if (id == 0) id = 0xFFFF;
|
||||
|
||||
script_->write_endian<std::uint16_t>(id);
|
||||
|
||||
if (id > max_string_id)
|
||||
{
|
||||
stack_->write_endian<std::uint16_t>(0);
|
||||
stack_->write_c_string(inst->data[0]);
|
||||
}
|
||||
}
|
||||
|
||||
void assembler::assemble_jump(const instruction::ptr& inst, bool expr, bool back)
|
||||
{
|
||||
const auto addr = resolve_label(inst->data[0]);
|
||||
|
||||
if (expr)
|
||||
{
|
||||
script_->write_endian<std::int16_t>(static_cast<std::int16_t>(addr - inst->index - 3));
|
||||
}
|
||||
else if (back)
|
||||
{
|
||||
script_->write_endian<std::int16_t>(static_cast<std::int16_t>((inst->index + 3) - addr));
|
||||
}
|
||||
else
|
||||
{
|
||||
script_->write_endian<std::int32_t>(static_cast<std::int32_t>(addr - inst->index - 5));
|
||||
}
|
||||
}
|
||||
|
||||
void assembler::assemble_offset(std::int32_t offset)
|
||||
{
|
||||
std::array<std::uint8_t, 4> bytes = {};
|
||||
|
||||
offset = (offset << 10) >> 8;
|
||||
|
||||
*reinterpret_cast<std::int32_t*>(bytes.data()) = offset;
|
||||
|
||||
script_->write_endian<std::uint8_t>(bytes[2]);
|
||||
script_->write_endian<std::uint8_t>(bytes[1]);
|
||||
script_->write_endian<std::uint8_t>(bytes[0]);
|
||||
}
|
||||
|
||||
auto assembler::resolve_function(const std::string& name) -> std::int32_t
|
||||
{
|
||||
for (const auto& entry : functions_)
|
||||
{
|
||||
if (entry->name == name)
|
||||
{
|
||||
return entry->index;
|
||||
}
|
||||
}
|
||||
|
||||
throw asm_error("couldn't resolve local function address of '" + name + "'!");
|
||||
}
|
||||
|
||||
auto assembler::resolve_label(const std::string& name) -> std::int32_t
|
||||
{
|
||||
for (const auto& entry : labels_)
|
||||
{
|
||||
if (entry.second == name)
|
||||
{
|
||||
return entry.first;
|
||||
}
|
||||
}
|
||||
|
||||
throw asm_error("couldn't resolve label address of '" + name + "'!");
|
||||
}
|
||||
|
||||
} // namespace xsk::gsc::iw6c
|
@ -1,40 +0,0 @@
|
||||
// Copyright 2022 xensik. All rights reserved.
|
||||
//
|
||||
// Use of this source code is governed by a GNU GPLv3 license
|
||||
// that can be found in the LICENSE file.
|
||||
|
||||
#pragma once
|
||||
|
||||
namespace xsk::gsc::iw6c
|
||||
{
|
||||
|
||||
class assembler : public gsc::assembler
|
||||
{
|
||||
std::string filename_;
|
||||
utils::byte_buffer::ptr script_;
|
||||
utils::byte_buffer::ptr stack_;
|
||||
std::vector<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<function::ptr>& funcs);
|
||||
|
||||
private:
|
||||
void assemble_function(const function::ptr& func);
|
||||
void assemble_instruction(const instruction::ptr& inst);
|
||||
void assemble_builtin_call(const instruction::ptr& inst, bool method, bool args);
|
||||
void assemble_local_call(const instruction::ptr& inst, bool thread);
|
||||
void assemble_far_call(const instruction::ptr& inst, bool thread);
|
||||
void assemble_switch(const instruction::ptr& inst);
|
||||
void assemble_end_switch(const instruction::ptr& inst);
|
||||
void assemble_field_variable(const instruction::ptr& inst);
|
||||
void assemble_jump(const instruction::ptr& inst, bool expr, bool back);
|
||||
void assemble_offset(std::int32_t offset);
|
||||
auto resolve_function(const std::string& name) -> std::int32_t;
|
||||
auto resolve_label(const std::string& name) -> std::int32_t;
|
||||
};
|
||||
|
||||
} // namespace xsk::gsc::iw6c
|
File diff suppressed because it is too large
Load Diff
@ -1,159 +0,0 @@
|
||||
// Copyright 2022 xensik. All rights reserved.
|
||||
//
|
||||
// Use of this source code is governed by a GNU GPLv3 license
|
||||
// that can be found in the LICENSE file.
|
||||
|
||||
#pragma once
|
||||
|
||||
namespace xsk::gsc::iw6c
|
||||
{
|
||||
|
||||
enum class opcode : std::uint8_t;
|
||||
|
||||
class compiler : public gsc::compiler
|
||||
{
|
||||
build mode_;
|
||||
std::string filename_;
|
||||
std::vector<function::ptr> assembly_;
|
||||
function::ptr function_;
|
||||
std::uint32_t index_;
|
||||
std::uint32_t label_idx_;
|
||||
std::uint8_t stack_idx_;
|
||||
std::vector<std::string> local_stack_;
|
||||
std::vector<std::string> local_functions_;
|
||||
std::vector<include_t> includes_;
|
||||
std::vector<animtree_t> animtrees_;
|
||||
std::unordered_map<std::string, ast::expr> constants_;
|
||||
std::vector<block*> break_blks_;
|
||||
std::vector<block*> continue_blks_;
|
||||
bool can_break_;
|
||||
bool can_continue_;
|
||||
bool developer_thread_;
|
||||
|
||||
public:
|
||||
auto output() -> std::vector<function::ptr>;
|
||||
void compile(const std::string& file, std::vector<std::uint8_t>& data);
|
||||
void mode(build mode);
|
||||
|
||||
private:
|
||||
auto parse_buffer(const std::string& file, const char* data, size_t size) -> ast::program::ptr;
|
||||
auto parse_file(const std::string& file) -> ast::program::ptr;
|
||||
void compile_program(const ast::program::ptr& program);
|
||||
void emit_include(const ast::include::ptr& include);
|
||||
void emit_declaration(const ast::decl& decl);
|
||||
void emit_decl_usingtree(const ast::decl_usingtree::ptr& animtree);
|
||||
void emit_decl_constant(const ast::decl_constant::ptr& constant);
|
||||
void emit_decl_thread(const ast::decl_thread::ptr& thread);
|
||||
void emit_stmt(const ast::stmt& stmt, const block::ptr& blk, bool last);
|
||||
void emit_stmt_list(const ast::stmt_list::ptr& stmt, const block::ptr& blk, bool last);
|
||||
void emit_stmt_dev(const ast::stmt_dev::ptr& stmt, const block::ptr& blk, bool last);
|
||||
void emit_stmt_expr(const ast::stmt_expr::ptr& stmt, const block::ptr& blk);
|
||||
void emit_stmt_call(const ast::stmt_call::ptr& stmt, const block::ptr& blk);
|
||||
void emit_stmt_assign(const ast::stmt_assign::ptr& stmt, const block::ptr& blk);
|
||||
void emit_stmt_endon(const ast::stmt_endon::ptr& stmt, const block::ptr& blk);
|
||||
void emit_stmt_notify(const ast::stmt_notify::ptr& stmt, const block::ptr& blk);
|
||||
void emit_stmt_wait(const ast::stmt_wait::ptr& stmt, const block::ptr& blk);
|
||||
void emit_stmt_waittill(const ast::stmt_waittill::ptr& stmt, const block::ptr& blk);
|
||||
void emit_stmt_waittillmatch(const ast::stmt_waittillmatch::ptr& stmt, const block::ptr& blk);
|
||||
void emit_stmt_waittillframeend(const ast::stmt_waittillframeend::ptr& stmt, const block::ptr& blk);
|
||||
void emit_stmt_if(const ast::stmt_if::ptr& stmt, const block::ptr& blk, bool last);
|
||||
void emit_stmt_ifelse(const ast::stmt_ifelse::ptr& stmt, const block::ptr& blk, bool last);
|
||||
void emit_stmt_while(const ast::stmt_while::ptr& stmt, const block::ptr& blk);
|
||||
void emit_stmt_dowhile(const ast::stmt_dowhile::ptr& stmt, const block::ptr& blk);
|
||||
void emit_stmt_for(const ast::stmt_for::ptr& stmt, const block::ptr& blk);
|
||||
void emit_stmt_foreach(const ast::stmt_foreach::ptr& stmt, const block::ptr& blk);
|
||||
void emit_stmt_switch(const ast::stmt_switch::ptr& stmt, const block::ptr& blk);
|
||||
void emit_stmt_case(const ast::stmt_case::ptr& stmt, const block::ptr& blk);
|
||||
void emit_stmt_default(const ast::stmt_default::ptr& stmt, const block::ptr& blk);
|
||||
void emit_stmt_break(const ast::stmt_break::ptr& stmt, const block::ptr& blk);
|
||||
void emit_stmt_continue(const ast::stmt_continue::ptr& stmt, const block::ptr& blk);
|
||||
void emit_stmt_return(const ast::stmt_return::ptr& stmt, const block::ptr& blk);
|
||||
void emit_stmt_breakpoint(const ast::stmt_breakpoint::ptr& stmt, const block::ptr& blk);
|
||||
void emit_stmt_prof_begin(const ast::stmt_prof_begin::ptr& stmt, const block::ptr& blk);
|
||||
void emit_stmt_prof_end(const ast::stmt_prof_end::ptr& stmt, const block::ptr& blk);
|
||||
void emit_expr(const ast::expr& expr, const block::ptr& blk);
|
||||
void emit_expr_assign(const ast::expr_assign::ptr& expr, const block::ptr& blk);
|
||||
void emit_expr_clear(const ast::expr& expr, const block::ptr& blk);
|
||||
void emit_expr_clear_local(const ast::expr_identifier::ptr& expr, const block::ptr& blk);
|
||||
void emit_expr_increment(const ast::expr_increment::ptr& expr, const block::ptr& blk, bool is_stmt);
|
||||
void emit_expr_decrement(const ast::expr_decrement::ptr& expr, const block::ptr& blk, bool is_stmt);
|
||||
void emit_expr_ternary(const ast::expr_ternary::ptr& expr, const block::ptr& blk);
|
||||
void emit_expr_binary(const ast::expr_binary::ptr& expr, const block::ptr& blk);
|
||||
void emit_expr_and(const ast::expr_and::ptr& expr, const block::ptr& blk);
|
||||
void emit_expr_or(const ast::expr_or::ptr& expr, const block::ptr& blk);
|
||||
void emit_expr_complement(const ast::expr_complement::ptr& expr, const block::ptr& blk);
|
||||
void emit_expr_negate(const ast::expr_negate::ptr& expr, const block::ptr& blk);
|
||||
void emit_expr_not(const ast::expr_not::ptr& expr, const block::ptr& blk);
|
||||
void emit_expr_call(const ast::expr_call::ptr& expr, const block::ptr& blk, bool is_stmt);
|
||||
void emit_expr_call_pointer(const ast::expr_pointer::ptr& expr, const block::ptr& blk, bool is_stmt);
|
||||
void emit_expr_call_function(const ast::expr_function::ptr& expr, const block::ptr& blk, bool is_stmt);
|
||||
void emit_expr_method(const ast::expr_method::ptr& expr, const block::ptr& blk, bool is_stmt);
|
||||
void emit_expr_method_pointer(const ast::expr_pointer::ptr& expr, const ast::expr& obj, const block::ptr& blk, bool is_stmt);
|
||||
void emit_expr_method_function(const ast::expr_function::ptr& expr, const ast::expr& obj, const block::ptr& blk, bool is_stmt);
|
||||
void emit_expr_add_array(const ast::expr_add_array::ptr& expr, const block::ptr& blk);
|
||||
void emit_expr_parameters(const ast::expr_parameters::ptr& expr, const block::ptr& blk);
|
||||
void emit_expr_arguments(const ast::expr_arguments::ptr& expr, const block::ptr& blk);
|
||||
void emit_expr_reference(const ast::expr_reference::ptr& expr, const block::ptr& blk);
|
||||
void emit_expr_size(const ast::expr_size::ptr& expr, const block::ptr& blk);
|
||||
void emit_expr_tuple(const ast::expr_tuple::ptr& expr, const block::ptr& blk);
|
||||
void emit_expr_variable_ref(const ast::expr& expr, const block::ptr& blk, bool set);
|
||||
void emit_expr_array_ref(const ast::expr_array::ptr& expr, const block::ptr& blk, bool set);
|
||||
void emit_expr_field_ref(const ast::expr_field::ptr& expr, const block::ptr& blk, bool set);
|
||||
void emit_expr_local_ref(const ast::expr_identifier::ptr& expr, const block::ptr& blk, bool set);
|
||||
void emit_expr_variable(const ast::expr& expr, const block::ptr& blk);
|
||||
void emit_expr_array(const ast::expr_array::ptr& expr, const block::ptr& blk);
|
||||
void emit_expr_field(const ast::expr_field::ptr& expr, const block::ptr& blk);
|
||||
void emit_expr_local(const ast::expr_identifier::ptr& expr, const block::ptr& blk);
|
||||
void emit_expr_object(const ast::expr& expr, const block::ptr& blk);
|
||||
void emit_expr_vector(const ast::expr_vector::ptr& expr, const block::ptr& blk);
|
||||
void emit_expr_animation(const ast::expr_animation::ptr& expr);
|
||||
void emit_expr_animtree(const ast::expr_animtree::ptr& expr);
|
||||
void emit_expr_istring(const ast::expr_istring::ptr& expr);
|
||||
void emit_expr_string(const ast::expr_string::ptr& expr);
|
||||
void emit_expr_float(const ast::expr_float::ptr& expr);
|
||||
void emit_expr_integer(const ast::expr_integer::ptr& expr);
|
||||
void emit_expr_false(const ast::expr_false::ptr& expr);
|
||||
void emit_expr_true(const ast::expr_true::ptr& expr);
|
||||
void emit_create_local_vars(const block::ptr& blk);
|
||||
void emit_remove_local_vars(const block::ptr& blk);
|
||||
void emit_opcode(opcode op);
|
||||
void emit_opcode(opcode op, const std::string& data);
|
||||
void emit_opcode(opcode op, const std::vector<std::string>& data);
|
||||
void process_thread(const ast::decl_thread::ptr& decl, const block::ptr& blk);
|
||||
void process_stmt(const ast::stmt& stmt, const block::ptr& blk);
|
||||
void process_stmt_list(const ast::stmt_list::ptr& stmt, const block::ptr& blk);
|
||||
void process_stmt_dev(const ast::stmt_dev::ptr& stmt, const block::ptr& blk);
|
||||
void process_stmt_expr(const ast::stmt_expr::ptr& stmt, const block::ptr& blk);
|
||||
void process_stmt_assign(const ast::stmt_assign::ptr& stmt, const block::ptr& blk);
|
||||
void process_stmt_waittill(const ast::stmt_waittill::ptr& stmt, const block::ptr& blk);
|
||||
void process_stmt_if(const ast::stmt_if::ptr& stmt, const block::ptr& blk);
|
||||
void process_stmt_ifelse(const ast::stmt_ifelse::ptr& stmt, const block::ptr& blk);
|
||||
void process_stmt_while(const ast::stmt_while::ptr& stmt, const block::ptr& blk);
|
||||
void process_stmt_dowhile(const ast::stmt_dowhile::ptr& stmt, const block::ptr& blk);
|
||||
void process_stmt_for(const ast::stmt_for::ptr& stmt, const block::ptr& blk);
|
||||
void process_stmt_foreach(const ast::stmt_foreach::ptr& stmt, const block::ptr& blk);
|
||||
void process_stmt_switch(const ast::stmt_switch::ptr& stmt, const block::ptr& blk);
|
||||
void process_stmt_break(const ast::stmt_break::ptr& stmt, const block::ptr& blk);
|
||||
void process_stmt_continue(const ast::stmt_continue::ptr& stmt, const block::ptr& blk);
|
||||
void process_stmt_return(const ast::stmt_return::ptr& stmt, const block::ptr& blk);
|
||||
void process_expr(const ast::expr& expr, const block::ptr& blk);
|
||||
void process_expr_tuple(const ast::expr_tuple::ptr& expr, const block::ptr& blk);
|
||||
void process_expr_parameters(const ast::expr_parameters::ptr& decl, const block::ptr& blk);
|
||||
void variable_register(const std::string& name, const block::ptr& blk);
|
||||
void variable_initialize(const ast::expr_identifier::ptr& name, const block::ptr& blk);
|
||||
void variable_create(const ast::expr_identifier::ptr& name, const block::ptr& blk);
|
||||
auto variable_stack_index(const ast::expr_identifier::ptr& name, const block::ptr& blk) -> std::uint8_t;
|
||||
auto variable_create_index(const ast::expr_identifier::ptr& name, const block::ptr& blk) -> std::string;
|
||||
auto variable_access_index(const ast::expr_identifier::ptr& name, const block::ptr& blk) -> std::string;
|
||||
auto variable_initialized(const ast::expr_identifier::ptr& name, const block::ptr& blk) -> bool;
|
||||
auto resolve_function_type(const ast::expr_function::ptr& expr) -> ast::call::type;
|
||||
auto resolve_reference_type(const ast::expr_reference::ptr& expr, bool& method) -> ast::call::type;
|
||||
auto is_constant_condition(const ast::expr& expr) -> bool;
|
||||
auto create_label() -> std::string;
|
||||
auto insert_label() -> std::string;
|
||||
void insert_label(const std::string& label);
|
||||
|
||||
auto map_known_includes(const std::string& include) -> bool;
|
||||
};
|
||||
|
||||
} // namespace xsk::gsc::iw6c
|
@ -1,23 +0,0 @@
|
||||
// Copyright 2022 xensik. All rights reserved.
|
||||
//
|
||||
// Use of this source code is governed by a GNU GPLv3 license
|
||||
// that can be found in the LICENSE file.
|
||||
|
||||
#include "stdafx.hpp"
|
||||
#include "iw6c.hpp"
|
||||
|
||||
namespace xsk::gsc::iw6c
|
||||
{
|
||||
|
||||
void context::init(build mode, read_cb_type callback)
|
||||
{
|
||||
compiler_.mode(mode);
|
||||
resolver::init(callback);
|
||||
}
|
||||
|
||||
void context::cleanup()
|
||||
{
|
||||
resolver::cleanup();
|
||||
}
|
||||
|
||||
} // namespace xsk::gsc::iw6c
|
@ -1,28 +0,0 @@
|
||||
// Copyright 2022 xensik. All rights reserved.
|
||||
//
|
||||
// Use of this source code is governed by a GNU GPLv3 license
|
||||
// that can be found in the LICENSE file.
|
||||
|
||||
#pragma once
|
||||
|
||||
namespace xsk::gsc::iw6c
|
||||
{
|
||||
|
||||
class context : public gsc::context
|
||||
{
|
||||
iw6c::assembler assembler_;
|
||||
iw6c::disassembler disassembler_;
|
||||
iw6c::compiler compiler_;
|
||||
iw6c::decompiler decompiler_;
|
||||
|
||||
public:
|
||||
void init(build mode, read_cb_type callback);
|
||||
void cleanup();
|
||||
|
||||
auto assembler() -> gsc::assembler& { return assembler_; }
|
||||
auto disassembler() -> gsc::disassembler& { return disassembler_; }
|
||||
auto compiler() -> gsc::compiler& { return compiler_; }
|
||||
auto decompiler() -> gsc::decompiler& { return decompiler_; }
|
||||
};
|
||||
|
||||
} // namespace xsk::gsc::iw6c
|
File diff suppressed because it is too large
Load Diff
@ -1,101 +0,0 @@
|
||||
// Copyright 2022 xensik. All rights reserved.
|
||||
//
|
||||
// Use of this source code is governed by a GNU GPLv3 license
|
||||
// that can be found in the LICENSE file.
|
||||
|
||||
#pragma once
|
||||
|
||||
namespace xsk::gsc::iw6c
|
||||
{
|
||||
|
||||
class decompiler : public gsc::decompiler
|
||||
{
|
||||
std::string filename_;
|
||||
ast::program::ptr program_;
|
||||
ast::decl_thread::ptr func_;
|
||||
std::unordered_map<std::uint32_t, std::string> labels_;
|
||||
std::vector<std::string> expr_labels_;
|
||||
std::vector<std::string> tern_labels_;
|
||||
std::stack<ast::node::ptr> stack_;
|
||||
std::vector<block> blocks_;
|
||||
bool in_waittill_;
|
||||
|
||||
public:
|
||||
auto output() -> std::vector<std::uint8_t>;
|
||||
void decompile(const std::string& file, std::vector<function::ptr>& funcs);
|
||||
|
||||
private:
|
||||
void decompile_function(const function::ptr& func);
|
||||
void decompile_instruction(const instruction::ptr& inst);
|
||||
void decompile_expressions(const instruction::ptr& inst);
|
||||
void decompile_statements(const ast::stmt_list::ptr& stmt);
|
||||
void decompile_loops(const ast::stmt_list::ptr& stmt);
|
||||
void decompile_switches(const ast::stmt_list::ptr& stmt);
|
||||
void decompile_ifelses(const ast::stmt_list::ptr& stmt);
|
||||
void decompile_aborts(const ast::stmt_list::ptr& stmt);
|
||||
void decompile_tuples(const ast::stmt_list::ptr& stmt);
|
||||
void decompile_if(const ast::stmt_list::ptr& stmt, std::size_t begin, std::size_t end);
|
||||
void decompile_ifelse(const ast::stmt_list::ptr& stmt, std::size_t begin, std::size_t end);
|
||||
void decompile_ifelse_end(const ast::stmt_list::ptr& stmt, std::size_t begin, std::size_t end);
|
||||
void decompile_inf(const ast::stmt_list::ptr& stmt, std::size_t begin, std::size_t end);
|
||||
void decompile_loop(const ast::stmt_list::ptr& stmt, std::size_t begin, std::size_t end);
|
||||
void decompile_while(const ast::stmt_list::ptr& stmt, std::size_t begin, std::size_t end);
|
||||
void decompile_dowhile(const ast::stmt_list::ptr& stmt, std::size_t begin, std::size_t end);
|
||||
void decompile_for(const ast::stmt_list::ptr& stmt, std::size_t begin, std::size_t end);
|
||||
void decompile_foreach(const ast::stmt_list::ptr& stmt, std::size_t begin, std::size_t end);
|
||||
void decompile_switch(const ast::stmt_list::ptr& stmt, std::size_t begin);
|
||||
auto find_location_reference(const ast::stmt_list::ptr& stmt, std::size_t begin, std::size_t end, const std::string& location) -> bool;
|
||||
auto find_location_index(const ast::stmt_list::ptr& stmt, const std::string& location) -> std::size_t;
|
||||
auto last_location_index(const ast::stmt_list::ptr& stmt, std::size_t index) -> bool;
|
||||
void process_stack(const ast::decl_thread::ptr& thread);
|
||||
void process_parameters(const ast::expr_parameters::ptr& params, const block::ptr& blk);
|
||||
void process_stmt(const ast::stmt& stmt, const block::ptr& blk);
|
||||
void process_stmt_list(const ast::stmt_list::ptr& stmt, const block::ptr& blk);
|
||||
void process_stmt_expr(const ast::stmt_expr::ptr& stmt, const block::ptr& blk);
|
||||
void process_stmt_call(const ast::stmt_call::ptr& stmt, const block::ptr& blk);
|
||||
void process_stmt_assign(const ast::stmt_assign::ptr& stmt, const block::ptr& blk);
|
||||
void process_stmt_endon(const ast::stmt_endon::ptr& stmt, const block::ptr& blk);
|
||||
void process_stmt_notify(const ast::stmt_notify::ptr& stmt, const block::ptr& blk);
|
||||
void process_stmt_wait(const ast::stmt_wait::ptr& stmt, const block::ptr& blk);
|
||||
void process_stmt_waittill(const ast::stmt_waittill::ptr& stmt, const block::ptr& blk);
|
||||
void process_stmt_waittillmatch(const ast::stmt_waittillmatch::ptr& stmt, const block::ptr& blk);
|
||||
void process_stmt_if(const ast::stmt_if::ptr& stmt, const block::ptr& blk);
|
||||
void process_stmt_ifelse(const ast::stmt_ifelse::ptr& stmt, const block::ptr& blk);
|
||||
void process_stmt_while(const ast::stmt_while::ptr& stmt, const block::ptr& blk);
|
||||
void process_stmt_dowhile(const ast::stmt_dowhile::ptr& stmt, const block::ptr& blk);
|
||||
void process_stmt_for(const ast::stmt_for::ptr& stmt, const block::ptr& blk);
|
||||
void process_stmt_foreach(const ast::stmt_foreach::ptr& stmt, const block::ptr& blk);
|
||||
void process_stmt_switch(const ast::stmt_switch::ptr& stmt, const block::ptr& blk);
|
||||
void process_stmt_cases(const ast::stmt_list::ptr& stmt, const block::ptr& blk);
|
||||
void process_stmt_break(const ast::stmt_break::ptr& stmt, const block::ptr& blk);
|
||||
void process_stmt_continue(const ast::stmt_continue::ptr& stmt, const block::ptr& blk);
|
||||
void process_stmt_return(const ast::stmt_return::ptr& stmt, const block::ptr& blk);
|
||||
void process_expr(ast::expr& expr, const block::ptr& blk);
|
||||
void process_expr_assign(ast::expr_assign::ptr& expr, const block::ptr& blk);
|
||||
void process_expr_increment(const ast::expr_increment::ptr& expr, const block::ptr& blk);
|
||||
void process_expr_decrement(const ast::expr_decrement::ptr& expr, const block::ptr& blk);
|
||||
void process_expr_ternary(const ast::expr_ternary::ptr& expr, const block::ptr& blk);
|
||||
void process_expr_binary(const ast::expr_binary::ptr& expr, const block::ptr& blk);
|
||||
void process_expr_and(const ast::expr_and::ptr& expr, const block::ptr& blk);
|
||||
void process_expr_or(const ast::expr_or::ptr& expr, const block::ptr& blk);
|
||||
void process_expr_complement(const ast::expr_complement::ptr& expr, const block::ptr& blk);
|
||||
void process_expr_not(const ast::expr_not::ptr& expr, const block::ptr& blk);
|
||||
void process_expr_call(const ast::expr_call::ptr& expr, const block::ptr& blk);
|
||||
void process_expr_method(const ast::expr_method::ptr& expr, const block::ptr& blk);
|
||||
void process_expr_call_pointer(const ast::expr_pointer::ptr& expr, const block::ptr& blk);
|
||||
void process_expr_call_function(const ast::expr_function::ptr& expr, const block::ptr& blk);
|
||||
void process_expr_method_pointer(const ast::expr_pointer::ptr& expr, ast::expr& obj, const block::ptr& blk);
|
||||
void process_expr_method_function(const ast::expr_function::ptr& expr, ast::expr& obj, const block::ptr& blk);
|
||||
void process_expr_arguments(const ast::expr_arguments::ptr& expr, const block::ptr& blk);
|
||||
void process_expr_add_array(const ast::expr_add_array::ptr& expr, const block::ptr& blk);
|
||||
void process_expr_size(const ast::expr_size::ptr& expr, const block::ptr& blk);
|
||||
void process_expr_tuple(const ast::expr_tuple::ptr& expr, const block::ptr& blk);
|
||||
void process_expr_array(const ast::expr_array::ptr& expr, const block::ptr& blk);
|
||||
void process_expr_field(const ast::expr_field::ptr& expr, const block::ptr& blk);
|
||||
void process_expr_vector(const ast::expr_vector::ptr& vec, const block::ptr& blk);
|
||||
void process_var_create(ast::expr& expr, const block::ptr& blk, bool fromstmt = false);
|
||||
void process_var_access(ast::expr& expr, const block::ptr& blk);
|
||||
void process_var_remove(const ast::asm_remove::ptr& expr, const block::ptr& blk);
|
||||
};
|
||||
|
||||
} // namespace xsk::gsc::iw6c
|
@ -1,575 +0,0 @@
|
||||
// Copyright 2022 xensik. All rights reserved.
|
||||
//
|
||||
// Use of this source code is governed by a GNU GPLv3 license
|
||||
// that can be found in the LICENSE file.
|
||||
|
||||
#include "stdafx.hpp"
|
||||
#include "iw6c.hpp"
|
||||
|
||||
namespace xsk::gsc::iw6c
|
||||
{
|
||||
|
||||
auto disassembler::output() -> std::vector<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("// IW6 GSC ASSEMBLY\n");
|
||||
output_->write_string("// Disassembled by https://github.com/xensik/gsc-tool\n");
|
||||
|
||||
for (const auto& func : functions_)
|
||||
{
|
||||
print_function(func);
|
||||
}
|
||||
|
||||
std::vector<std::uint8_t> output;
|
||||
|
||||
output.resize(output_->pos());
|
||||
std::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<function>());
|
||||
const auto& func = functions_.back();
|
||||
|
||||
func->index = static_cast<std::uint32_t>(script_->pos());
|
||||
func->size = stack_->read_endian<std::uint32_t>();
|
||||
func->id = stack_->read_endian<std::uint16_t>();
|
||||
func->name = func->id == 0 ? stack_->read_c_string() : resolver::token_name(static_cast<std::uint16_t>(func->id));
|
||||
|
||||
dissasemble_function(func);
|
||||
|
||||
func->labels = labels_;
|
||||
labels_.clear();
|
||||
}
|
||||
|
||||
resolve_local_functions();
|
||||
}
|
||||
|
||||
void disassembler::dissasemble_function(const function::ptr& func)
|
||||
{
|
||||
auto size = func->size;
|
||||
|
||||
while (size > 0)
|
||||
{
|
||||
func->instructions.push_back(std::make_unique<instruction>());
|
||||
|
||||
const 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);
|
||||
|
||||
dissasemble_instruction(inst);
|
||||
|
||||
size -= inst->size;
|
||||
}
|
||||
}
|
||||
|
||||
void disassembler::dissasemble_instruction(const instruction::ptr& inst)
|
||||
{
|
||||
switch (static_cast<opcode>(inst->opcode))
|
||||
{
|
||||
case opcode::OP_Return:
|
||||
case opcode::OP_BoolNot:
|
||||
case opcode::OP_CastBool:
|
||||
case opcode::OP_inequality:
|
||||
case opcode::OP_GetThisthread:
|
||||
case opcode::OP_ClearLocalVariableFieldCached0:
|
||||
case opcode::OP_checkclearparams:
|
||||
case opcode::OP_CastFieldObject:
|
||||
case opcode::OP_End:
|
||||
case opcode::OP_size:
|
||||
case opcode::OP_EmptyArray:
|
||||
case opcode::OP_bit_and:
|
||||
case opcode::OP_less_equal:
|
||||
case opcode::OP_voidCodepos:
|
||||
// case opcode::OP_ClearVariableField:
|
||||
case opcode::OP_divide:
|
||||
case opcode::OP_GetSelf:
|
||||
case opcode::OP_SetLocalVariableFieldCached0:
|
||||
case opcode::OP_plus:
|
||||
case opcode::OP_BoolComplement:
|
||||
case opcode::OP_ScriptMethodCallPointer:
|
||||
case opcode::OP_inc:
|
||||
case opcode::OP_clearparams:
|
||||
case opcode::OP_EvalLocalVariableRefCached0:
|
||||
case opcode::OP_ScriptFunctionCallPointer:
|
||||
case opcode::OP_endon:
|
||||
case opcode::OP_greater_equal:
|
||||
case opcode::OP_GetSelfObject:
|
||||
case opcode::OP_SetVariableField:
|
||||
case opcode::OP_EvalLocalArrayRefCached0:
|
||||
case opcode::OP_less:
|
||||
case opcode::OP_GetGameRef:
|
||||
case opcode::OP_waittillFrameEnd:
|
||||
case opcode::OP_SafeSetVariableFieldCached0:
|
||||
case opcode::OP_GetLevel:
|
||||
case opcode::OP_notify:
|
||||
case opcode::OP_DecTop:
|
||||
case opcode::OP_shift_left:
|
||||
case opcode::OP_greater:
|
||||
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_GetZero:
|
||||
case opcode::OP_wait:
|
||||
case opcode::OP_minus:
|
||||
// case opcode::OP_EvalNewLocalVariableRefCached0:
|
||||
case opcode::OP_multiply:
|
||||
case opcode::OP_mod:
|
||||
case opcode::OP_GetGame:
|
||||
case opcode::OP_waittill:
|
||||
case opcode::OP_dec:
|
||||
case opcode::OP_PreScriptCall:
|
||||
case opcode::OP_GetAnim:
|
||||
case opcode::OP_GetUndefined:
|
||||
case opcode::OP_GetAnimObject:
|
||||
case opcode::OP_GetLevelObject:
|
||||
case opcode::OP_bit_ex_or:
|
||||
case opcode::OP_equality:
|
||||
case opcode::OP_ClearArray:
|
||||
case opcode::OP_EvalArrayRef:
|
||||
case opcode::OP_EvalArray:
|
||||
case opcode::OP_vector:
|
||||
case opcode::OP_bit_or:
|
||||
case opcode::OP_AddArray:
|
||||
case opcode::OP_waittillmatch2:
|
||||
case opcode::OP_shift_right:
|
||||
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_endian<std::uint16_t>()));
|
||||
break;
|
||||
case opcode::OP_GetInteger:
|
||||
inst->data.push_back(utils::string::va("%i", script_->read_endian<std::int32_t>()));
|
||||
break;
|
||||
case opcode::OP_GetFloat:
|
||||
inst->data.push_back(utils::string::float_string(script_->read_endian<float>()));
|
||||
break;
|
||||
case opcode::OP_GetVector:
|
||||
inst->size += script_->align(4);
|
||||
inst->data.push_back(utils::string::float_string(script_->read_endian<float>()));
|
||||
inst->data.push_back(utils::string::float_string(script_->read_endian<float>()));
|
||||
inst->data.push_back(utils::string::float_string(script_->read_endian<float>()));
|
||||
break;
|
||||
case opcode::OP_GetString:
|
||||
case opcode::OP_GetIString:
|
||||
script_->seek(2);
|
||||
inst->data.push_back(utils::string::to_literal(stack_->read_c_string()));
|
||||
break;
|
||||
case opcode::OP_GetAnimation:
|
||||
script_->seek(4);
|
||||
inst->data.push_back(utils::string::quote(stack_->read_c_string(), false));
|
||||
inst->data.push_back(utils::string::quote(stack_->read_c_string(), false));
|
||||
break;
|
||||
case opcode::OP_GetAnimTree:
|
||||
script_->seek(1);
|
||||
inst->data.push_back(utils::string::quote(stack_->read_c_string(), false));
|
||||
break;
|
||||
case opcode::OP_waittillmatch:
|
||||
inst->data.push_back(utils::string::va("%i", script_->read<std::uint8_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:
|
||||
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:
|
||||
disassemble_local_call(inst, false);
|
||||
break;
|
||||
case opcode::OP_ScriptLocalThreadCall:
|
||||
case opcode::OP_ScriptLocalChildThreadCall:
|
||||
case opcode::OP_ScriptLocalMethodThreadCall:
|
||||
case opcode::OP_ScriptLocalMethodChildThreadCall:
|
||||
disassemble_local_call(inst, true);
|
||||
break;
|
||||
case opcode::OP_GetFarFunction:
|
||||
case opcode::OP_ScriptFarFunctionCall2:
|
||||
case opcode::OP_ScriptFarFunctionCall:
|
||||
case opcode::OP_ScriptFarMethodCall:
|
||||
disassemble_far_call(inst, false);
|
||||
break;
|
||||
case opcode::OP_ScriptFarThreadCall:
|
||||
case opcode::OP_ScriptFarChildThreadCall:
|
||||
case opcode::OP_ScriptFarMethodThreadCall:
|
||||
case opcode::OP_ScriptFarMethodChildThreadCall:
|
||||
disassemble_far_call(inst, true);
|
||||
break;
|
||||
case opcode::OP_CallBuiltin:
|
||||
disassemble_builtin_call(inst, false, true);
|
||||
break;
|
||||
case opcode::OP_CallBuiltinMethod:
|
||||
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:
|
||||
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:
|
||||
disassemble_builtin_call(inst, true, false);
|
||||
break;
|
||||
case opcode::OP_JumpOnFalse:
|
||||
case opcode::OP_JumpOnTrue:
|
||||
case opcode::OP_JumpOnFalseExpr:
|
||||
case opcode::OP_JumpOnTrueExpr:
|
||||
disassemble_jump(inst, true, false);
|
||||
break;
|
||||
case opcode::OP_jumpback:
|
||||
disassemble_jump(inst, false, true);
|
||||
break;
|
||||
case opcode::OP_jump:
|
||||
disassemble_jump(inst, false, false);
|
||||
break;
|
||||
case opcode::OP_switch:
|
||||
disassemble_switch(inst);
|
||||
break;
|
||||
case opcode::OP_endswitch:
|
||||
disassemble_end_switch(inst);
|
||||
break;
|
||||
default:
|
||||
throw disasm_error(utils::string::va("unhandled opcode 0x%X at index '%04X'!", inst->opcode, inst->index));
|
||||
}
|
||||
}
|
||||
|
||||
void disassembler::disassemble_builtin_call(const instruction::ptr& inst, bool method, bool args)
|
||||
{
|
||||
if (args)
|
||||
{
|
||||
inst->data.push_back(utils::string::va("%i", script_->read<std::uint8_t>()));
|
||||
}
|
||||
|
||||
const auto id = script_->read_endian<std::uint16_t>();
|
||||
const auto name = method ? resolver::method_name(id) : resolver::function_name(id);
|
||||
inst->data.emplace(inst->data.begin(), name);
|
||||
}
|
||||
|
||||
void disassembler::disassemble_local_call(const instruction::ptr& inst, bool thread)
|
||||
{
|
||||
const auto offset = 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 instruction::ptr& inst, bool thread)
|
||||
{
|
||||
script_->seek(3);
|
||||
|
||||
if (thread)
|
||||
{
|
||||
inst->data.push_back(utils::string::va("%i", script_->read<std::uint8_t>()));
|
||||
}
|
||||
|
||||
const auto file_id = stack_->read_endian<std::uint16_t>();
|
||||
const auto file_name = file_id == 0 ? stack_->read_c_string() : resolver::token_name(file_id);
|
||||
const auto func_id = stack_->read_endian<std::uint16_t>();
|
||||
const auto func_name = func_id == 0 ? stack_->read_c_string() : resolver::token_name(func_id);
|
||||
|
||||
inst->data.emplace(inst->data.begin(), func_name);
|
||||
inst->data.emplace(inst->data.begin(), file_name);
|
||||
}
|
||||
|
||||
void disassembler::disassemble_switch(const instruction::ptr& inst)
|
||||
{
|
||||
const auto addr = inst->index + 4 + script_->read_endian<std::int32_t>();
|
||||
const auto label = utils::string::va("loc_%X", addr);
|
||||
|
||||
inst->data.push_back(label);
|
||||
labels_.insert({ addr, label });
|
||||
}
|
||||
|
||||
void disassembler::disassemble_end_switch(const instruction::ptr& inst)
|
||||
{
|
||||
const auto count = script_->read_endian<std::uint16_t>();
|
||||
inst->data.push_back(utils::string::va("%i", count));
|
||||
|
||||
std::uint32_t index = inst->index + 3;
|
||||
|
||||
if (count)
|
||||
{
|
||||
for (auto i = count; i > 0; i--)
|
||||
{
|
||||
const auto value = script_->read_endian<std::uint32_t>();
|
||||
|
||||
if (value < 0x40000)
|
||||
{
|
||||
const auto data = stack_->read_c_string();
|
||||
|
||||
if (data.data()[0] != 0x01)
|
||||
{
|
||||
inst->data.push_back("case");
|
||||
inst->data.push_back(utils::string::quote(data, false));
|
||||
}
|
||||
else
|
||||
inst->data.push_back("default");
|
||||
}
|
||||
else
|
||||
{
|
||||
inst->data.push_back("case");
|
||||
inst->data.push_back(utils::string::va("%i", (value - 0x800000) & 0xFFFFFF));
|
||||
}
|
||||
|
||||
index += 4;
|
||||
|
||||
const auto addr = disassemble_offset() + index;
|
||||
const auto label = utils::string::va("loc_%X", addr);
|
||||
|
||||
inst->data.push_back(label);
|
||||
labels_.insert({ addr, label });
|
||||
|
||||
index += 3;
|
||||
inst->size += 7;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void disassembler::disassemble_field_variable(const instruction::ptr& inst)
|
||||
{
|
||||
const auto id = script_->read_endian<std::uint16_t>();
|
||||
std::string name;
|
||||
|
||||
if (id > max_string_id)
|
||||
{
|
||||
auto temp = stack_->read_endian<std::uint16_t>();
|
||||
name = temp == 0 ? stack_->read_c_string() : std::to_string(temp);
|
||||
}
|
||||
else
|
||||
{
|
||||
name = resolver::token_name(id);
|
||||
}
|
||||
|
||||
inst->data.push_back(name);
|
||||
}
|
||||
|
||||
void disassembler::disassemble_jump(const instruction::ptr& inst, bool expr, bool back)
|
||||
{
|
||||
std::int32_t addr;
|
||||
|
||||
if (expr)
|
||||
{
|
||||
addr = inst->index + 3 + script_->read_endian<std::int16_t>();
|
||||
}
|
||||
else if (back)
|
||||
{
|
||||
addr = inst->index + 3 - script_->read_endian<std::uint16_t>();
|
||||
}
|
||||
else
|
||||
{
|
||||
addr = inst->index + 5 + script_->read_endian<std::int32_t>();
|
||||
}
|
||||
|
||||
const auto label = utils::string::va("loc_%X", addr);
|
||||
|
||||
inst->data.push_back(label);
|
||||
labels_.insert({ addr, label });
|
||||
}
|
||||
|
||||
auto disassembler::disassemble_offset() -> std::int32_t
|
||||
{
|
||||
std::array<std::uint8_t, 4> bytes = {};
|
||||
|
||||
for (auto i = 0; i < 3; i++)
|
||||
{
|
||||
bytes[2 - i] = script_->read<std::uint8_t>();
|
||||
}
|
||||
|
||||
auto offset = *reinterpret_cast<std::int32_t*>(bytes.data());
|
||||
|
||||
offset = (offset << 8) >> 10;
|
||||
|
||||
return offset;
|
||||
}
|
||||
|
||||
void disassembler::resolve_local_functions()
|
||||
{
|
||||
for (const auto& func : functions_)
|
||||
{
|
||||
for (const auto& inst : func->instructions)
|
||||
{
|
||||
switch (static_cast<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[0] = 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 (const auto& func : functions_)
|
||||
{
|
||||
if (func->index == idx)
|
||||
{
|
||||
return func->name;
|
||||
}
|
||||
}
|
||||
|
||||
throw disasm_error(utils::string::va("couldn't resolve function name at index '0x%04X'!", idx));
|
||||
}
|
||||
|
||||
throw disasm_error(utils::string::va("\"%s\" is not valid function address!", index.data()));
|
||||
}
|
||||
|
||||
void disassembler::print_function(const function::ptr& func)
|
||||
{
|
||||
output_->write_string("\n");
|
||||
output_->write_string(utils::string::va("sub_%s\n", func->name.data()));
|
||||
|
||||
for (const auto& inst : func->instructions)
|
||||
{
|
||||
const auto itr = func->labels.find(inst->index);
|
||||
|
||||
if (itr != func->labels.end())
|
||||
{
|
||||
output_->write_string(utils::string::va("\t%s\n", itr->second.data()));
|
||||
}
|
||||
|
||||
print_instruction(inst);
|
||||
}
|
||||
|
||||
output_->write_string(utils::string::va("end_%s\n", func->name.data()));
|
||||
}
|
||||
|
||||
void disassembler::print_instruction(const instruction::ptr& inst)
|
||||
{
|
||||
output_->write_string(utils::string::va("\t\t%s", resolver::opcode_name(inst->opcode).data()));
|
||||
|
||||
switch (static_cast<opcode>(inst->opcode))
|
||||
{
|
||||
case opcode::OP_GetLocalFunction:
|
||||
case opcode::OP_ScriptLocalFunctionCall:
|
||||
case opcode::OP_ScriptLocalFunctionCall2:
|
||||
case opcode::OP_ScriptLocalMethodCall:
|
||||
output_->write_string(utils::string::va(" sub_%s", inst->data[0].data()));
|
||||
break;
|
||||
case opcode::OP_ScriptLocalThreadCall:
|
||||
case opcode::OP_ScriptLocalChildThreadCall:
|
||||
case opcode::OP_ScriptLocalMethodThreadCall:
|
||||
case opcode::OP_ScriptLocalMethodChildThreadCall:
|
||||
output_->write_string(utils::string::va(" sub_%s %s\n", inst->data[0].data(), inst->data[1].data()));
|
||||
break;
|
||||
case opcode::OP_endswitch:
|
||||
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:
|
||||
for (auto& data : inst->data)
|
||||
{
|
||||
output_->write_string(utils::string::va(" %s", data.data()));
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
output_->write_string("\n");
|
||||
}
|
||||
|
||||
} // namespace xsk::gsc::iw6c
|
@ -1,42 +0,0 @@
|
||||
// Copyright 2022 xensik. All rights reserved.
|
||||
//
|
||||
// Use of this source code is governed by a GNU GPLv3 license
|
||||
// that can be found in the LICENSE file.
|
||||
|
||||
#pragma once
|
||||
|
||||
namespace xsk::gsc::iw6c
|
||||
{
|
||||
|
||||
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<function::ptr> functions_;
|
||||
std::unordered_map<std::uint32_t, std::string> labels_;
|
||||
|
||||
public:
|
||||
auto output() -> std::vector<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 function::ptr& func);
|
||||
void dissasemble_instruction(const instruction::ptr& inst);
|
||||
void disassemble_builtin_call(const instruction::ptr& inst, bool method, bool args);
|
||||
void disassemble_local_call(const instruction::ptr& inst, bool thread);
|
||||
void disassemble_far_call(const instruction::ptr& inst, bool thread);
|
||||
void disassemble_switch(const instruction::ptr& inst);
|
||||
void disassemble_end_switch(const instruction::ptr& inst);
|
||||
void disassemble_field_variable(const instruction::ptr& inst);
|
||||
void disassemble_jump(const instruction::ptr& inst, bool expr, bool back);
|
||||
auto disassemble_offset() -> std::int32_t;
|
||||
void resolve_local_functions();
|
||||
auto resolve_function(const std::string& index) -> std::string;
|
||||
void print_function(const function::ptr& func);
|
||||
void print_instruction(const instruction::ptr& inst);
|
||||
};
|
||||
|
||||
} // namespace xsk::gsc::iw6c
|
@ -1,180 +0,0 @@
|
||||
// Copyright 2022 xensik. All rights reserved.
|
||||
//
|
||||
// Use of this source code is governed by a GNU GPLv3 license
|
||||
// that can be found in the LICENSE file.
|
||||
|
||||
#include "stdafx.hpp"
|
||||
#include "iw6c.hpp"
|
||||
|
||||
namespace xsk::gsc::iw6c
|
||||
{
|
||||
|
||||
auto opcode_size(std::uint8_t id) -> std::uint32_t
|
||||
{
|
||||
switch (static_cast<opcode>(id))
|
||||
{
|
||||
case opcode::OP_End:
|
||||
case opcode::OP_Return:
|
||||
case opcode::OP_GetUndefined:
|
||||
case opcode::OP_GetZero:
|
||||
case opcode::OP_waittillFrameEnd:
|
||||
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_EvalArray:
|
||||
case opcode::OP_EvalArrayRef:
|
||||
case opcode::OP_EvalLocalArrayRefCached0:
|
||||
case opcode::OP_ClearArray:
|
||||
case opcode::OP_EmptyArray:
|
||||
case opcode::OP_AddArray:
|
||||
case opcode::OP_PreScriptCall:
|
||||
case opcode::OP_ScriptFunctionCallPointer:
|
||||
case opcode::OP_ScriptMethodCallPointer:
|
||||
case opcode::OP_GetLevelObject:
|
||||
case opcode::OP_GetAnimObject:
|
||||
case opcode::OP_GetSelf:
|
||||
case opcode::OP_GetThisthread:
|
||||
case opcode::OP_GetLevel:
|
||||
case opcode::OP_GetGame:
|
||||
case opcode::OP_GetAnim:
|
||||
case opcode::OP_GetGameRef:
|
||||
case opcode::OP_inc:
|
||||
case opcode::OP_dec:
|
||||
case opcode::OP_bit_or:
|
||||
case opcode::OP_bit_ex_or:
|
||||
case opcode::OP_bit_and:
|
||||
case opcode::OP_equality:
|
||||
case opcode::OP_inequality:
|
||||
case opcode::OP_less:
|
||||
case opcode::OP_greater:
|
||||
case opcode::OP_less_equal:
|
||||
case opcode::OP_waittillmatch2:
|
||||
case opcode::OP_waittill:
|
||||
case opcode::OP_notify:
|
||||
case opcode::OP_endon:
|
||||
case opcode::OP_voidCodepos:
|
||||
case opcode::OP_vector:
|
||||
case opcode::OP_greater_equal:
|
||||
case opcode::OP_shift_left:
|
||||
case opcode::OP_shift_right:
|
||||
case opcode::OP_plus:
|
||||
case opcode::OP_minus:
|
||||
case opcode::OP_multiply:
|
||||
case opcode::OP_divide:
|
||||
case opcode::OP_mod:
|
||||
case opcode::OP_size:
|
||||
case opcode::OP_GetSelfObject:
|
||||
case opcode::OP_SafeSetVariableFieldCached0:
|
||||
case opcode::OP_clearparams:
|
||||
case opcode::OP_checkclearparams:
|
||||
case opcode::OP_EvalLocalVariableRefCached0:
|
||||
// case opcode::OP_EvalNewLocalVariableRefCached0:
|
||||
case opcode::OP_SetVariableField:
|
||||
// case opcode::OP_ClearVariableField:
|
||||
case opcode::OP_SetLocalVariableFieldCached0:
|
||||
case opcode::OP_ClearLocalVariableFieldCached0:
|
||||
case opcode::OP_wait:
|
||||
case opcode::OP_DecTop:
|
||||
case opcode::OP_CastFieldObject:
|
||||
case opcode::OP_CastBool:
|
||||
case opcode::OP_BoolNot:
|
||||
case opcode::OP_BoolComplement:
|
||||
return 1;
|
||||
case opcode::OP_GetByte:
|
||||
case opcode::OP_GetNegByte:
|
||||
case opcode::OP_CreateLocalVariable:
|
||||
case opcode::OP_RemoveLocalVariables:
|
||||
case opcode::OP_EvalLocalVariableCached:
|
||||
case opcode::OP_EvalLocalArrayCached:
|
||||
case opcode::OP_EvalNewLocalArrayRefCached0:
|
||||
case opcode::OP_EvalLocalArrayRefCached:
|
||||
case opcode::OP_ScriptThreadCallPointer:
|
||||
case opcode::OP_ScriptChildThreadCallPointer:
|
||||
case opcode::OP_ScriptMethodThreadCallPointer:
|
||||
case opcode::OP_ScriptMethodChildThreadCallPointer:
|
||||
case opcode::OP_CallBuiltinPointer:
|
||||
case opcode::OP_CallBuiltinMethodPointer:
|
||||
case opcode::OP_waittillmatch:
|
||||
case opcode::OP_SafeCreateVariableFieldCached:
|
||||
case opcode::OP_SafeSetVariableFieldCached:
|
||||
case opcode::OP_SafeSetWaittillVariableFieldCached:
|
||||
case opcode::OP_GetAnimTree:
|
||||
case opcode::OP_EvalLocalVariableRefCached:
|
||||
case opcode::OP_SetNewLocalVariableFieldCached0:
|
||||
case opcode::OP_SetLocalVariableFieldCached:
|
||||
case opcode::OP_ClearLocalVariableFieldCached:
|
||||
case opcode::OP_EvalLocalVariableObjectCached:
|
||||
return 2;
|
||||
case opcode::OP_GetUnsignedShort:
|
||||
case opcode::OP_GetNegUnsignedShort:
|
||||
case opcode::OP_GetBuiltinFunction:
|
||||
case opcode::OP_GetBuiltinMethod:
|
||||
case opcode::OP_GetString:
|
||||
case opcode::OP_GetIString:
|
||||
case opcode::OP_JumpOnFalseExpr:
|
||||
case opcode::OP_JumpOnTrueExpr:
|
||||
case opcode::OP_jumpback:
|
||||
case opcode::OP_endswitch:
|
||||
case opcode::OP_JumpOnFalse:
|
||||
case opcode::OP_JumpOnTrue:
|
||||
case opcode::OP_EvalLevelFieldVariable:
|
||||
case opcode::OP_EvalAnimFieldVariable:
|
||||
case opcode::OP_EvalSelfFieldVariable:
|
||||
case opcode::OP_EvalFieldVariable:
|
||||
case opcode::OP_EvalLevelFieldVariableRef:
|
||||
case opcode::OP_EvalAnimFieldVariableRef:
|
||||
case opcode::OP_EvalSelfFieldVariableRef:
|
||||
case opcode::OP_EvalFieldVariableRef:
|
||||
case opcode::OP_ClearFieldVariable:
|
||||
case opcode::OP_SetLevelFieldVariableField:
|
||||
case opcode::OP_SetAnimFieldVariableField:
|
||||
case opcode::OP_SetSelfFieldVariableField:
|
||||
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_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_ScriptLocalFunctionCall2:
|
||||
case opcode::OP_ScriptLocalFunctionCall:
|
||||
case opcode::OP_ScriptLocalMethodCall:
|
||||
case opcode::OP_GetLocalFunction:
|
||||
case opcode::OP_CallBuiltin:
|
||||
case opcode::OP_CallBuiltinMethod:
|
||||
case opcode::OP_ScriptFarFunctionCall2:
|
||||
case opcode::OP_ScriptFarFunctionCall:
|
||||
case opcode::OP_ScriptFarMethodCall:
|
||||
case opcode::OP_GetFarFunction:
|
||||
return 4;
|
||||
case opcode::OP_GetInteger:
|
||||
case opcode::OP_GetFloat:
|
||||
case opcode::OP_ScriptLocalThreadCall:
|
||||
case opcode::OP_ScriptLocalChildThreadCall:
|
||||
case opcode::OP_ScriptLocalMethodThreadCall:
|
||||
case opcode::OP_ScriptLocalMethodChildThreadCall:
|
||||
case opcode::OP_ScriptFarThreadCall:
|
||||
case opcode::OP_ScriptFarChildThreadCall:
|
||||
case opcode::OP_ScriptFarMethodThreadCall:
|
||||
case opcode::OP_ScriptFarMethodChildThreadCall:
|
||||
case opcode::OP_GetAnimation:
|
||||
case opcode::OP_switch:
|
||||
case opcode::OP_jump:
|
||||
return 5;
|
||||
case opcode::OP_GetVector:
|
||||
return 13;
|
||||
default:
|
||||
throw error("couldn't resolve instruction size for " + std::to_string(id));
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace xsk::gsc::iw6c
|
@ -1,183 +0,0 @@
|
||||
// Copyright 2022 xensik. All rights reserved.
|
||||
//
|
||||
// Use of this source code is governed by a GNU GPLv3 license
|
||||
// that can be found in the LICENSE file.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "utils/xsk/utils.hpp"
|
||||
|
||||
#include "assembler.hpp"
|
||||
#include "disassembler.hpp"
|
||||
#include "compiler.hpp"
|
||||
#include "decompiler.hpp"
|
||||
#include "resolver.hpp"
|
||||
#include "context.hpp"
|
||||
|
||||
namespace xsk::gsc::iw6c
|
||||
{
|
||||
|
||||
constexpr std::uint16_t max_string_id = 0x95A1;
|
||||
// ps3 0x95A1
|
||||
// 360 0x8EFA
|
||||
|
||||
enum class opcode : std::uint8_t
|
||||
{
|
||||
OP_CastFieldObject = 0x1D,
|
||||
OP_SetLocalVariableFieldCached = 0x1E,
|
||||
OP_plus = 0x1F,
|
||||
OP_RemoveLocalVariables = 0x20,
|
||||
OP_EvalSelfFieldVariableRef = 0x21,
|
||||
OP_ScriptFarMethodChildThreadCall = 0x22,
|
||||
OP_GetGameRef = 0x23,
|
||||
OP_EvalAnimFieldVariable = 0x24,
|
||||
OP_EvalLevelFieldVariableRef = 0x25,
|
||||
OP_GetThisthread = 0x26,
|
||||
OP_greater = 0x27,
|
||||
OP_waittillmatch = 0x28,
|
||||
OP_shift_right = 0x29,
|
||||
OP_dec = 0x2A,
|
||||
OP_JumpOnTrue = 0x2B,
|
||||
OP_bit_or = 0x2C,
|
||||
OP_equality = 0x2D,
|
||||
OP_ClearLocalVariableFieldCached0 = 0x2E,
|
||||
OP_notify = 0x2F,
|
||||
OP_GetVector = 0x30,
|
||||
OP_ScriptMethodChildThreadCallPointer = 0x31,
|
||||
OP_PreScriptCall = 0x32,
|
||||
OP_GetByte = 0x33,
|
||||
OP_ScriptFarThreadCall = 0x34,
|
||||
OP_SetSelfFieldVariableField = 0x35,
|
||||
OP_JumpOnFalseExpr = 0x36,
|
||||
OP_GetUndefined = 0x37,
|
||||
OP_jumpback = 0x38,
|
||||
OP_JumpOnTrueExpr = 0x39,
|
||||
OP_CallBuiltin0 = 0x3A,
|
||||
OP_CallBuiltin1 = 0x3B,
|
||||
OP_CallBuiltin2 = 0x3C,
|
||||
OP_CallBuiltin3 = 0x3D,
|
||||
OP_CallBuiltin4 = 0x3E,
|
||||
OP_CallBuiltin5 = 0x3F,
|
||||
OP_CallBuiltin = 0x40,
|
||||
OP_SetLocalVariableFieldCached0 = 0x41,
|
||||
OP_ClearFieldVariable = 0x42,
|
||||
OP_GetLevel = 0x43,
|
||||
OP_size = 0x44,
|
||||
OP_SafeSetWaittillVariableFieldCached = 0x45,
|
||||
OP_ScriptLocalMethodThreadCall = 0x46,
|
||||
OP_AddArray = 0x47,
|
||||
OP_endon = 0x48,
|
||||
OP_EvalFieldVariable = 0x49,
|
||||
OP_shift_left = 0x4A,
|
||||
OP_EvalLocalArrayRefCached0 = 0x4B,
|
||||
OP_Return = 0x4C,
|
||||
OP_CreateLocalVariable = 0x4D,
|
||||
OP_SafeSetVariableFieldCached0 = 0x4E,
|
||||
OP_GetBuiltinMethod = 0x4F,
|
||||
OP_ScriptLocalMethodCall = 0x50,
|
||||
OP_CallBuiltinMethodPointer = 0x51,
|
||||
OP_ScriptLocalChildThreadCall = 0x52,
|
||||
OP_GetSelfObject = 0x53,
|
||||
OP_GetGame = 0x54,
|
||||
OP_SetLevelFieldVariableField = 0x55,
|
||||
OP_EvalArray = 0x56,
|
||||
OP_GetSelf = 0x57,
|
||||
OP_End = 0x58,
|
||||
OP_EvalSelfFieldVariable = 0x59,
|
||||
OP_less_equal = 0x5A,
|
||||
OP_EvalLocalVariableCached0 = 0x5B,
|
||||
OP_EvalLocalVariableCached1 = 0x5C,
|
||||
OP_EvalLocalVariableCached2 = 0x5D,
|
||||
OP_EvalLocalVariableCached3 = 0x5E,
|
||||
OP_EvalLocalVariableCached4 = 0x5F,
|
||||
OP_EvalLocalVariableCached5 = 0x60,
|
||||
OP_EvalLocalVariableCached = 0x61,
|
||||
OP_EvalNewLocalArrayRefCached0 = 0x62,
|
||||
OP_ScriptChildThreadCallPointer = 0x63,
|
||||
OP_EvalLocalVariableObjectCached = 0x64,
|
||||
OP_ScriptLocalThreadCall = 0x65,
|
||||
OP_GetInteger = 0x66,
|
||||
OP_ScriptMethodCallPointer = 0x67,
|
||||
OP_checkclearparams = 0x68,
|
||||
OP_SetAnimFieldVariableField = 0x69,
|
||||
OP_waittillmatch2 = 0x6A,
|
||||
OP_minus = 0x6B,
|
||||
OP_ScriptLocalFunctionCall2 = 0x6C,
|
||||
OP_GetNegUnsignedShort = 0x6D,
|
||||
OP_GetNegByte = 0x6E,
|
||||
OP_SafeCreateVariableFieldCached = 0x6F,
|
||||
OP_greater_equal = 0x70,
|
||||
OP_vector = 0x71,
|
||||
OP_GetBuiltinFunction = 0x72,
|
||||
OP_endswitch = 0x73,
|
||||
OP_ClearArray = 0x74,
|
||||
OP_DecTop = 0x75,
|
||||
OP_CastBool = 0x76,
|
||||
OP_EvalArrayRef = 0x77,
|
||||
OP_SetNewLocalVariableFieldCached0 = 0x78,
|
||||
OP_GetZero = 0x79,
|
||||
OP_wait = 0x7A,
|
||||
OP_waittill = 0x7B,
|
||||
OP_GetIString = 0x7C,
|
||||
OP_ScriptFarFunctionCall = 0x7D,
|
||||
OP_GetAnimObject = 0x7E,
|
||||
OP_GetAnimTree = 0x7F,
|
||||
OP_EvalLocalArrayCached = 0x80,
|
||||
OP_mod = 0x81,
|
||||
OP_ScriptFarMethodThreadCall = 0x82,
|
||||
OP_GetUnsignedShort = 0x83,
|
||||
OP_clearparams = 0x84,
|
||||
OP_ScriptMethodThreadCallPointer = 0x85,
|
||||
OP_ScriptFunctionCallPointer = 0x86,
|
||||
OP_EmptyArray = 0x87,
|
||||
OP_SafeSetVariableFieldCached = 0x88,
|
||||
// ---- = 0x89,
|
||||
OP_EvalFieldVariableRef = 0x8A,
|
||||
OP_ScriptLocalMethodChildThreadCall = 0x8B,
|
||||
// ---- = 0x8C,
|
||||
OP_GetFloat = 0x8D,
|
||||
OP_EvalLocalVariableRefCached = 0x8E,
|
||||
OP_JumpOnFalse = 0x8F,
|
||||
OP_BoolComplement = 0x90,
|
||||
OP_ScriptThreadCallPointer = 0x91,
|
||||
OP_ScriptFarFunctionCall2 = 0x92,
|
||||
OP_less = 0x93,
|
||||
OP_BoolNot = 0x94,
|
||||
OP_waittillFrameEnd = 0x95,
|
||||
OP_GetString = 0x96,
|
||||
OP_EvalLevelFieldVariable = 0x97,
|
||||
OP_GetLevelObject = 0x98,
|
||||
OP_inc = 0x99,
|
||||
OP_CallBuiltinMethod0 = 0x9A,
|
||||
OP_CallBuiltinMethod1 = 0x9B,
|
||||
OP_CallBuiltinMethod2 = 0x9C,
|
||||
OP_CallBuiltinMethod3 = 0x9D,
|
||||
OP_CallBuiltinMethod4 = 0x9E,
|
||||
OP_CallBuiltinMethod5 = 0x9F,
|
||||
OP_CallBuiltinMethod = 0xA0,
|
||||
OP_GetAnim = 0xA1,
|
||||
OP_switch = 0xA2,
|
||||
OP_SetVariableField = 0xA3,
|
||||
OP_divide = 0xA4,
|
||||
OP_GetLocalFunction = 0xA5,
|
||||
OP_ScriptFarChildThreadCall = 0xA6,
|
||||
OP_multiply = 0xA7,
|
||||
OP_ClearLocalVariableFieldCached = 0xA8,
|
||||
OP_EvalAnimFieldVariableRef = 0xA9,
|
||||
OP_EvalLocalArrayRefCached = 0xAA,
|
||||
OP_EvalLocalVariableRefCached0 = 0xAB,
|
||||
OP_bit_and = 0xAC,
|
||||
OP_GetAnimation = 0xAD,
|
||||
OP_GetFarFunction = 0xAE,
|
||||
OP_CallBuiltinPointer = 0xAF,
|
||||
OP_jump = 0xB0,
|
||||
OP_voidCodepos = 0xB1,
|
||||
OP_ScriptFarMethodCall = 0xB2,
|
||||
OP_inequality = 0xB3,
|
||||
OP_ScriptLocalFunctionCall = 0xB4,
|
||||
OP_bit_ex_or = 0xB5,
|
||||
};
|
||||
|
||||
auto opcode_size(std::uint8_t id) -> std::uint32_t;
|
||||
|
||||
} // namespace xsk::gsc::iw6c
|
@ -1,848 +0,0 @@
|
||||
// Copyright 2022 xensik. All rights reserved.
|
||||
//
|
||||
// Use of this source code is governed by a GNU GPLv3 license
|
||||
// that can be found in the LICENSE file.
|
||||
|
||||
#include "stdafx.hpp"
|
||||
#include "iw6c.hpp"
|
||||
#include "parser.hpp"
|
||||
#include "lexer.hpp"
|
||||
|
||||
xsk::gsc::iw6c::parser::symbol_type IW6Clex(xsk::gsc::iw6c::lexer& lexer)
|
||||
{
|
||||
return lexer.lex();
|
||||
}
|
||||
|
||||
namespace xsk::gsc::iw6c
|
||||
{
|
||||
|
||||
const std::unordered_map<std::string_view, parser::token::token_kind_type> keyword_map
|
||||
{{
|
||||
{ "#define", parser::token::SH_DEFINE },
|
||||
{ "#undef", parser::token::SH_UNDEF },
|
||||
{ "#ifdef", parser::token::SH_IFDEF },
|
||||
{ "#ifndef", parser::token::SH_IFNDEF },
|
||||
{ "#if", parser::token::SH_IF },
|
||||
{ "#elif", parser::token::SH_ELIF },
|
||||
{ "#else", parser::token::SH_ELSE },
|
||||
{ "#endif", parser::token::SH_ENDIF },
|
||||
{ "#inline", parser::token::INLINE },
|
||||
{ "#include", parser::token::INCLUDE },
|
||||
{ "#using_animtree", parser::token::USINGTREE },
|
||||
{ "#animtree", parser::token::ANIMTREE },
|
||||
{ "endon", parser::token::ENDON },
|
||||
{ "notify", parser::token::NOTIFY },
|
||||
{ "wait", parser::token::WAIT },
|
||||
{ "waittill", parser::token::WAITTILL },
|
||||
{ "waittillmatch", parser::token::WAITTILLMATCH },
|
||||
{ "waittillframeend", parser::token::WAITTILLFRAMEEND },
|
||||
{ "if", parser::token::IF },
|
||||
{ "else", parser::token::ELSE },
|
||||
{ "do", parser::token::DO },
|
||||
{ "while", parser::token::WHILE },
|
||||
{ "for", parser::token::FOR },
|
||||
{ "foreach", parser::token::FOREACH },
|
||||
{ "in", parser::token::IN },
|
||||
{ "switch", parser::token::SWITCH },
|
||||
{ "case", parser::token::CASE },
|
||||
{ "default", parser::token::DEFAULT },
|
||||
{ "break", parser::token::BREAK },
|
||||
{ "continue", parser::token::CONTINUE },
|
||||
{ "return", parser::token::RETURN },
|
||||
{ "breakpoint", parser::token::BREAKPOINT },
|
||||
{ "prof_begin", parser::token::PROFBEGIN },
|
||||
{ "prof_end", parser::token::PROFEND },
|
||||
{ "thread", parser::token::THREAD },
|
||||
{ "childthread", parser::token::CHILDTHREAD },
|
||||
{ "thisthread", parser::token::THISTHREAD },
|
||||
{ "call", parser::token::CALL },
|
||||
{ "true", parser::token::TRUE },
|
||||
{ "false", parser::token::FALSE },
|
||||
{ "undefined", parser::token::UNDEFINED },
|
||||
{ "size", parser::token::SIZE },
|
||||
{ "game", parser::token::GAME },
|
||||
{ "self", parser::token::SELF },
|
||||
{ "anim", parser::token::ANIM },
|
||||
{ "level", parser::token::LEVEL },
|
||||
}};
|
||||
|
||||
buffer::buffer() : length(0)
|
||||
{
|
||||
data = static_cast<char*>(std::malloc(max_buf_size));
|
||||
}
|
||||
|
||||
buffer::~buffer()
|
||||
{
|
||||
if (data) std::free(data);
|
||||
}
|
||||
|
||||
bool buffer::push(char c)
|
||||
{
|
||||
if (length >= max_buf_size)
|
||||
return false;
|
||||
|
||||
data[length++] = c;
|
||||
return true;
|
||||
}
|
||||
|
||||
reader::reader() : buffer_pos(0), bytes_remaining(0), last_byte(0), current_byte(0), state(reader::end)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
void reader::init(const char* data, size_t size)
|
||||
{
|
||||
if (data && size)
|
||||
{
|
||||
state = reader::ok;
|
||||
buffer_pos = data;
|
||||
bytes_remaining = static_cast<std::uint32_t>(size);
|
||||
last_byte = 0;
|
||||
current_byte = *data;
|
||||
}
|
||||
else
|
||||
{
|
||||
state = reader::end;
|
||||
buffer_pos = 0;
|
||||
bytes_remaining = 0;
|
||||
last_byte = 0;
|
||||
current_byte = 0;
|
||||
}
|
||||
}
|
||||
|
||||
void reader::advance()
|
||||
{
|
||||
++buffer_pos;
|
||||
|
||||
if (bytes_remaining-- == 1)
|
||||
{
|
||||
state = reader::end;
|
||||
bytes_remaining = 0;
|
||||
last_byte = current_byte;
|
||||
current_byte = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
last_byte = current_byte;
|
||||
current_byte = *buffer_pos;
|
||||
}
|
||||
}
|
||||
|
||||
lexer::lexer(build mode, const std::string& name, const char* data, size_t size) : loc_(location(&name)),
|
||||
locs_(std::stack<location>()), readers_(std::stack<reader>()), header_top_(0), mode_(mode), indev_(false), clean_(true)
|
||||
{
|
||||
reader_.init(data, size);
|
||||
}
|
||||
|
||||
void lexer::push_header(const std::string& file)
|
||||
{
|
||||
try
|
||||
{
|
||||
if (header_top_++ >= 10)
|
||||
throw comp_error(loc_, "maximum gsh depth exceeded '10'");
|
||||
|
||||
auto data = resolver::file_data(file + ".gsh");
|
||||
|
||||
readers_.push(reader_);
|
||||
locs_.push(loc_);
|
||||
loc_.initialize(std::get<0>(data));
|
||||
reader_.init(std::get<1>(data), std::get<2>(data));
|
||||
clean_ = true;
|
||||
}
|
||||
catch (const std::exception& e)
|
||||
{
|
||||
throw error("parsing header file '" + file + "': " + e.what());
|
||||
}
|
||||
}
|
||||
|
||||
void lexer::pop_header()
|
||||
{
|
||||
header_top_--;
|
||||
loc_ = locs_.top();
|
||||
locs_.pop();
|
||||
reader_ = readers_.top();
|
||||
readers_.pop();
|
||||
}
|
||||
|
||||
void lexer::ban_header(const location& loc)
|
||||
{
|
||||
if (header_top_ > 0)
|
||||
{
|
||||
throw comp_error(loc, "not allowed inside a gsh file");
|
||||
}
|
||||
}
|
||||
|
||||
auto lexer::lex() -> parser::symbol_type
|
||||
{
|
||||
buffer_.length = 0;
|
||||
state_ = state::start;
|
||||
|
||||
while (true)
|
||||
{
|
||||
const auto& state = reader_.state;
|
||||
auto& last = reader_.last_byte;
|
||||
auto& curr = reader_.current_byte;
|
||||
auto path = false;
|
||||
loc_.step();
|
||||
|
||||
if (state == reader::end)
|
||||
{
|
||||
if (indev_)
|
||||
throw comp_error(loc_, "unmatched devblock start ('/#')");
|
||||
|
||||
if (header_top_ > 0)
|
||||
pop_header();
|
||||
else
|
||||
return parser::make_IW6CEOF(loc_);
|
||||
}
|
||||
|
||||
if (clean_ && last != 0 && last != ' ' && last != '\t' && last != '\n')
|
||||
clean_ = false;
|
||||
|
||||
advance();
|
||||
|
||||
switch (last)
|
||||
{
|
||||
case ' ':
|
||||
case '\t':
|
||||
case '\r':
|
||||
loc_.step();
|
||||
continue;
|
||||
case '\n':
|
||||
loc_.lines();
|
||||
loc_.step();
|
||||
clean_ = true;
|
||||
continue;
|
||||
case '\\':
|
||||
throw comp_error(loc_, "invalid token ('\\')");
|
||||
case '/':
|
||||
if (curr != '=' && curr != '#' && curr != '@' && curr != '*' && curr != '/')
|
||||
return parser::make_DIV(loc_);
|
||||
|
||||
advance();
|
||||
|
||||
if (last == '=')
|
||||
return parser::make_ASSIGN_DIV(loc_);
|
||||
|
||||
if (last == '#')
|
||||
{
|
||||
if (indev_)
|
||||
throw comp_error(loc_, "cannot recurse devblock ('/#')");
|
||||
|
||||
if (mode_ == build::dev)
|
||||
{
|
||||
indev_ = true;
|
||||
return parser::make_DEVBEGIN(loc_);
|
||||
}
|
||||
else
|
||||
{
|
||||
while (true)
|
||||
{
|
||||
if (state == reader::end)
|
||||
throw comp_error(loc_, "unmatched devblock start ('/#')");
|
||||
|
||||
if (curr == '\n')
|
||||
{
|
||||
loc_.lines();
|
||||
loc_.step();
|
||||
}
|
||||
else if (last == '#' && curr == '/')
|
||||
{
|
||||
advance();
|
||||
break;
|
||||
}
|
||||
|
||||
advance();
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (last == '@')
|
||||
{
|
||||
while (true)
|
||||
{
|
||||
if (state == reader::end)
|
||||
throw comp_error(loc_, "unmatched script doc comment start ('/@')");
|
||||
|
||||
if (curr == '\n')
|
||||
{
|
||||
loc_.lines();
|
||||
loc_.step();
|
||||
}
|
||||
else if (last == '@' && curr == '/')
|
||||
{
|
||||
advance();
|
||||
break;
|
||||
}
|
||||
|
||||
advance();
|
||||
}
|
||||
}
|
||||
else if (last == '*')
|
||||
{
|
||||
while (true)
|
||||
{
|
||||
if (state == reader::end)
|
||||
throw comp_error(loc_, "unmatched multiline comment start ('/*')");
|
||||
|
||||
if (curr == '\n')
|
||||
{
|
||||
loc_.lines();
|
||||
loc_.step();
|
||||
}
|
||||
else if (last == '*' && curr == '/')
|
||||
{
|
||||
advance();
|
||||
break;
|
||||
}
|
||||
|
||||
advance();
|
||||
}
|
||||
}
|
||||
else if (last == '/')
|
||||
{
|
||||
while (true)
|
||||
{
|
||||
if (state == reader::end)
|
||||
break;
|
||||
|
||||
if (curr == '\n')
|
||||
break;
|
||||
|
||||
advance();
|
||||
}
|
||||
}
|
||||
continue;
|
||||
case '#':
|
||||
if (curr == '/')
|
||||
{
|
||||
if (!indev_)
|
||||
throw comp_error(loc_, "unmatched devblock end ('#/')");
|
||||
|
||||
advance();
|
||||
indev_ = false;
|
||||
return parser::make_DEVEND(loc_);
|
||||
}
|
||||
|
||||
buffer_.push(last);
|
||||
advance();
|
||||
|
||||
while (state == reader::ok)
|
||||
{
|
||||
if (last != ' ' || last != '\t')
|
||||
break;
|
||||
|
||||
advance();
|
||||
}
|
||||
|
||||
if (state == reader::end || !((last > 64 && last < 91) || (last > 96 && last < 123)))
|
||||
throw comp_error(loc_, "invalid preprocessor directive ('#')");
|
||||
|
||||
state_ = state::preprocessor;
|
||||
goto lex_name;
|
||||
case '*':
|
||||
if (curr != '=' && curr != '/')
|
||||
return parser::make_MUL(loc_);
|
||||
|
||||
advance();
|
||||
|
||||
if (last == '=')
|
||||
return parser::make_ASSIGN_MUL(loc_);
|
||||
|
||||
throw comp_error(loc_, "unmatched multiline comment end ('*/')");
|
||||
case '"':
|
||||
state_ = state::string;
|
||||
goto lex_string;
|
||||
case '.':
|
||||
if (curr < '0' || curr > '9')
|
||||
return parser::make_DOT(loc_);
|
||||
goto lex_number;
|
||||
case '(':
|
||||
return parser::make_LPAREN(loc_);
|
||||
case ')':
|
||||
return parser::make_RPAREN(loc_);
|
||||
case '{':
|
||||
return parser::make_LBRACE(loc_);
|
||||
case '}':
|
||||
return parser::make_RBRACE(loc_);
|
||||
case '[':
|
||||
return parser::make_LBRACKET(loc_);
|
||||
case ']':
|
||||
return parser::make_RBRACKET(loc_);
|
||||
case ',':
|
||||
return parser::make_COMMA(loc_);
|
||||
case ';':
|
||||
return parser::make_SEMICOLON(loc_);
|
||||
case ':':
|
||||
if (curr != ':')
|
||||
return parser::make_COLON(loc_);
|
||||
|
||||
advance();
|
||||
return parser::make_DOUBLECOLON(loc_);
|
||||
case '?':
|
||||
return parser::make_QMARK(loc_);
|
||||
case '=':
|
||||
if (curr != '=')
|
||||
return parser::make_ASSIGN(loc_);
|
||||
|
||||
advance();
|
||||
return parser::make_EQUALITY(loc_);
|
||||
case '+':
|
||||
if (curr != '+' && curr != '=')
|
||||
return parser::make_ADD(loc_);
|
||||
|
||||
advance();
|
||||
|
||||
if (last == '+')
|
||||
return parser::make_INCREMENT(loc_);
|
||||
|
||||
return parser::make_ASSIGN_ADD(loc_);
|
||||
case '-':
|
||||
if (curr != '-' && curr != '=')
|
||||
return parser::make_SUB(loc_);
|
||||
|
||||
advance();
|
||||
|
||||
if (last == '-')
|
||||
return parser::make_DECREMENT(loc_);
|
||||
|
||||
return parser::make_ASSIGN_SUB(loc_);
|
||||
case '%':
|
||||
if (curr != '=')
|
||||
return parser::make_MOD(loc_);
|
||||
|
||||
advance();
|
||||
|
||||
return parser::make_ASSIGN_MOD(loc_);
|
||||
case '|':
|
||||
if (curr != '|' && curr != '=')
|
||||
return parser::make_BITWISE_OR(loc_);
|
||||
|
||||
advance();
|
||||
|
||||
if (last == '|')
|
||||
return parser::make_OR(loc_);
|
||||
|
||||
return parser::make_ASSIGN_BW_OR(loc_);
|
||||
case '&':
|
||||
if (curr != '&' && curr != '=' && curr != '"')
|
||||
return parser::make_BITWISE_AND(loc_);
|
||||
|
||||
advance();
|
||||
|
||||
if (last == '&')
|
||||
return parser::make_AND(loc_);
|
||||
|
||||
if (last == '=')
|
||||
return parser::make_ASSIGN_BW_AND(loc_);
|
||||
|
||||
state_ = state::localize;
|
||||
goto lex_string;
|
||||
case '^':
|
||||
if (curr != '=')
|
||||
return parser::make_BITWISE_EXOR(loc_);
|
||||
|
||||
advance();
|
||||
return parser::make_ASSIGN_BW_EXOR(loc_);
|
||||
case '!':
|
||||
if (curr != '=')
|
||||
return parser::make_NOT(loc_);
|
||||
|
||||
advance();
|
||||
return parser::make_INEQUALITY(loc_);
|
||||
case '~':
|
||||
return parser::make_COMPLEMENT(loc_);
|
||||
case '<':
|
||||
if (curr != '<' && curr != '=')
|
||||
return parser::make_LESS(loc_);
|
||||
|
||||
advance();
|
||||
if (last == '=')
|
||||
return parser::make_LESS_EQUAL(loc_);
|
||||
|
||||
if (curr != '=')
|
||||
return parser::make_LSHIFT(loc_);
|
||||
|
||||
advance();
|
||||
return parser::make_ASSIGN_LSHIFT(loc_);
|
||||
case '>':
|
||||
if (curr != '>' && curr != '=')
|
||||
return parser::make_GREATER(loc_);
|
||||
|
||||
advance();
|
||||
|
||||
if (last == '=')
|
||||
return parser::make_GREATER_EQUAL(loc_);
|
||||
|
||||
if (curr != '=')
|
||||
return parser::make_RSHIFT(loc_);
|
||||
|
||||
advance();
|
||||
return parser::make_ASSIGN_RSHIFT(loc_);
|
||||
default:
|
||||
if (last >= '0' && last <= '9')
|
||||
goto lex_number;
|
||||
else if (last == '_' || (last >= 'A' && last <= 'Z') || (last >= 'a' && last <= 'z'))
|
||||
goto lex_name;
|
||||
|
||||
throw comp_error(loc_, utils::string::va("bad token: \'%c\'", last));
|
||||
}
|
||||
|
||||
lex_string:
|
||||
while (true)
|
||||
{
|
||||
if (state == reader::end)
|
||||
throw comp_error(loc_, "unmatched string start ('\"')");
|
||||
|
||||
if (curr == '"')
|
||||
{
|
||||
advance();
|
||||
break;
|
||||
}
|
||||
|
||||
if (curr == '\n')
|
||||
throw comp_error(loc_, "unterminated string literal");
|
||||
|
||||
if (curr == '\\')
|
||||
{
|
||||
advance();
|
||||
|
||||
if (state == reader::end)
|
||||
throw comp_error(loc_, "invalid token ('\')");
|
||||
|
||||
char c = curr;
|
||||
switch (curr)
|
||||
{
|
||||
case 't': c = '\t'; break;
|
||||
case 'r': c = '\r'; break;
|
||||
case 'n': c = '\n'; break;
|
||||
case '"': c = '\"'; break;
|
||||
case '\\': c = '\\'; break;
|
||||
default: break;
|
||||
}
|
||||
|
||||
if (!buffer_.push(c))
|
||||
throw comp_error(loc_, "max string size exceeded");
|
||||
}
|
||||
else if (!buffer_.push(curr))
|
||||
throw comp_error(loc_, "max string size exceeded");
|
||||
|
||||
advance();
|
||||
}
|
||||
|
||||
if (state_ == state::localize)
|
||||
return parser::make_ISTRING(std::string(buffer_.data, buffer_.length), loc_);
|
||||
|
||||
return parser::make_STRING(std::string(buffer_.data, buffer_.length), loc_);
|
||||
|
||||
lex_name:
|
||||
buffer_.push(last);
|
||||
|
||||
while (true)
|
||||
{
|
||||
if (state == reader::end)
|
||||
break;
|
||||
|
||||
if (!(curr == '\\' || curr == '_' || (curr > 64 && curr < 91) || (curr > 96 && curr < 123) || (curr > 47 && curr < 58)))
|
||||
break;
|
||||
|
||||
if (curr == '\\')
|
||||
{
|
||||
if (last == '\\')
|
||||
throw comp_error(loc_, "invalid path '\\\\'");
|
||||
|
||||
path = true;
|
||||
if (!buffer_.push('/'))
|
||||
throw comp_error(loc_, "max string size exceeded");
|
||||
}
|
||||
else if (!buffer_.push(curr))
|
||||
throw comp_error(loc_, "max string size exceeded");
|
||||
|
||||
advance();
|
||||
}
|
||||
|
||||
if (state_ == state::preprocessor)
|
||||
{
|
||||
auto token = parser::token::IW6CUNDEF;
|
||||
|
||||
if (buffer_.length < 16)
|
||||
{
|
||||
const auto itr = keyword_map.find(std::string_view(buffer_.data, buffer_.length));
|
||||
|
||||
if (itr != keyword_map.end())
|
||||
{
|
||||
if (itr->second > parser::token::SH_ENDIF)
|
||||
return parser::symbol_type(itr->second, loc_);
|
||||
|
||||
token = itr->second;
|
||||
}
|
||||
}
|
||||
|
||||
preprocessor_run(token);
|
||||
|
||||
state_ = state::start;
|
||||
continue;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (buffer_.length < 17)
|
||||
{
|
||||
const auto itr = keyword_map.find(std::string_view(buffer_.data, buffer_.length));
|
||||
|
||||
if (itr != keyword_map.end())
|
||||
return parser::symbol_type(itr->second, loc_);
|
||||
}
|
||||
|
||||
if (path)
|
||||
{
|
||||
if (buffer_.data[buffer_.length - 1] == '/')
|
||||
throw comp_error(loc_, "invalid path end '\\'");
|
||||
|
||||
return parser::make_PATH(resolver::make_token(std::string_view(buffer_.data, buffer_.length)), loc_);
|
||||
}
|
||||
|
||||
return parser::make_IDENTIFIER(resolver::make_token(std::string_view(buffer_.data, buffer_.length)), loc_);
|
||||
}
|
||||
|
||||
lex_number:
|
||||
if (last == '.' || last != '0' || (last == '0' && (curr != 'o' && curr != 'b' && curr != 'x')))
|
||||
{
|
||||
buffer_.push(last);
|
||||
|
||||
auto dot = last == '.' ? 1 : 0;
|
||||
auto flt = 0;
|
||||
|
||||
while (true)
|
||||
{
|
||||
if (state == reader::end)
|
||||
break;
|
||||
|
||||
if (curr == '\'' && (last == '\'' || last == 'f' || last == '.'))
|
||||
throw comp_error(loc_, "invalid number literal");
|
||||
|
||||
if ((curr == '.' || curr == 'f') && last == '\'')
|
||||
throw comp_error(loc_, "invalid number literal");
|
||||
|
||||
if (curr == '\'')
|
||||
{
|
||||
advance();
|
||||
continue;
|
||||
}
|
||||
|
||||
if (curr == 'f')
|
||||
flt++;
|
||||
else if (curr == '.')
|
||||
dot++;
|
||||
else if (!(curr > 47 && curr < 58))
|
||||
break;
|
||||
|
||||
if (!buffer_.push(curr))
|
||||
throw comp_error(loc_, "number literal size exceeded");
|
||||
|
||||
advance();
|
||||
}
|
||||
|
||||
if (last == '\'')
|
||||
throw comp_error(loc_, "invalid number literal");
|
||||
|
||||
if (dot > 1 || flt > 1 || (flt && buffer_.data[buffer_.length - 1] != 'f'))
|
||||
throw comp_error(loc_, "invalid number literal");
|
||||
|
||||
if (dot || flt)
|
||||
return parser::make_FLOAT(std::string(buffer_.data, buffer_.length), loc_);
|
||||
|
||||
return parser::make_INTEGER(std::string(buffer_.data, buffer_.length), loc_);
|
||||
}
|
||||
else if (curr == 'o')
|
||||
{
|
||||
advance();
|
||||
|
||||
while (true)
|
||||
{
|
||||
if (state == reader::end)
|
||||
break;
|
||||
|
||||
if ((curr == '\'' && (last == '\'' || last == 'o')) || (curr == 'o' && last == '\''))
|
||||
throw comp_error(loc_, "invalid octal literal");
|
||||
|
||||
if (curr == '\'')
|
||||
{
|
||||
advance();
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!(curr > 47 && curr < 56))
|
||||
break;
|
||||
|
||||
if (!buffer_.push(curr))
|
||||
throw error("gsc lexer: out of memory!");
|
||||
|
||||
advance();
|
||||
}
|
||||
|
||||
if (last == '\'' || buffer_.length <= 0)
|
||||
throw comp_error(loc_, "invalid octal literal");
|
||||
|
||||
return parser::make_INTEGER(utils::string::oct_to_dec(buffer_.data), loc_);
|
||||
}
|
||||
else if (curr == 'b')
|
||||
{
|
||||
buffer_.push(last);
|
||||
buffer_.push(curr);
|
||||
advance();
|
||||
|
||||
while (true)
|
||||
{
|
||||
if (state == reader::end)
|
||||
break;
|
||||
|
||||
if ((curr == '\'' && (last == '\'' || last == 'b')) || (curr == 'b' && last == '\''))
|
||||
throw comp_error(loc_, "invalid binary literal");
|
||||
|
||||
if (curr == '\'')
|
||||
{
|
||||
advance();
|
||||
continue;
|
||||
}
|
||||
|
||||
if (curr != '0' && curr != '1')
|
||||
break;
|
||||
|
||||
if (!buffer_.push(curr))
|
||||
throw comp_error(loc_, "number literal size exceeded");
|
||||
|
||||
advance();
|
||||
}
|
||||
|
||||
if (last == '\'' || buffer_.length < 3)
|
||||
throw comp_error(loc_, "invalid binary literal");
|
||||
|
||||
return parser::make_INTEGER(utils::string::bin_to_dec(buffer_.data), loc_);
|
||||
}
|
||||
else if (curr == 'x')
|
||||
{
|
||||
buffer_.push(last);
|
||||
buffer_.push(curr);
|
||||
advance();
|
||||
|
||||
while (true)
|
||||
{
|
||||
if (state == reader::end)
|
||||
break;
|
||||
|
||||
if ((curr == '\'' && (last == '\'' || last == 'x')) || (curr == 'x' && last == '\''))
|
||||
throw comp_error(loc_, "invalid hexadecimal literal");
|
||||
|
||||
if (curr == '\'')
|
||||
{
|
||||
advance();
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!((curr > 47 && curr < 58) || (curr > 64 && curr < 71) || (curr > 96 && curr < 103)))
|
||||
break;
|
||||
|
||||
if (!buffer_.push(curr))
|
||||
throw error("gsc lexer: out of memory!");
|
||||
|
||||
advance();
|
||||
}
|
||||
|
||||
if (last == '\'' || buffer_.length < 3)
|
||||
throw comp_error(loc_, "invalid hexadecimal literal");
|
||||
|
||||
return parser::make_INTEGER(utils::string::hex_to_dec(buffer_.data), loc_);
|
||||
}
|
||||
|
||||
throw error("UNEXPECTED LEXER INTERNAL ERROR!");
|
||||
}
|
||||
}
|
||||
|
||||
void lexer::advance()
|
||||
{
|
||||
reader_.advance();
|
||||
loc_.end.column++;
|
||||
|
||||
if (reader_.current_byte == '\\') [[unlikely]]
|
||||
preprocessor_wrap();
|
||||
}
|
||||
|
||||
void lexer::preprocessor_wrap()
|
||||
{
|
||||
while (reader_.current_byte == '\\')
|
||||
{
|
||||
if (reader_.bytes_remaining == 1)
|
||||
throw comp_error(loc_, "invalid token ('\\')");
|
||||
|
||||
if (reader_.buffer_pos[1] != '\r' && reader_.buffer_pos[1] != '\n')
|
||||
break;
|
||||
|
||||
if (reader_.buffer_pos[1] == '\r')
|
||||
{
|
||||
if (reader_.bytes_remaining <= 3 || reader_.buffer_pos[2] != '\n')
|
||||
throw comp_error(loc_, "invalid token ('\\')");
|
||||
|
||||
reader_.buffer_pos += 3;
|
||||
reader_.bytes_remaining -= 3;
|
||||
}
|
||||
|
||||
if ((reader_.buffer_pos[1] == '\n'))
|
||||
{
|
||||
if (reader_.bytes_remaining == 2)
|
||||
throw comp_error(loc_, "invalid token ('\\')");
|
||||
|
||||
reader_.buffer_pos += 2;
|
||||
reader_.bytes_remaining -= 2;
|
||||
}
|
||||
|
||||
if (reader_.bytes_remaining == 0)
|
||||
{
|
||||
reader_.state = reader::end;
|
||||
reader_.current_byte = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
reader_.current_byte = *reader_.buffer_pos;
|
||||
}
|
||||
|
||||
loc_.lines();
|
||||
loc_.step();
|
||||
}
|
||||
}
|
||||
|
||||
void lexer::preprocessor_run(parser::token::token_kind_type token)
|
||||
{
|
||||
if (!clean_)
|
||||
throw comp_error(loc_, "invalid token ('#')");
|
||||
|
||||
switch (token)
|
||||
{
|
||||
case parser::token::SH_DEFINE:
|
||||
throw comp_error(loc_, "unimplemented preprocessor directive");
|
||||
break;
|
||||
case parser::token::SH_UNDEF:
|
||||
throw comp_error(loc_, "unimplemented preprocessor directive");
|
||||
break;
|
||||
case parser::token::SH_IFDEF:
|
||||
throw comp_error(loc_, "unimplemented preprocessor directive");
|
||||
break;
|
||||
case parser::token::SH_IFNDEF:
|
||||
throw comp_error(loc_, "unimplemented preprocessor directive");
|
||||
break;
|
||||
case parser::token::SH_IF:
|
||||
throw comp_error(loc_, "unimplemented preprocessor directive");
|
||||
break;
|
||||
case parser::token::SH_ELIF:
|
||||
throw comp_error(loc_, "unimplemented preprocessor directive");
|
||||
break;
|
||||
case parser::token::SH_ELSE:
|
||||
throw comp_error(loc_, "unimplemented preprocessor directive");
|
||||
break;
|
||||
case parser::token::SH_ENDIF:
|
||||
throw comp_error(loc_, "unimplemented preprocessor directive");
|
||||
break;
|
||||
default:
|
||||
throw comp_error(loc_, "unknown preprocessor directive");
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace xsk::gsc::iw6c
|
@ -1,78 +0,0 @@
|
||||
// Copyright 2022 xensik. All rights reserved.
|
||||
//
|
||||
// Use of this source code is governed by a GNU GPLv3 license
|
||||
// that can be found in the LICENSE file.
|
||||
|
||||
#pragma once
|
||||
|
||||
namespace xsk::gsc::iw6c
|
||||
{
|
||||
|
||||
constexpr size_t max_buf_size = 0x2000;
|
||||
|
||||
struct buffer
|
||||
{
|
||||
char* data;
|
||||
size_t length;
|
||||
|
||||
buffer();
|
||||
~buffer();
|
||||
bool push(char c);
|
||||
};
|
||||
|
||||
struct reader
|
||||
{
|
||||
enum state_type : std::uint8_t { end, ok };
|
||||
|
||||
const char* buffer_pos;
|
||||
std::uint32_t bytes_remaining;
|
||||
char last_byte;
|
||||
char current_byte;
|
||||
state_type state;
|
||||
|
||||
reader();
|
||||
|
||||
reader(const reader& obj)
|
||||
{
|
||||
std::memcpy(this, &obj, sizeof(reader));
|
||||
}
|
||||
|
||||
reader& operator=(const reader& obj)
|
||||
{
|
||||
std::memcpy(this, &obj, sizeof(reader));
|
||||
return *this;
|
||||
}
|
||||
|
||||
void init(const char* data, size_t size);
|
||||
void advance();
|
||||
};
|
||||
|
||||
class lexer
|
||||
{
|
||||
enum class state : std::uint8_t { start, string, localize, preprocessor };
|
||||
|
||||
reader reader_;
|
||||
buffer buffer_;
|
||||
location loc_;
|
||||
std::stack<location> locs_;
|
||||
std::stack<reader> readers_;
|
||||
std::uint32_t header_top_;
|
||||
state state_;
|
||||
build mode_;
|
||||
bool indev_;
|
||||
bool clean_;
|
||||
|
||||
public:
|
||||
lexer(build mode, const std::string& name, const char* data, size_t size);
|
||||
auto lex() -> parser::symbol_type;
|
||||
void push_header(const std::string& file);
|
||||
void pop_header();
|
||||
void ban_header(const location& loc);
|
||||
|
||||
private:
|
||||
void advance();
|
||||
void preprocessor_wrap();
|
||||
void preprocessor_run(parser::token::token_kind_type token);
|
||||
};
|
||||
|
||||
} // namespace xsk::gsc::iw6c
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@ -1,486 +0,0 @@
|
||||
// Copyright 2022 xensik. All rights reserved.
|
||||
//
|
||||
// Use of this source code is governed by a GNU GPLv3 license
|
||||
// that can be found in the LICENSE file.
|
||||
|
||||
#include "stdafx.hpp"
|
||||
#include "iw6c.hpp"
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#pragma warning(push)
|
||||
#pragma warning(disable:4244)
|
||||
#endif
|
||||
|
||||
namespace xsk::gsc::iw6c
|
||||
{
|
||||
|
||||
std::unordered_map<std::uint8_t, std::string_view> opcode_map;
|
||||
std::unordered_map<std::uint16_t, std::string_view> function_map;
|
||||
std::unordered_map<std::uint16_t, std::string_view> method_map;
|
||||
std::unordered_map<std::uint16_t, std::string_view> token_map;
|
||||
std::unordered_map<std::string_view, std::uint8_t> opcode_map_rev;
|
||||
std::unordered_map<std::string_view, std::uint16_t> function_map_rev;
|
||||
std::unordered_map<std::string_view, std::uint16_t> method_map_rev;
|
||||
std::unordered_map<std::string_view, std::uint16_t> token_map_rev;
|
||||
std::unordered_map<std::string, std::vector<std::uint8_t>> files;
|
||||
read_cb_type read_callback = nullptr;
|
||||
std::set<std::string> string_map;
|
||||
|
||||
void resolver::init(read_cb_type callback)
|
||||
{
|
||||
read_callback = callback;
|
||||
}
|
||||
|
||||
void resolver::cleanup()
|
||||
{
|
||||
files.clear();
|
||||
}
|
||||
|
||||
auto resolver::opcode_id(const std::string& name) -> std::uint8_t
|
||||
{
|
||||
const auto itr = opcode_map_rev.find(name);
|
||||
|
||||
if (itr != opcode_map_rev.end())
|
||||
{
|
||||
return itr->second;
|
||||
}
|
||||
|
||||
throw error(utils::string::va("couldn't resolve opcode id for name '%s'!", name.data()));
|
||||
}
|
||||
|
||||
auto resolver::opcode_name(std::uint8_t id) -> std::string
|
||||
{
|
||||
const auto itr = opcode_map.find(id);
|
||||
|
||||
if (itr != opcode_map.end())
|
||||
{
|
||||
return std::string(itr->second);
|
||||
}
|
||||
|
||||
throw 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
|
||||
{
|
||||
if (name.starts_with("_func_"))
|
||||
{
|
||||
return static_cast<std::uint16_t>(std::stoul(name.substr(6), nullptr, 16));
|
||||
}
|
||||
|
||||
const auto itr = function_map_rev.find(name);
|
||||
|
||||
if (itr != function_map_rev.end())
|
||||
{
|
||||
return itr->second;
|
||||
}
|
||||
|
||||
throw 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 std::string(itr->second);
|
||||
}
|
||||
|
||||
return utils::string::va("_func_%04X", id);
|
||||
}
|
||||
|
||||
auto resolver::method_id(const std::string& name) -> std::uint16_t
|
||||
{
|
||||
if (name.starts_with("_meth_"))
|
||||
{
|
||||
return static_cast<std::uint16_t>(std::stoul(name.substr(6), nullptr, 16));
|
||||
}
|
||||
|
||||
const auto itr = method_map_rev.find(name);
|
||||
|
||||
if (itr != method_map_rev.end())
|
||||
{
|
||||
return itr->second;
|
||||
}
|
||||
|
||||
throw 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 std::string(itr->second);
|
||||
}
|
||||
|
||||
return utils::string::va("_meth_%04X", id);
|
||||
}
|
||||
|
||||
auto resolver::token_id(const std::string& name) -> std::uint16_t
|
||||
{
|
||||
if (name.starts_with("_id_"))
|
||||
{
|
||||
return static_cast<std::uint16_t>(std::stoul(name.substr(4), nullptr, 16));
|
||||
}
|
||||
|
||||
const auto itr = token_map_rev.find(name);
|
||||
|
||||
if (itr != token_map_rev.end())
|
||||
{
|
||||
return itr->second;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
auto resolver::token_name(std::uint16_t id) -> std::string
|
||||
{
|
||||
const auto itr = token_map.find(id);
|
||||
|
||||
if (itr != token_map.end())
|
||||
{
|
||||
return std::string(itr->second);
|
||||
}
|
||||
|
||||
return utils::string::va("_id_%04X", id);
|
||||
}
|
||||
|
||||
auto resolver::find_function(const std::string& name) -> bool
|
||||
{
|
||||
if (name.starts_with("_func_")) return true;
|
||||
|
||||
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
|
||||
{
|
||||
if (name.starts_with("_meth_")) return true;
|
||||
|
||||
const auto itr = method_map_rev.find(name);
|
||||
|
||||
if (itr != method_map_rev.end())
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
auto resolver::make_token(std::string_view str) -> std::string
|
||||
{
|
||||
if (str.starts_with("_id_") || str.starts_with("_func_") || str.starts_with("_meth_"))
|
||||
{
|
||||
return std::string(str);
|
||||
}
|
||||
|
||||
auto data = std::string(str.begin(), str.end());
|
||||
|
||||
for (std::size_t i = 0; i < data.size(); i++)
|
||||
{
|
||||
data[i] = static_cast<char>(std::tolower(static_cast<unsigned char>(str[i])));
|
||||
if (data[i] == '\\') data[i] = '/';
|
||||
}
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
auto resolver::file_data(const std::string& name) -> std::tuple<const std::string*, const char*, size_t>
|
||||
{
|
||||
const auto itr = files.find(name);
|
||||
|
||||
if (itr != files.end())
|
||||
{
|
||||
return { &itr->first ,reinterpret_cast<const char*>(itr->second.data()), itr->second.size() };
|
||||
}
|
||||
|
||||
auto data = read_callback(name);
|
||||
|
||||
const auto res = files.insert({ name, std::move(data)});
|
||||
|
||||
if (res.second)
|
||||
{
|
||||
return { &res.first->first, reinterpret_cast<const char*>(res.first->second.data()), res.first->second.size() };
|
||||
}
|
||||
|
||||
throw error("couldn't open gsc file '" + name + "'");
|
||||
}
|
||||
|
||||
std::set<std::string_view> paths
|
||||
{
|
||||
"character"sv,
|
||||
"codescripts"sv,
|
||||
"common_scripts"sv,
|
||||
"destructible_scripts"sv,
|
||||
"maps"sv,
|
||||
"vehicle_scripts"sv,
|
||||
"xmodelalias"sv,
|
||||
"maps/animated_models"sv,
|
||||
"maps/createart"sv,
|
||||
"maps/createfx"sv,
|
||||
"maps/interactive_models"sv,
|
||||
"maps/mp"sv,
|
||||
"maps/mp/agents"sv,
|
||||
"maps/mp/alien"sv,
|
||||
"maps/mp/bots"sv,
|
||||
"maps/mp/gametypes"sv,
|
||||
"maps/mp/killstreaks"sv,
|
||||
"maps/mp/perks"sv,
|
||||
"maps/mp/agents/alien"sv,
|
||||
"maps/mp/agents/dog"sv,
|
||||
"maps/mp/agents/alien/alien_ancestor"sv,
|
||||
"maps/mp/agents/alien/alien_kraken"sv,
|
||||
"maps/mp/agents/alien/alien_spider"sv,
|
||||
};
|
||||
|
||||
auto resolver::fs_to_game_path(const std::filesystem::path& file) -> std::filesystem::path
|
||||
{
|
||||
auto result = std::filesystem::path();
|
||||
auto root = false;
|
||||
|
||||
for (auto& entry : file)
|
||||
{
|
||||
if (!root && paths.contains(entry.string()))
|
||||
{
|
||||
result = entry;
|
||||
root = true;
|
||||
}
|
||||
else if (paths.contains(result.string()))
|
||||
{
|
||||
result /= entry;
|
||||
}
|
||||
}
|
||||
|
||||
return result.empty() ? file : result;
|
||||
}
|
||||
|
||||
const std::array<std::pair<std::uint8_t, const char*>, 153> opcode_list
|
||||
{{
|
||||
{ 0x1D, "OP_CastFieldObject" },
|
||||
{ 0x1E, "OP_SetLocalVariableFieldCached" },
|
||||
{ 0x1F, "OP_plus" },
|
||||
{ 0x20, "OP_RemoveLocalVariables" },
|
||||
{ 0x21, "OP_EvalSelfFieldVariableRef" },
|
||||
{ 0x22, "OP_ScriptFarMethodChildThreadCall" },
|
||||
{ 0x23, "OP_GetGameRef" },
|
||||
{ 0x24, "OP_EvalAnimFieldVariable" },
|
||||
{ 0x25, "OP_EvalLevelFieldVariableRef" },
|
||||
{ 0x26, "OP_GetThisthread" },
|
||||
{ 0x27, "OP_greater" },
|
||||
{ 0x28, "OP_waittillmatch" },
|
||||
{ 0x29, "OP_shift_right" },
|
||||
{ 0x2A, "OP_dec" },
|
||||
{ 0x2B, "OP_JumpOnTrue" },
|
||||
{ 0x2C, "OP_bit_or" },
|
||||
{ 0x2D, "OP_equality" },
|
||||
{ 0x2E, "OP_ClearLocalVariableFieldCached0" },
|
||||
{ 0x2F, "OP_notify" },
|
||||
{ 0x30, "OP_GetVector" },
|
||||
{ 0x31, "OP_ScriptMethodChildThreadCallPointer" },
|
||||
{ 0x32, "OP_PreScriptCall" },
|
||||
{ 0x33, "OP_GetByte" },
|
||||
{ 0x34, "OP_ScriptFarThreadCall" },
|
||||
{ 0x35, "OP_SetSelfFieldVariableField" },
|
||||
{ 0x36, "OP_JumpOnFalseExpr" },
|
||||
{ 0x37, "OP_GetUndefined" },
|
||||
{ 0x38, "OP_jumpback" },
|
||||
{ 0x39, "OP_JumpOnTrueExpr" },
|
||||
{ 0x3A, "OP_CallBuiltin0" },
|
||||
{ 0x3B, "OP_CallBuiltin1" },
|
||||
{ 0x3C, "OP_CallBuiltin2" },
|
||||
{ 0x3D, "OP_CallBuiltin3" },
|
||||
{ 0x3E, "OP_CallBuiltin4" },
|
||||
{ 0x3F, "OP_CallBuiltin5" },
|
||||
{ 0x40, "OP_CallBuiltin" },
|
||||
{ 0x41, "OP_SetLocalVariableFieldCached0" },
|
||||
{ 0x42, "OP_ClearFieldVariable" },
|
||||
{ 0x43, "OP_GetLevel" },
|
||||
{ 0x44, "OP_size" },
|
||||
{ 0x45, "OP_SafeSetWaittillVariableFieldCached" },
|
||||
{ 0x46, "OP_ScriptLocalMethodThreadCall" },
|
||||
{ 0x47, "OP_AddArray" },
|
||||
{ 0x48, "OP_endon" },
|
||||
{ 0x49, "OP_EvalFieldVariable" },
|
||||
{ 0x4A, "OP_shift_left" },
|
||||
{ 0x4B, "OP_EvalLocalArrayRefCached0" },
|
||||
{ 0x4C, "OP_Return" },
|
||||
{ 0x4D, "OP_CreateLocalVariable" },
|
||||
{ 0x4E, "OP_SafeSetVariableFieldCached0" },
|
||||
{ 0x4F, "OP_GetBuiltinMethod" },
|
||||
{ 0x50, "OP_ScriptLocalMethodCall" },
|
||||
{ 0x51, "OP_CallBuiltinMethodPointer" },
|
||||
{ 0x52, "OP_ScriptLocalChildThreadCall" },
|
||||
{ 0x53, "OP_GetSelfObject" },
|
||||
{ 0x54, "OP_GetGame" },
|
||||
{ 0x55, "OP_SetLevelFieldVariableField" },
|
||||
{ 0x56, "OP_EvalArray" },
|
||||
{ 0x57, "OP_GetSelf" },
|
||||
{ 0x58, "OP_End" },
|
||||
{ 0x59, "OP_EvalSelfFieldVariable" },
|
||||
{ 0x5A, "OP_less_equal" },
|
||||
{ 0x5B, "OP_EvalLocalVariableCached0" },
|
||||
{ 0x5C, "OP_EvalLocalVariableCached1" },
|
||||
{ 0x5D, "OP_EvalLocalVariableCached2" },
|
||||
{ 0x5E, "OP_EvalLocalVariableCached3" },
|
||||
{ 0x5F, "OP_EvalLocalVariableCached4" },
|
||||
{ 0x60, "OP_EvalLocalVariableCached5" },
|
||||
{ 0x61, "OP_EvalLocalVariableCached" },
|
||||
{ 0x62, "OP_EvalNewLocalArrayRefCached0" },
|
||||
{ 0x63, "OP_ScriptChildThreadCallPointer" },
|
||||
{ 0x64, "OP_EvalLocalVariableObjectCached" },
|
||||
{ 0x65, "OP_ScriptLocalThreadCall" },
|
||||
{ 0x66, "OP_GetInteger" },
|
||||
{ 0x67, "OP_ScriptMethodCallPointer" },
|
||||
{ 0x68, "OP_checkclearparams" },
|
||||
{ 0x69, "OP_SetAnimFieldVariableField" },
|
||||
{ 0x6A, "OP_waittillmatch2" },
|
||||
{ 0x6B, "OP_minus" },
|
||||
{ 0x6C, "OP_ScriptLocalFunctionCall2" },
|
||||
{ 0x6D, "OP_GetNegUnsignedShort" },
|
||||
{ 0x6E, "OP_GetNegByte" },
|
||||
{ 0x6F, "OP_SafeCreateVariableFieldCached" },
|
||||
{ 0x70, "OP_greater_equal" },
|
||||
{ 0x71, "OP_vector" },
|
||||
{ 0x72, "OP_GetBuiltinFunction" },
|
||||
{ 0x73, "OP_endswitch" },
|
||||
{ 0x74, "OP_ClearArray" },
|
||||
{ 0x75, "OP_DecTop" },
|
||||
{ 0x76, "OP_CastBool" },
|
||||
{ 0x77, "OP_EvalArrayRef" },
|
||||
{ 0x78, "OP_SetNewLocalVariableFieldCached0" },
|
||||
{ 0x79, "OP_GetZero" },
|
||||
{ 0x7A, "OP_wait" },
|
||||
{ 0x7B, "OP_waittill" },
|
||||
{ 0x7C, "OP_GetIString" },
|
||||
{ 0x7D, "OP_ScriptFarFunctionCall" },
|
||||
{ 0x7E, "OP_GetAnimObject" },
|
||||
{ 0x7F, "OP_GetAnimTree" },
|
||||
{ 0x80, "OP_EvalLocalArrayCached" },
|
||||
{ 0x81, "OP_mod" },
|
||||
{ 0x82, "OP_ScriptFarMethodThreadCall" },
|
||||
{ 0x83, "OP_GetUnsignedShort" },
|
||||
{ 0x84, "OP_clearparams" },
|
||||
{ 0x85, "OP_ScriptMethodThreadCallPointer" },
|
||||
{ 0x86, "OP_ScriptFunctionCallPointer" },
|
||||
{ 0x87, "OP_EmptyArray" },
|
||||
{ 0x88, "OP_SafeSetVariableFieldCached" },
|
||||
{ 0x89, "OP_UNK_2" },
|
||||
{ 0x8A, "OP_EvalFieldVariableRef" },
|
||||
{ 0x8B, "OP_ScriptLocalMethodChildThreadCall" },
|
||||
{ 0x8C, "OP_UNK_3" },
|
||||
{ 0x8D, "OP_GetFloat" },
|
||||
{ 0x8E, "OP_EvalLocalVariableRefCached" },
|
||||
{ 0x8F, "OP_JumpOnFalse" },
|
||||
{ 0x90, "OP_BoolComplement" },
|
||||
{ 0x91, "OP_ScriptThreadCallPointer" },
|
||||
{ 0x92, "OP_ScriptFarFunctionCall2" },
|
||||
{ 0x93, "OP_less" },
|
||||
{ 0x94, "OP_BoolNot" },
|
||||
{ 0x95, "OP_waittillFrameEnd" },
|
||||
{ 0x96, "OP_GetString" },
|
||||
{ 0x97, "OP_EvalLevelFieldVariable" },
|
||||
{ 0x98, "OP_GetLevelObject" },
|
||||
{ 0x99, "OP_inc" },
|
||||
{ 0x9A, "OP_CallBuiltinMethod0" },
|
||||
{ 0x9B, "OP_CallBuiltinMethod1" },
|
||||
{ 0x9C, "OP_CallBuiltinMethod2" },
|
||||
{ 0x9D, "OP_CallBuiltinMethod3" },
|
||||
{ 0x9E, "OP_CallBuiltinMethod4" },
|
||||
{ 0x9F, "OP_CallBuiltinMethod5" },
|
||||
{ 0xA0, "OP_CallBuiltinMethod" },
|
||||
{ 0xA1, "OP_GetAnim" },
|
||||
{ 0xA2, "OP_switch" },
|
||||
{ 0xA3, "OP_SetVariableField" },
|
||||
{ 0xA4, "OP_divide" },
|
||||
{ 0xA5, "OP_GetLocalFunction" },
|
||||
{ 0xA6, "OP_ScriptFarChildThreadCall" },
|
||||
{ 0xA7, "OP_multiply" },
|
||||
{ 0xA8, "OP_ClearLocalVariableFieldCached" },
|
||||
{ 0xA9, "OP_EvalAnimFieldVariableRef" },
|
||||
{ 0xAA, "OP_EvalLocalArrayRefCached" },
|
||||
{ 0xAB, "OP_EvalLocalVariableRefCached0" },
|
||||
{ 0xAC, "OP_bit_and" },
|
||||
{ 0xAD, "OP_GetAnimation" },
|
||||
{ 0xAE, "OP_GetFarFunction" },
|
||||
{ 0xAF, "OP_CallBuiltinPointer" },
|
||||
{ 0xB0, "OP_jump" },
|
||||
{ 0xB1, "OP_voidCodepos" },
|
||||
{ 0xB2, "OP_ScriptFarMethodCall" },
|
||||
{ 0xB3, "OP_inequality" },
|
||||
{ 0xB4, "OP_ScriptLocalFunctionCall" },
|
||||
{ 0xB5, "OP_bit_ex_or" },
|
||||
}};
|
||||
|
||||
const std::array<std::pair<std::uint16_t, const char*>, 3> function_list
|
||||
{{
|
||||
{ 0x12, "isdefined" },
|
||||
{ 0xB7, "getfirstarraykey" },
|
||||
{ 0xB8, "getnextarraykey" },
|
||||
}};
|
||||
|
||||
const std::array<std::pair<std::uint16_t, const char*>, 0> method_list
|
||||
{{
|
||||
}};
|
||||
|
||||
const std::array<std::pair<std::uint16_t, const char*>, 0> token_list
|
||||
{{
|
||||
}};
|
||||
|
||||
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());
|
||||
token_map.reserve(token_list.size());
|
||||
token_map_rev.reserve(token_list.size());
|
||||
|
||||
for (const auto& entry : opcode_list)
|
||||
{
|
||||
opcode_map.insert({ entry.first, entry.second });
|
||||
opcode_map_rev.insert({ entry.second, entry.first });
|
||||
}
|
||||
|
||||
for (const auto& entry : function_list)
|
||||
{
|
||||
function_map.insert({ entry.first, entry.second });
|
||||
function_map_rev.insert({ entry.second, entry.first });
|
||||
}
|
||||
|
||||
for (const auto& entry : method_list)
|
||||
{
|
||||
method_map.insert({ entry.first, entry.second });
|
||||
method_map_rev.insert({ entry.second, entry.first });
|
||||
}
|
||||
|
||||
for (const auto& entry : token_list)
|
||||
{
|
||||
token_map.insert({ entry.first, entry.second });
|
||||
token_map_rev.insert({ entry.second, entry.first });
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
__init__ _;
|
||||
|
||||
} // namespace xsk::gsc::iw6c
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#pragma warning(pop)
|
||||
#endif
|
@ -1,40 +0,0 @@
|
||||
// Copyright 2022 xensik. All rights reserved.
|
||||
//
|
||||
// Use of this source code is governed by a GNU GPLv3 license
|
||||
// that can be found in the LICENSE file.
|
||||
|
||||
#pragma once
|
||||
|
||||
namespace xsk::gsc::iw6c
|
||||
{
|
||||
|
||||
class resolver
|
||||
{
|
||||
public:
|
||||
static void init(read_cb_type callback);
|
||||
static void cleanup();
|
||||
|
||||
static auto opcode_id(const std::string& name) -> std::uint8_t;
|
||||
static auto opcode_name(std::uint8_t id) -> std::string;
|
||||
|
||||
static auto 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 token_id(const std::string& name) -> std::uint16_t;
|
||||
static auto token_name(std::uint16_t id) -> std::string;
|
||||
|
||||
static auto find_function(const std::string& name) -> bool;
|
||||
static auto find_method(const std::string& name) -> bool;
|
||||
|
||||
static void add_function(const std::string& name, std::uint16_t id);
|
||||
static void add_method(const std::string& name, std::uint16_t id);
|
||||
|
||||
static auto make_token(std::string_view str) -> std::string;
|
||||
static auto file_data(const std::string& name) -> std::tuple<const std::string*, const char*, size_t>;
|
||||
static auto fs_to_game_path(const std::filesystem::path& file) -> std::filesystem::path;
|
||||
};
|
||||
|
||||
} // namespace xsk::gsc::iw6c
|
@ -1,26 +0,0 @@
|
||||
// Copyright 2022 xensik. All rights reserved.
|
||||
//
|
||||
// Use of this source code is governed by a GNU GPLv3 license
|
||||
// that can be found in the LICENSE file.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <cstdio>
|
||||
#include <algorithm>
|
||||
#include <array>
|
||||
#include <filesystem>
|
||||
#include <fstream>
|
||||
#include <functional>
|
||||
#include <iostream>
|
||||
#include <map>
|
||||
#include <memory>
|
||||
#include <regex>
|
||||
#include <set>
|
||||
#include <sstream>
|
||||
#include <stack>
|
||||
#include <stdexcept>
|
||||
#include <string>
|
||||
#include <unordered_map>
|
||||
#include <vector>
|
||||
|
||||
using namespace std::literals;
|
@ -1,555 +0,0 @@
|
||||
// Copyright 2022 xensik. All rights reserved.
|
||||
//
|
||||
// Use of this source code is governed by a GNU GPLv3 license
|
||||
// that can be found in the LICENSE file.
|
||||
|
||||
#include "stdafx.hpp"
|
||||
#include "s1c.hpp"
|
||||
|
||||
namespace xsk::gsc::s1c
|
||||
{
|
||||
|
||||
auto assembler::output_script() -> std::vector<std::uint8_t>
|
||||
{
|
||||
std::vector<std::uint8_t> script;
|
||||
|
||||
if (script_ == nullptr) return script;
|
||||
|
||||
script.resize(script_->pos());
|
||||
std::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());
|
||||
std::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<function::ptr> functions;
|
||||
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<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 opdata = utils::string::parse_code(line);
|
||||
|
||||
if (switchnum)
|
||||
{
|
||||
if (opdata[0] == "case" || opdata[0] == "default")
|
||||
{
|
||||
for (auto& entry : opdata)
|
||||
{
|
||||
func->instructions.back()->data.push_back(entry);
|
||||
}
|
||||
switchnum--;
|
||||
continue;
|
||||
}
|
||||
|
||||
throw asm_error("invalid instruction inside endswitch \""s + line + "\"!");
|
||||
}
|
||||
else
|
||||
{
|
||||
auto inst = std::make_unique<instruction>();
|
||||
inst->index = index;
|
||||
inst->opcode = resolver::opcode_id(opdata[0]);
|
||||
inst->size = opcode_size(inst->opcode);
|
||||
opdata.erase(opdata.begin());
|
||||
inst->data = std::move(opdata);
|
||||
|
||||
switch (static_cast<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[0] = inst->data[0].substr(4);
|
||||
break;
|
||||
case opcode::OP_endswitch:
|
||||
switchnum = static_cast<std::uint16_t>(std::stoi(inst->data[0]));
|
||||
inst->size += 7 * switchnum;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
index += inst->size;
|
||||
func->instructions.push_back(std::move(inst));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
assemble(file, functions);
|
||||
}
|
||||
|
||||
void assembler::assemble(const std::string& file, std::vector<function::ptr>& funcs)
|
||||
{
|
||||
script_ = std::make_unique<utils::byte_buffer>(0x100000);
|
||||
stack_ = std::make_unique<utils::byte_buffer>(0x100000);
|
||||
filename_ = file;
|
||||
functions_ = std::move(funcs);
|
||||
|
||||
script_->write_endian<std::uint8_t>(static_cast<std::uint8_t>(opcode::OP_End));
|
||||
|
||||
for (const auto& func : functions_)
|
||||
{
|
||||
assemble_function(func);
|
||||
}
|
||||
}
|
||||
|
||||
void assembler::assemble_function(const function::ptr& func)
|
||||
{
|
||||
labels_ = func->labels;
|
||||
|
||||
func->id = resolver::token_id(func->name);
|
||||
|
||||
stack_->write_endian<std::uint32_t>(func->size);
|
||||
stack_->write_endian<std::uint16_t>(static_cast<std::uint16_t>(func->id));
|
||||
|
||||
if (func->id == 0)
|
||||
{
|
||||
stack_->write_c_string(func->name);
|
||||
}
|
||||
|
||||
for (const auto& inst : func->instructions)
|
||||
{
|
||||
assemble_instruction(inst);
|
||||
}
|
||||
}
|
||||
|
||||
void assembler::assemble_instruction(const instruction::ptr& inst)
|
||||
{
|
||||
script_->write_endian<std::uint8_t>(static_cast<std::uint8_t>(inst->opcode));
|
||||
|
||||
switch (static_cast<opcode>(inst->opcode))
|
||||
{
|
||||
case opcode::OP_Return:
|
||||
case opcode::OP_BoolNot:
|
||||
case opcode::OP_CastBool:
|
||||
case opcode::OP_inequality:
|
||||
case opcode::OP_GetThisthread:
|
||||
case opcode::OP_ClearLocalVariableFieldCached0:
|
||||
case opcode::OP_checkclearparams:
|
||||
case opcode::OP_CastFieldObject:
|
||||
case opcode::OP_End:
|
||||
case opcode::OP_size:
|
||||
case opcode::OP_EmptyArray:
|
||||
case opcode::OP_bit_and:
|
||||
case opcode::OP_less_equal:
|
||||
case opcode::OP_voidCodepos:
|
||||
// case opcode::OP_ClearVariableField:
|
||||
case opcode::OP_divide:
|
||||
case opcode::OP_GetSelf:
|
||||
case opcode::OP_SetLocalVariableFieldCached0:
|
||||
case opcode::OP_plus:
|
||||
case opcode::OP_BoolComplement:
|
||||
case opcode::OP_ScriptMethodCallPointer:
|
||||
case opcode::OP_inc:
|
||||
case opcode::OP_clearparams:
|
||||
case opcode::OP_EvalLocalVariableRefCached0:
|
||||
case opcode::OP_ScriptFunctionCallPointer:
|
||||
case opcode::OP_endon:
|
||||
case opcode::OP_greater_equal:
|
||||
case opcode::OP_GetSelfObject:
|
||||
case opcode::OP_SetVariableField:
|
||||
case opcode::OP_EvalLocalArrayRefCached0:
|
||||
case opcode::OP_less:
|
||||
case opcode::OP_GetGameRef:
|
||||
case opcode::OP_waittillFrameEnd:
|
||||
case opcode::OP_waitFrame:
|
||||
case opcode::OP_SafeSetVariableFieldCached0:
|
||||
case opcode::OP_GetLevel:
|
||||
case opcode::OP_notify:
|
||||
case opcode::OP_DecTop:
|
||||
case opcode::OP_shift_left:
|
||||
case opcode::OP_greater:
|
||||
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_GetZero:
|
||||
case opcode::OP_wait:
|
||||
case opcode::OP_minus:
|
||||
// case opcode::OP_EvalNewLocalVariableRefCached0:
|
||||
case opcode::OP_multiply:
|
||||
case opcode::OP_mod:
|
||||
case opcode::OP_GetGame:
|
||||
case opcode::OP_waittill:
|
||||
case opcode::OP_dec:
|
||||
case opcode::OP_PreScriptCall:
|
||||
case opcode::OP_GetAnim:
|
||||
case opcode::OP_GetUndefined:
|
||||
case opcode::OP_GetAnimObject:
|
||||
case opcode::OP_GetLevelObject:
|
||||
case opcode::OP_bit_ex_or:
|
||||
case opcode::OP_equality:
|
||||
case opcode::OP_ClearArray:
|
||||
case opcode::OP_EvalArrayRef:
|
||||
case opcode::OP_EvalArray:
|
||||
case opcode::OP_vector:
|
||||
case opcode::OP_bit_or:
|
||||
case opcode::OP_AddArray:
|
||||
case opcode::OP_waittillmatch2:
|
||||
case opcode::OP_shift_right:
|
||||
break;
|
||||
case opcode::OP_GetByte:
|
||||
case opcode::OP_GetNegByte:
|
||||
script_->write_endian<std::uint8_t>(static_cast<std::uint8_t>(std::stoi(inst->data[0])));
|
||||
break;
|
||||
case opcode::OP_GetUnsignedShort:
|
||||
case opcode::OP_GetNegUnsignedShort:
|
||||
script_->write_endian<std::uint16_t>(static_cast<std::uint16_t>(std::stoi(inst->data[0])));
|
||||
break;
|
||||
case opcode::OP_GetInteger:
|
||||
script_->write_endian<std::int32_t>(std::stoi(inst->data[0]));
|
||||
break;
|
||||
case opcode::OP_GetFloat:
|
||||
script_->write_endian<float>(std::stof(inst->data[0]));
|
||||
break;
|
||||
case opcode::OP_GetVector:
|
||||
inst->size += script_->align(4);
|
||||
script_->write_endian<float>(std::stof(inst->data[0]));
|
||||
script_->write_endian<float>(std::stof(inst->data[1]));
|
||||
script_->write_endian<float>(std::stof(inst->data[2]));
|
||||
break;
|
||||
case opcode::OP_GetString:
|
||||
case opcode::OP_GetIString:
|
||||
script_->write_endian<std::uint16_t>(0);
|
||||
stack_->write_c_string(inst->data[0]);
|
||||
break;
|
||||
case opcode::OP_GetAnimation:
|
||||
script_->write_endian<std::uint32_t>(0);
|
||||
stack_->write_c_string(inst->data[0]);
|
||||
stack_->write_c_string(inst->data[1]);
|
||||
break;
|
||||
case opcode::OP_GetAnimTree:
|
||||
script_->write_endian<std::uint8_t>(0);
|
||||
stack_->write_c_string(inst->data[0]);
|
||||
break;
|
||||
case opcode::OP_waittillmatch:
|
||||
script_->write_endian<std::uint8_t>(static_cast<std::uint8_t>(std::stoi(inst->data[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_endian<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:
|
||||
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_endian<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:
|
||||
assemble_local_call(inst, false);
|
||||
break;
|
||||
case opcode::OP_ScriptLocalThreadCall:
|
||||
case opcode::OP_ScriptLocalChildThreadCall:
|
||||
case opcode::OP_ScriptLocalMethodThreadCall:
|
||||
case opcode::OP_ScriptLocalMethodChildThreadCall:
|
||||
assemble_local_call(inst, true);
|
||||
break;
|
||||
case opcode::OP_GetFarFunction:
|
||||
case opcode::OP_ScriptFarFunctionCall2:
|
||||
case opcode::OP_ScriptFarFunctionCall:
|
||||
case opcode::OP_ScriptFarMethodCall:
|
||||
assemble_far_call(inst, false);
|
||||
break;
|
||||
case opcode::OP_ScriptFarThreadCall:
|
||||
case opcode::OP_ScriptFarChildThreadCall:
|
||||
case opcode::OP_ScriptFarMethodThreadCall:
|
||||
case opcode::OP_ScriptFarMethodChildThreadCall:
|
||||
assemble_far_call(inst, true);
|
||||
break;
|
||||
case opcode::OP_CallBuiltin:
|
||||
assemble_builtin_call(inst, false, true);
|
||||
break;
|
||||
case opcode::OP_CallBuiltinMethod:
|
||||
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:
|
||||
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:
|
||||
assemble_builtin_call(inst, true, false);
|
||||
break;
|
||||
case opcode::OP_JumpOnFalseExpr:
|
||||
case opcode::OP_JumpOnTrueExpr:
|
||||
case opcode::OP_JumpOnFalse:
|
||||
case opcode::OP_JumpOnTrue:
|
||||
assemble_jump(inst, true, false);
|
||||
break;
|
||||
case opcode::OP_jumpback:
|
||||
assemble_jump(inst, false, true);
|
||||
break;
|
||||
case opcode::OP_jump:
|
||||
assemble_jump(inst, false, false);
|
||||
break;
|
||||
case opcode::OP_switch:
|
||||
assemble_switch(inst);
|
||||
break;
|
||||
case opcode::OP_endswitch:
|
||||
assemble_end_switch(inst);
|
||||
break;
|
||||
default:
|
||||
throw asm_error(utils::string::va("unhandled opcode 0x%X at index '%04X'!", inst->opcode, inst->index));
|
||||
}
|
||||
}
|
||||
|
||||
void assembler::assemble_builtin_call(const instruction::ptr& inst, bool method, bool args)
|
||||
{
|
||||
if (args)
|
||||
{
|
||||
script_->write_endian<std::uint8_t>(static_cast<std::uint8_t>(std::stoi(inst->data[1])));
|
||||
}
|
||||
|
||||
const auto id = method ? resolver::method_id(inst->data[0]) : resolver::function_id(inst->data[0]);
|
||||
|
||||
script_->write_endian<std::uint16_t>(id);
|
||||
}
|
||||
|
||||
void assembler::assemble_local_call(const instruction::ptr& inst, bool thread)
|
||||
{
|
||||
const auto addr = resolve_function(inst->data[0]);
|
||||
const auto offset = static_cast<std::int32_t>(addr - inst->index - 1);
|
||||
|
||||
assemble_offset(offset);
|
||||
|
||||
if (thread)
|
||||
{
|
||||
script_->write_endian<std::uint8_t>(static_cast<std::uint8_t>(std::stoi(inst->data[1])));
|
||||
}
|
||||
}
|
||||
|
||||
void assembler::assemble_far_call(const instruction::ptr& inst, bool thread)
|
||||
{
|
||||
script_->write_endian<std::uint8_t>(0);
|
||||
script_->write_endian<std::uint16_t>(0);
|
||||
|
||||
if (thread)
|
||||
{
|
||||
script_->write_endian<std::uint8_t>(static_cast<std::uint8_t>(std::stoi(inst->data[2])));
|
||||
}
|
||||
|
||||
const auto file_id = resolver::token_id(inst->data[0]);
|
||||
const auto func_id = resolver::token_id(inst->data[1]);
|
||||
|
||||
stack_->write_endian<std::uint16_t>(file_id);
|
||||
if (file_id == 0) stack_->write_c_string(inst->data[0]);
|
||||
stack_->write_endian<std::uint16_t>(func_id);
|
||||
if (func_id == 0) stack_->write_c_string(inst->data[1]);
|
||||
}
|
||||
|
||||
void assembler::assemble_switch(const instruction::ptr& inst)
|
||||
{
|
||||
const auto addr = resolve_label(inst->data[0]);
|
||||
|
||||
script_->write_endian<std::int32_t>(addr - inst->index - 4);
|
||||
}
|
||||
|
||||
void assembler::assemble_end_switch(const instruction::ptr& inst)
|
||||
{
|
||||
const auto count = std::stoul(inst->data[0]);
|
||||
|
||||
script_->write_endian<std::uint16_t>(static_cast<std::uint16_t>(count));
|
||||
|
||||
std::uint32_t index = inst->index + 3;
|
||||
|
||||
for (auto i = 0u; i < count; i++)
|
||||
{
|
||||
if (inst->data[1 + (3 * i)] == "case")
|
||||
{
|
||||
if (utils::string::is_number(inst->data[1 + (3 * i) + 1]))
|
||||
{
|
||||
script_->write_endian<uint32_t>((std::stoi(inst->data[1 + (3 * i) + 1]) & 0xFFFFFF) + 0x800000);
|
||||
}
|
||||
else
|
||||
{
|
||||
script_->write_endian<uint32_t>(i + 1);
|
||||
stack_->write_c_string(inst->data[1 + (3 * i) + 1]);
|
||||
}
|
||||
|
||||
index += 4;
|
||||
|
||||
const auto addr = resolve_label(inst->data[1 + (3 * i) + 2]);
|
||||
|
||||
assemble_offset(addr - index);
|
||||
|
||||
index += 3;
|
||||
}
|
||||
else if (inst->data[1 + (3 * i)] == "default")
|
||||
{
|
||||
script_->write_endian<uint32_t>(0);
|
||||
stack_->write_c_string("\x01");
|
||||
|
||||
index += 4;
|
||||
|
||||
const auto addr = resolve_label(inst->data[1 + (3 * i) + 1]);
|
||||
|
||||
assemble_offset(addr - index);
|
||||
|
||||
index += 3;
|
||||
}
|
||||
else
|
||||
{
|
||||
throw asm_error("invalid switch case '" + inst->data[1 + (3 * i)] + "'!");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void assembler::assemble_field_variable(const instruction::ptr& inst)
|
||||
{
|
||||
auto id = resolver::token_id(inst->data[0]);
|
||||
|
||||
if (id == 0) id = 0xFFFF;
|
||||
|
||||
script_->write_endian<std::uint16_t>(id);
|
||||
|
||||
if (id > max_string_id)
|
||||
{
|
||||
stack_->write_endian<std::uint16_t>(0);
|
||||
stack_->write_c_string(inst->data[0]);
|
||||
}
|
||||
}
|
||||
|
||||
void assembler::assemble_jump(const instruction::ptr& inst, bool expr, bool back)
|
||||
{
|
||||
const auto addr = resolve_label(inst->data[0]);
|
||||
|
||||
if (expr)
|
||||
{
|
||||
script_->write_endian<std::int16_t>(static_cast<std::int16_t>(addr - inst->index - 3));
|
||||
}
|
||||
else if (back)
|
||||
{
|
||||
script_->write_endian<std::int16_t>(static_cast<std::int16_t>((inst->index + 3) - addr));
|
||||
}
|
||||
else
|
||||
{
|
||||
script_->write_endian<std::int32_t>(static_cast<std::int32_t>(addr - inst->index - 5));
|
||||
}
|
||||
}
|
||||
|
||||
void assembler::assemble_offset(std::int32_t offset)
|
||||
{
|
||||
std::array<std::uint8_t, 4> bytes = {};
|
||||
|
||||
offset = (offset << 10) >> 8;
|
||||
|
||||
*reinterpret_cast<std::int32_t*>(bytes.data()) = offset;
|
||||
|
||||
script_->write_endian<std::uint8_t>(bytes[2]);
|
||||
script_->write_endian<std::uint8_t>(bytes[1]);
|
||||
script_->write_endian<std::uint8_t>(bytes[0]);
|
||||
}
|
||||
|
||||
auto assembler::resolve_function(const std::string& name) -> std::int32_t
|
||||
{
|
||||
for (const auto& entry : functions_)
|
||||
{
|
||||
if (entry->name == name)
|
||||
{
|
||||
return entry->index;
|
||||
}
|
||||
}
|
||||
|
||||
throw asm_error("couldn't resolve local function address of '" + name + "'!");
|
||||
}
|
||||
|
||||
auto assembler::resolve_label(const std::string& name) -> std::int32_t
|
||||
{
|
||||
for (const auto& entry : labels_)
|
||||
{
|
||||
if (entry.second == name)
|
||||
{
|
||||
return entry.first;
|
||||
}
|
||||
}
|
||||
|
||||
throw asm_error("couldn't resolve label address of '" + name + "'!");
|
||||
}
|
||||
|
||||
} // namespace xsk::gsc::s1c
|
@ -1,40 +0,0 @@
|
||||
// Copyright 2022 xensik. All rights reserved.
|
||||
//
|
||||
// Use of this source code is governed by a GNU GPLv3 license
|
||||
// that can be found in the LICENSE file.
|
||||
|
||||
#pragma once
|
||||
|
||||
namespace xsk::gsc::s1c
|
||||
{
|
||||
|
||||
class assembler : public gsc::assembler
|
||||
{
|
||||
std::string filename_;
|
||||
utils::byte_buffer::ptr script_;
|
||||
utils::byte_buffer::ptr stack_;
|
||||
std::vector<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<function::ptr>& funcs);
|
||||
|
||||
private:
|
||||
void assemble_function(const function::ptr& func);
|
||||
void assemble_instruction(const instruction::ptr& inst);
|
||||
void assemble_builtin_call(const instruction::ptr& inst, bool method, bool args);
|
||||
void assemble_local_call(const instruction::ptr& inst, bool thread);
|
||||
void assemble_far_call(const instruction::ptr& inst, bool thread);
|
||||
void assemble_switch(const instruction::ptr& inst);
|
||||
void assemble_end_switch(const instruction::ptr& inst);
|
||||
void assemble_field_variable(const instruction::ptr& inst);
|
||||
void assemble_jump(const instruction::ptr& inst, bool expr, bool back);
|
||||
void assemble_offset(std::int32_t offset);
|
||||
auto resolve_function(const std::string& name) -> std::int32_t;
|
||||
auto resolve_label(const std::string& name) -> std::int32_t;
|
||||
};
|
||||
|
||||
} // namespace xsk::gsc::s1c
|
File diff suppressed because it is too large
Load Diff
@ -1,160 +0,0 @@
|
||||
// Copyright 2022 xensik. All rights reserved.
|
||||
//
|
||||
// Use of this source code is governed by a GNU GPLv3 license
|
||||
// that can be found in the LICENSE file.
|
||||
|
||||
#pragma once
|
||||
|
||||
namespace xsk::gsc::s1c
|
||||
{
|
||||
|
||||
enum class opcode : std::uint8_t;
|
||||
|
||||
class compiler : public gsc::compiler
|
||||
{
|
||||
build mode_;
|
||||
std::string filename_;
|
||||
std::vector<function::ptr> assembly_;
|
||||
function::ptr function_;
|
||||
std::uint32_t index_;
|
||||
std::uint32_t label_idx_;
|
||||
std::uint8_t stack_idx_;
|
||||
std::vector<std::string> local_stack_;
|
||||
std::vector<std::string> local_functions_;
|
||||
std::vector<include_t> includes_;
|
||||
std::vector<animtree_t> animtrees_;
|
||||
std::unordered_map<std::string, ast::expr> constants_;
|
||||
std::vector<block*> break_blks_;
|
||||
std::vector<block*> continue_blks_;
|
||||
bool can_break_;
|
||||
bool can_continue_;
|
||||
bool developer_thread_;
|
||||
|
||||
public:
|
||||
auto output() -> std::vector<function::ptr>;
|
||||
void compile(const std::string& file, std::vector<std::uint8_t>& data);
|
||||
void mode(build mode);
|
||||
|
||||
private:
|
||||
auto parse_buffer(const std::string& file, const char* data, size_t size) -> ast::program::ptr;
|
||||
auto parse_file(const std::string& file) -> ast::program::ptr;
|
||||
void compile_program(const ast::program::ptr& program);
|
||||
void emit_include(const ast::include::ptr& include);
|
||||
void emit_declaration(const ast::decl& decl);
|
||||
void emit_decl_usingtree(const ast::decl_usingtree::ptr& animtree);
|
||||
void emit_decl_constant(const ast::decl_constant::ptr& constant);
|
||||
void emit_decl_thread(const ast::decl_thread::ptr& thread);
|
||||
void emit_stmt(const ast::stmt& stmt, const block::ptr& blk, bool last);
|
||||
void emit_stmt_list(const ast::stmt_list::ptr& stmt, const block::ptr& blk, bool last);
|
||||
void emit_stmt_dev(const ast::stmt_dev::ptr& stmt, const block::ptr& blk, bool last);
|
||||
void emit_stmt_expr(const ast::stmt_expr::ptr& stmt, const block::ptr& blk);
|
||||
void emit_stmt_call(const ast::stmt_call::ptr& stmt, const block::ptr& blk);
|
||||
void emit_stmt_assign(const ast::stmt_assign::ptr& stmt, const block::ptr& blk);
|
||||
void emit_stmt_endon(const ast::stmt_endon::ptr& stmt, const block::ptr& blk);
|
||||
void emit_stmt_notify(const ast::stmt_notify::ptr& stmt, const block::ptr& blk);
|
||||
void emit_stmt_wait(const ast::stmt_wait::ptr& stmt, const block::ptr& blk);
|
||||
void emit_stmt_waittill(const ast::stmt_waittill::ptr& stmt, const block::ptr& blk);
|
||||
void emit_stmt_waittillmatch(const ast::stmt_waittillmatch::ptr& stmt, const block::ptr& blk);
|
||||
void emit_stmt_waittillframeend(const ast::stmt_waittillframeend::ptr& stmt, const block::ptr& blk);
|
||||
void emit_stmt_waitframe(const ast::stmt_waitframe::ptr& stmt, const block::ptr& blk);
|
||||
void emit_stmt_if(const ast::stmt_if::ptr& stmt, const block::ptr& blk, bool last);
|
||||
void emit_stmt_ifelse(const ast::stmt_ifelse::ptr& stmt, const block::ptr& blk, bool last);
|
||||
void emit_stmt_while(const ast::stmt_while::ptr& stmt, const block::ptr& blk);
|
||||
void emit_stmt_dowhile(const ast::stmt_dowhile::ptr& stmt, const block::ptr& blk);
|
||||
void emit_stmt_for(const ast::stmt_for::ptr& stmt, const block::ptr& blk);
|
||||
void emit_stmt_foreach(const ast::stmt_foreach::ptr& stmt, const block::ptr& blk);
|
||||
void emit_stmt_switch(const ast::stmt_switch::ptr& stmt, const block::ptr& blk);
|
||||
void emit_stmt_case(const ast::stmt_case::ptr& stmt, const block::ptr& blk);
|
||||
void emit_stmt_default(const ast::stmt_default::ptr& stmt, const block::ptr& blk);
|
||||
void emit_stmt_break(const ast::stmt_break::ptr& stmt, const block::ptr& blk);
|
||||
void emit_stmt_continue(const ast::stmt_continue::ptr& stmt, const block::ptr& blk);
|
||||
void emit_stmt_return(const ast::stmt_return::ptr& stmt, const block::ptr& blk);
|
||||
void emit_stmt_breakpoint(const ast::stmt_breakpoint::ptr& stmt, const block::ptr& blk);
|
||||
void emit_stmt_prof_begin(const ast::stmt_prof_begin::ptr& stmt, const block::ptr& blk);
|
||||
void emit_stmt_prof_end(const ast::stmt_prof_end::ptr& stmt, const block::ptr& blk);
|
||||
void emit_expr(const ast::expr& expr, const block::ptr& blk);
|
||||
void emit_expr_assign(const ast::expr_assign::ptr& expr, const block::ptr& blk);
|
||||
void emit_expr_clear(const ast::expr& expr, const block::ptr& blk);
|
||||
void emit_expr_clear_local(const ast::expr_identifier::ptr& expr, const block::ptr& blk);
|
||||
void emit_expr_increment(const ast::expr_increment::ptr& expr, const block::ptr& blk, bool is_stmt);
|
||||
void emit_expr_decrement(const ast::expr_decrement::ptr& expr, const block::ptr& blk, bool is_stmt);
|
||||
void emit_expr_ternary(const ast::expr_ternary::ptr& expr, const block::ptr& blk);
|
||||
void emit_expr_binary(const ast::expr_binary::ptr& expr, const block::ptr& blk);
|
||||
void emit_expr_and(const ast::expr_and::ptr& expr, const block::ptr& blk);
|
||||
void emit_expr_or(const ast::expr_or::ptr& expr, const block::ptr& blk);
|
||||
void emit_expr_complement(const ast::expr_complement::ptr& expr, const block::ptr& blk);
|
||||
void emit_expr_negate(const ast::expr_negate::ptr& expr, const block::ptr& blk);
|
||||
void emit_expr_not(const ast::expr_not::ptr& expr, const block::ptr& blk);
|
||||
void emit_expr_call(const ast::expr_call::ptr& expr, const block::ptr& blk, bool is_stmt);
|
||||
void emit_expr_call_pointer(const ast::expr_pointer::ptr& expr, const block::ptr& blk, bool is_stmt);
|
||||
void emit_expr_call_function(const ast::expr_function::ptr& expr, const block::ptr& blk, bool is_stmt);
|
||||
void emit_expr_method(const ast::expr_method::ptr& expr, const block::ptr& blk, bool is_stmt);
|
||||
void emit_expr_method_pointer(const ast::expr_pointer::ptr& expr, const ast::expr& obj, const block::ptr& blk, bool is_stmt);
|
||||
void emit_expr_method_function(const ast::expr_function::ptr& expr, const ast::expr& obj, const block::ptr& blk, bool is_stmt);
|
||||
void emit_expr_add_array(const ast::expr_add_array::ptr& expr, const block::ptr& blk);
|
||||
void emit_expr_parameters(const ast::expr_parameters::ptr& expr, const block::ptr& blk);
|
||||
void emit_expr_arguments(const ast::expr_arguments::ptr& expr, const block::ptr& blk);
|
||||
void emit_expr_reference(const ast::expr_reference::ptr& expr, const block::ptr& blk);
|
||||
void emit_expr_size(const ast::expr_size::ptr& expr, const block::ptr& blk);
|
||||
void emit_expr_tuple(const ast::expr_tuple::ptr& expr, const block::ptr& blk);
|
||||
void emit_expr_variable_ref(const ast::expr& expr, const block::ptr& blk, bool set);
|
||||
void emit_expr_array_ref(const ast::expr_array::ptr& expr, const block::ptr& blk, bool set);
|
||||
void emit_expr_field_ref(const ast::expr_field::ptr& expr, const block::ptr& blk, bool set);
|
||||
void emit_expr_local_ref(const ast::expr_identifier::ptr& expr, const block::ptr& blk, bool set);
|
||||
void emit_expr_variable(const ast::expr& expr, const block::ptr& blk);
|
||||
void emit_expr_array(const ast::expr_array::ptr& expr, const block::ptr& blk);
|
||||
void emit_expr_field(const ast::expr_field::ptr& expr, const block::ptr& blk);
|
||||
void emit_expr_local(const ast::expr_identifier::ptr& expr, const block::ptr& blk);
|
||||
void emit_expr_object(const ast::expr& expr, const block::ptr& blk);
|
||||
void emit_expr_vector(const ast::expr_vector::ptr& expr, const block::ptr& blk);
|
||||
void emit_expr_animation(const ast::expr_animation::ptr& expr);
|
||||
void emit_expr_animtree(const ast::expr_animtree::ptr& expr);
|
||||
void emit_expr_istring(const ast::expr_istring::ptr& expr);
|
||||
void emit_expr_string(const ast::expr_string::ptr& expr);
|
||||
void emit_expr_float(const ast::expr_float::ptr& expr);
|
||||
void emit_expr_integer(const ast::expr_integer::ptr& expr);
|
||||
void emit_expr_false(const ast::expr_false::ptr& expr);
|
||||
void emit_expr_true(const ast::expr_true::ptr& expr);
|
||||
void emit_create_local_vars(const block::ptr& blk);
|
||||
void emit_remove_local_vars(const block::ptr& blk);
|
||||
void emit_opcode(opcode op);
|
||||
void emit_opcode(opcode op, const std::string& data);
|
||||
void emit_opcode(opcode op, const std::vector<std::string>& data);
|
||||
void process_thread(const ast::decl_thread::ptr& decl, const block::ptr& blk);
|
||||
void process_stmt(const ast::stmt& stmt, const block::ptr& blk);
|
||||
void process_stmt_list(const ast::stmt_list::ptr& stmt, const block::ptr& blk);
|
||||
void process_stmt_dev(const ast::stmt_dev::ptr& stmt, const block::ptr& blk);
|
||||
void process_stmt_expr(const ast::stmt_expr::ptr& stmt, const block::ptr& blk);
|
||||
void process_stmt_assign(const ast::stmt_assign::ptr& stmt, const block::ptr& blk);
|
||||
void process_stmt_waittill(const ast::stmt_waittill::ptr& stmt, const block::ptr& blk);
|
||||
void process_stmt_if(const ast::stmt_if::ptr& stmt, const block::ptr& blk);
|
||||
void process_stmt_ifelse(const ast::stmt_ifelse::ptr& stmt, const block::ptr& blk);
|
||||
void process_stmt_while(const ast::stmt_while::ptr& stmt, const block::ptr& blk);
|
||||
void process_stmt_dowhile(const ast::stmt_dowhile::ptr& stmt, const block::ptr& blk);
|
||||
void process_stmt_for(const ast::stmt_for::ptr& stmt, const block::ptr& blk);
|
||||
void process_stmt_foreach(const ast::stmt_foreach::ptr& stmt, const block::ptr& blk);
|
||||
void process_stmt_switch(const ast::stmt_switch::ptr& stmt, const block::ptr& blk);
|
||||
void process_stmt_break(const ast::stmt_break::ptr& stmt, const block::ptr& blk);
|
||||
void process_stmt_continue(const ast::stmt_continue::ptr& stmt, const block::ptr& blk);
|
||||
void process_stmt_return(const ast::stmt_return::ptr& stmt, const block::ptr& blk);
|
||||
void process_expr(const ast::expr& expr, const block::ptr& blk);
|
||||
void process_expr_tuple(const ast::expr_tuple::ptr& expr, const block::ptr& blk);
|
||||
void process_expr_parameters(const ast::expr_parameters::ptr& decl, const block::ptr& blk);
|
||||
void variable_register(const std::string& name, const block::ptr& blk);
|
||||
void variable_initialize(const ast::expr_identifier::ptr& name, const block::ptr& blk);
|
||||
void variable_create(const ast::expr_identifier::ptr& name, const block::ptr& blk);
|
||||
auto variable_stack_index(const ast::expr_identifier::ptr& name, const block::ptr& blk) -> std::uint8_t;
|
||||
auto variable_create_index(const ast::expr_identifier::ptr& name, const block::ptr& blk) -> std::string;
|
||||
auto variable_access_index(const ast::expr_identifier::ptr& name, const block::ptr& blk) -> std::string;
|
||||
auto variable_initialized(const ast::expr_identifier::ptr& name, const block::ptr& blk) -> bool;
|
||||
auto resolve_function_type(const ast::expr_function::ptr& expr) -> ast::call::type;
|
||||
auto resolve_reference_type(const ast::expr_reference::ptr& expr, bool& method) -> ast::call::type;
|
||||
auto is_constant_condition(const ast::expr& expr) -> bool;
|
||||
auto create_label() -> std::string;
|
||||
auto insert_label() -> std::string;
|
||||
void insert_label(const std::string& label);
|
||||
|
||||
auto map_known_includes(const std::string& include) -> bool;
|
||||
};
|
||||
|
||||
} // namespace xsk::gsc::s1c
|
@ -1,23 +0,0 @@
|
||||
// Copyright 2022 xensik. All rights reserved.
|
||||
//
|
||||
// Use of this source code is governed by a GNU GPLv3 license
|
||||
// that can be found in the LICENSE file.
|
||||
|
||||
#include "stdafx.hpp"
|
||||
#include "s1c.hpp"
|
||||
|
||||
namespace xsk::gsc::s1c
|
||||
{
|
||||
|
||||
void context::init(build mode, read_cb_type callback)
|
||||
{
|
||||
compiler_.mode(mode);
|
||||
resolver::init(callback);
|
||||
}
|
||||
|
||||
void context::cleanup()
|
||||
{
|
||||
resolver::cleanup();
|
||||
}
|
||||
|
||||
} // namespace xsk::gsc::s1c
|
@ -1,28 +0,0 @@
|
||||
// Copyright 2022 xensik. All rights reserved.
|
||||
//
|
||||
// Use of this source code is governed by a GNU GPLv3 license
|
||||
// that can be found in the LICENSE file.
|
||||
|
||||
#pragma once
|
||||
|
||||
namespace xsk::gsc::s1c
|
||||
{
|
||||
|
||||
class context : public gsc::context
|
||||
{
|
||||
s1c::assembler assembler_;
|
||||
s1c::disassembler disassembler_;
|
||||
s1c::compiler compiler_;
|
||||
s1c::decompiler decompiler_;
|
||||
|
||||
public:
|
||||
void init(build mode, read_cb_type callback);
|
||||
void cleanup();
|
||||
|
||||
auto assembler() -> gsc::assembler& { return assembler_; }
|
||||
auto disassembler() -> gsc::disassembler& { return disassembler_; }
|
||||
auto compiler() -> gsc::compiler& { return compiler_; }
|
||||
auto decompiler() -> gsc::decompiler& { return decompiler_; }
|
||||
};
|
||||
|
||||
} // namespace xsk::gsc::s1c
|
File diff suppressed because it is too large
Load Diff
@ -1,101 +0,0 @@
|
||||
// Copyright 2022 xensik. All rights reserved.
|
||||
//
|
||||
// Use of this source code is governed by a GNU GPLv3 license
|
||||
// that can be found in the LICENSE file.
|
||||
|
||||
#pragma once
|
||||
|
||||
namespace xsk::gsc::s1c
|
||||
{
|
||||
|
||||
class decompiler : public gsc::decompiler
|
||||
{
|
||||
std::string filename_;
|
||||
ast::program::ptr program_;
|
||||
ast::decl_thread::ptr func_;
|
||||
std::unordered_map<std::uint32_t, std::string> labels_;
|
||||
std::vector<std::string> expr_labels_;
|
||||
std::vector<std::string> tern_labels_;
|
||||
std::stack<ast::node::ptr> stack_;
|
||||
std::vector<block> blocks_;
|
||||
bool in_waittill_;
|
||||
|
||||
public:
|
||||
auto output() -> std::vector<std::uint8_t>;
|
||||
void decompile(const std::string& file, std::vector<function::ptr>& funcs);
|
||||
|
||||
private:
|
||||
void decompile_function(const function::ptr& func);
|
||||
void decompile_instruction(const instruction::ptr& inst);
|
||||
void decompile_expressions(const instruction::ptr& inst);
|
||||
void decompile_statements(const ast::stmt_list::ptr& stmt);
|
||||
void decompile_loops(const ast::stmt_list::ptr& stmt);
|
||||
void decompile_switches(const ast::stmt_list::ptr& stmt);
|
||||
void decompile_ifelses(const ast::stmt_list::ptr& stmt);
|
||||
void decompile_aborts(const ast::stmt_list::ptr& stmt);
|
||||
void decompile_tuples(const ast::stmt_list::ptr& stmt);
|
||||
void decompile_if(const ast::stmt_list::ptr& stmt, std::size_t begin, std::size_t end);
|
||||
void decompile_ifelse(const ast::stmt_list::ptr& stmt, std::size_t begin, std::size_t end);
|
||||
void decompile_ifelse_end(const ast::stmt_list::ptr& stmt, std::size_t begin, std::size_t end);
|
||||
void decompile_inf(const ast::stmt_list::ptr& stmt, std::size_t begin, std::size_t end);
|
||||
void decompile_loop(const ast::stmt_list::ptr& stmt, std::size_t begin, std::size_t end);
|
||||
void decompile_while(const ast::stmt_list::ptr& stmt, std::size_t begin, std::size_t end);
|
||||
void decompile_dowhile(const ast::stmt_list::ptr& stmt, std::size_t begin, std::size_t end);
|
||||
void decompile_for(const ast::stmt_list::ptr& stmt, std::size_t begin, std::size_t end);
|
||||
void decompile_foreach(const ast::stmt_list::ptr& stmt, std::size_t begin, std::size_t end);
|
||||
void decompile_switch(const ast::stmt_list::ptr& stmt, std::size_t begin);
|
||||
auto find_location_reference(const ast::stmt_list::ptr& stmt, std::size_t begin, std::size_t end, const std::string& location) -> bool;
|
||||
auto find_location_index(const ast::stmt_list::ptr& stmt, const std::string& location) -> std::size_t;
|
||||
auto last_location_index(const ast::stmt_list::ptr& stmt, std::size_t index) -> bool;
|
||||
void process_stack(const ast::decl_thread::ptr& thread);
|
||||
void process_parameters(const ast::expr_parameters::ptr& params, const block::ptr& blk);
|
||||
void process_stmt(const ast::stmt& stmt, const block::ptr& blk);
|
||||
void process_stmt_list(const ast::stmt_list::ptr& stmt, const block::ptr& blk);
|
||||
void process_stmt_expr(const ast::stmt_expr::ptr& stmt, const block::ptr& blk);
|
||||
void process_stmt_call(const ast::stmt_call::ptr& stmt, const block::ptr& blk);
|
||||
void process_stmt_assign(const ast::stmt_assign::ptr& stmt, const block::ptr& blk);
|
||||
void process_stmt_endon(const ast::stmt_endon::ptr& stmt, const block::ptr& blk);
|
||||
void process_stmt_notify(const ast::stmt_notify::ptr& stmt, const block::ptr& blk);
|
||||
void process_stmt_wait(const ast::stmt_wait::ptr& stmt, const block::ptr& blk);
|
||||
void process_stmt_waittill(const ast::stmt_waittill::ptr& stmt, const block::ptr& blk);
|
||||
void process_stmt_waittillmatch(const ast::stmt_waittillmatch::ptr& stmt, const block::ptr& blk);
|
||||
void process_stmt_if(const ast::stmt_if::ptr& stmt, const block::ptr& blk);
|
||||
void process_stmt_ifelse(const ast::stmt_ifelse::ptr& stmt, const block::ptr& blk);
|
||||
void process_stmt_while(const ast::stmt_while::ptr& stmt, const block::ptr& blk);
|
||||
void process_stmt_dowhile(const ast::stmt_dowhile::ptr& stmt, const block::ptr& blk);
|
||||
void process_stmt_for(const ast::stmt_for::ptr& stmt, const block::ptr& blk);
|
||||
void process_stmt_foreach(const ast::stmt_foreach::ptr& stmt, const block::ptr& blk);
|
||||
void process_stmt_switch(const ast::stmt_switch::ptr& stmt, const block::ptr& blk);
|
||||
void process_stmt_cases(const ast::stmt_list::ptr& stmt, const block::ptr& blk);
|
||||
void process_stmt_break(const ast::stmt_break::ptr& stmt, const block::ptr& blk);
|
||||
void process_stmt_continue(const ast::stmt_continue::ptr& stmt, const block::ptr& blk);
|
||||
void process_stmt_return(const ast::stmt_return::ptr& stmt, const block::ptr& blk);
|
||||
void process_expr(ast::expr& expr, const block::ptr& blk);
|
||||
void process_expr_assign(ast::expr_assign::ptr& expr, const block::ptr& blk);
|
||||
void process_expr_increment(const ast::expr_increment::ptr& expr, const block::ptr& blk);
|
||||
void process_expr_decrement(const ast::expr_decrement::ptr& expr, const block::ptr& blk);
|
||||
void process_expr_ternary(const ast::expr_ternary::ptr& expr, const block::ptr& blk);
|
||||
void process_expr_binary(const ast::expr_binary::ptr& expr, const block::ptr& blk);
|
||||
void process_expr_and(const ast::expr_and::ptr& expr, const block::ptr& blk);
|
||||
void process_expr_or(const ast::expr_or::ptr& expr, const block::ptr& blk);
|
||||
void process_expr_complement(const ast::expr_complement::ptr& expr, const block::ptr& blk);
|
||||
void process_expr_not(const ast::expr_not::ptr& expr, const block::ptr& blk);
|
||||
void process_expr_call(const ast::expr_call::ptr& expr, const block::ptr& blk);
|
||||
void process_expr_method(const ast::expr_method::ptr& expr, const block::ptr& blk);
|
||||
void process_expr_call_pointer(const ast::expr_pointer::ptr& expr, const block::ptr& blk);
|
||||
void process_expr_call_function(const ast::expr_function::ptr& expr, const block::ptr& blk);
|
||||
void process_expr_method_pointer(const ast::expr_pointer::ptr& expr, ast::expr& obj, const block::ptr& blk);
|
||||
void process_expr_method_function(const ast::expr_function::ptr& expr, ast::expr& obj, const block::ptr& blk);
|
||||
void process_expr_arguments(const ast::expr_arguments::ptr& expr, const block::ptr& blk);
|
||||
void process_expr_add_array(const ast::expr_add_array::ptr& expr, const block::ptr& blk);
|
||||
void process_expr_size(const ast::expr_size::ptr& expr, const block::ptr& blk);
|
||||
void process_expr_tuple(const ast::expr_tuple::ptr& expr, const block::ptr& blk);
|
||||
void process_expr_array(const ast::expr_array::ptr& expr, const block::ptr& blk);
|
||||
void process_expr_field(const ast::expr_field::ptr& expr, const block::ptr& blk);
|
||||
void process_expr_vector(const ast::expr_vector::ptr& vec, const block::ptr& blk);
|
||||
void process_var_create(ast::expr& expr, const block::ptr& blk, bool fromstmt = false);
|
||||
void process_var_access(ast::expr& expr, const block::ptr& blk);
|
||||
void process_var_remove(const ast::asm_remove::ptr& expr, const block::ptr& blk);
|
||||
};
|
||||
|
||||
} // namespace xsk::gsc::s1c
|
@ -1,576 +0,0 @@
|
||||
// Copyright 2022 xensik. All rights reserved.
|
||||
//
|
||||
// Use of this source code is governed by a GNU GPLv3 license
|
||||
// that can be found in the LICENSE file.
|
||||
|
||||
#include "stdafx.hpp"
|
||||
#include "s1c.hpp"
|
||||
|
||||
namespace xsk::gsc::s1c
|
||||
{
|
||||
|
||||
auto disassembler::output() -> std::vector<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("// S1 GSC ASSEMBLY\n");
|
||||
output_->write_string("// Disassembled by https://github.com/xensik/gsc-tool\n");
|
||||
|
||||
for (const auto& func : functions_)
|
||||
{
|
||||
print_function(func);
|
||||
}
|
||||
|
||||
std::vector<std::uint8_t> output;
|
||||
|
||||
output.resize(output_->pos());
|
||||
std::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<function>());
|
||||
const auto& func = functions_.back();
|
||||
|
||||
func->index = static_cast<std::uint32_t>(script_->pos());
|
||||
func->size = stack_->read_endian<std::uint32_t>();
|
||||
func->id = stack_->read_endian<std::uint16_t>();
|
||||
func->name = func->id == 0 ? stack_->read_c_string() : resolver::token_name(static_cast<std::uint16_t>(func->id));
|
||||
|
||||
dissasemble_function(func);
|
||||
|
||||
func->labels = labels_;
|
||||
labels_.clear();
|
||||
}
|
||||
|
||||
resolve_local_functions();
|
||||
}
|
||||
|
||||
void disassembler::dissasemble_function(const function::ptr& func)
|
||||
{
|
||||
auto size = func->size;
|
||||
|
||||
while (size > 0)
|
||||
{
|
||||
func->instructions.push_back(std::make_unique<instruction>());
|
||||
|
||||
const auto& inst = func->instructions.back();
|
||||
inst->index = static_cast<std::uint32_t>(script_->pos());
|
||||
inst->opcode = script_->read_endian<std::uint8_t>();
|
||||
inst->size = opcode_size(inst->opcode);
|
||||
|
||||
dissasemble_instruction(inst);
|
||||
|
||||
size -= inst->size;
|
||||
}
|
||||
}
|
||||
|
||||
void disassembler::dissasemble_instruction(const instruction::ptr& inst)
|
||||
{
|
||||
switch (static_cast<opcode>(inst->opcode))
|
||||
{
|
||||
case opcode::OP_Return:
|
||||
case opcode::OP_BoolNot:
|
||||
case opcode::OP_CastBool:
|
||||
case opcode::OP_inequality:
|
||||
case opcode::OP_GetThisthread:
|
||||
case opcode::OP_ClearLocalVariableFieldCached0:
|
||||
case opcode::OP_checkclearparams:
|
||||
case opcode::OP_CastFieldObject:
|
||||
case opcode::OP_End:
|
||||
case opcode::OP_size:
|
||||
case opcode::OP_EmptyArray:
|
||||
case opcode::OP_bit_and:
|
||||
case opcode::OP_less_equal:
|
||||
case opcode::OP_voidCodepos:
|
||||
// case opcode::OP_ClearVariableField:
|
||||
case opcode::OP_divide:
|
||||
case opcode::OP_GetSelf:
|
||||
case opcode::OP_SetLocalVariableFieldCached0:
|
||||
case opcode::OP_plus:
|
||||
case opcode::OP_BoolComplement:
|
||||
case opcode::OP_ScriptMethodCallPointer:
|
||||
case opcode::OP_inc:
|
||||
case opcode::OP_clearparams:
|
||||
case opcode::OP_EvalLocalVariableRefCached0:
|
||||
case opcode::OP_ScriptFunctionCallPointer:
|
||||
case opcode::OP_endon:
|
||||
case opcode::OP_greater_equal:
|
||||
case opcode::OP_GetSelfObject:
|
||||
case opcode::OP_SetVariableField:
|
||||
case opcode::OP_EvalLocalArrayRefCached0:
|
||||
case opcode::OP_less:
|
||||
case opcode::OP_GetGameRef:
|
||||
case opcode::OP_waittillFrameEnd:
|
||||
case opcode::OP_waitFrame:
|
||||
case opcode::OP_SafeSetVariableFieldCached0:
|
||||
case opcode::OP_GetLevel:
|
||||
case opcode::OP_notify:
|
||||
case opcode::OP_DecTop:
|
||||
case opcode::OP_shift_left:
|
||||
case opcode::OP_greater:
|
||||
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_GetZero:
|
||||
case opcode::OP_wait:
|
||||
case opcode::OP_minus:
|
||||
// case opcode::OP_EvalNewLocalVariableRefCached0:
|
||||
case opcode::OP_multiply:
|
||||
case opcode::OP_mod:
|
||||
case opcode::OP_GetGame:
|
||||
case opcode::OP_waittill:
|
||||
case opcode::OP_dec:
|
||||
case opcode::OP_PreScriptCall:
|
||||
case opcode::OP_GetAnim:
|
||||
case opcode::OP_GetUndefined:
|
||||
case opcode::OP_GetAnimObject:
|
||||
case opcode::OP_GetLevelObject:
|
||||
case opcode::OP_bit_ex_or:
|
||||
case opcode::OP_equality:
|
||||
case opcode::OP_ClearArray:
|
||||
case opcode::OP_EvalArrayRef:
|
||||
case opcode::OP_EvalArray:
|
||||
case opcode::OP_vector:
|
||||
case opcode::OP_bit_or:
|
||||
case opcode::OP_AddArray:
|
||||
case opcode::OP_waittillmatch2:
|
||||
case opcode::OP_shift_right:
|
||||
break;
|
||||
case opcode::OP_GetByte:
|
||||
case opcode::OP_GetNegByte:
|
||||
inst->data.push_back(utils::string::va("%i", script_->read_endian<std::uint8_t>()));
|
||||
break;
|
||||
case opcode::OP_GetUnsignedShort:
|
||||
case opcode::OP_GetNegUnsignedShort:
|
||||
inst->data.push_back(utils::string::va("%i", script_->read_endian<std::uint16_t>()));
|
||||
break;
|
||||
case opcode::OP_GetInteger:
|
||||
inst->data.push_back(utils::string::va("%i", script_->read_endian<std::int32_t>()));
|
||||
break;
|
||||
case opcode::OP_GetFloat:
|
||||
inst->data.push_back(utils::string::float_string(script_->read_endian<float>()));
|
||||
break;
|
||||
case opcode::OP_GetVector:
|
||||
inst->size += script_->align(4);
|
||||
inst->data.push_back(utils::string::float_string(script_->read_endian<float>()));
|
||||
inst->data.push_back(utils::string::float_string(script_->read_endian<float>()));
|
||||
inst->data.push_back(utils::string::float_string(script_->read_endian<float>()));
|
||||
break;
|
||||
case opcode::OP_GetString:
|
||||
case opcode::OP_GetIString:
|
||||
script_->seek(2);
|
||||
inst->data.push_back(utils::string::to_literal(stack_->read_c_string()));
|
||||
break;
|
||||
case opcode::OP_GetAnimation:
|
||||
script_->seek(4);
|
||||
inst->data.push_back(utils::string::quote(stack_->read_c_string(), false));
|
||||
inst->data.push_back(utils::string::quote(stack_->read_c_string(), false));
|
||||
break;
|
||||
case opcode::OP_GetAnimTree:
|
||||
script_->seek(1);
|
||||
inst->data.push_back(utils::string::quote(stack_->read_c_string(), false));
|
||||
break;
|
||||
case opcode::OP_waittillmatch:
|
||||
inst->data.push_back(utils::string::va("%i", script_->read_endian<std::uint8_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_endian<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:
|
||||
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_endian<std::uint8_t>()));
|
||||
break;
|
||||
case opcode::OP_GetLocalFunction:
|
||||
case opcode::OP_ScriptLocalFunctionCall2:
|
||||
case opcode::OP_ScriptLocalFunctionCall:
|
||||
case opcode::OP_ScriptLocalMethodCall:
|
||||
disassemble_local_call(inst, false);
|
||||
break;
|
||||
case opcode::OP_ScriptLocalThreadCall:
|
||||
case opcode::OP_ScriptLocalChildThreadCall:
|
||||
case opcode::OP_ScriptLocalMethodThreadCall:
|
||||
case opcode::OP_ScriptLocalMethodChildThreadCall:
|
||||
disassemble_local_call(inst, true);
|
||||
break;
|
||||
case opcode::OP_GetFarFunction:
|
||||
case opcode::OP_ScriptFarFunctionCall2:
|
||||
case opcode::OP_ScriptFarFunctionCall:
|
||||
case opcode::OP_ScriptFarMethodCall:
|
||||
disassemble_far_call(inst, false);
|
||||
break;
|
||||
case opcode::OP_ScriptFarThreadCall:
|
||||
case opcode::OP_ScriptFarChildThreadCall:
|
||||
case opcode::OP_ScriptFarMethodThreadCall:
|
||||
case opcode::OP_ScriptFarMethodChildThreadCall:
|
||||
disassemble_far_call(inst, true);
|
||||
break;
|
||||
case opcode::OP_CallBuiltin:
|
||||
disassemble_builtin_call(inst, false, true);
|
||||
break;
|
||||
case opcode::OP_CallBuiltinMethod:
|
||||
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:
|
||||
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:
|
||||
disassemble_builtin_call(inst, true, false);
|
||||
break;
|
||||
case opcode::OP_JumpOnFalse:
|
||||
case opcode::OP_JumpOnTrue:
|
||||
case opcode::OP_JumpOnFalseExpr:
|
||||
case opcode::OP_JumpOnTrueExpr:
|
||||
disassemble_jump(inst, true, false);
|
||||
break;
|
||||
case opcode::OP_jumpback:
|
||||
disassemble_jump(inst, false, true);
|
||||
break;
|
||||
case opcode::OP_jump:
|
||||
disassemble_jump(inst, false, false);
|
||||
break;
|
||||
case opcode::OP_switch:
|
||||
disassemble_switch(inst);
|
||||
break;
|
||||
case opcode::OP_endswitch:
|
||||
disassemble_end_switch(inst);
|
||||
break;
|
||||
default:
|
||||
throw disasm_error(utils::string::va("unhandled opcode 0x%X at index '%04X'!", inst->opcode, inst->index));
|
||||
}
|
||||
}
|
||||
|
||||
void disassembler::disassemble_builtin_call(const instruction::ptr& inst, bool method, bool args)
|
||||
{
|
||||
if (args)
|
||||
{
|
||||
inst->data.push_back(utils::string::va("%i", script_->read_endian<std::uint8_t>()));
|
||||
}
|
||||
|
||||
const auto id = script_->read_endian<std::uint16_t>();
|
||||
const auto name = method ? resolver::method_name(id) : resolver::function_name(id);
|
||||
inst->data.emplace(inst->data.begin(), name);
|
||||
}
|
||||
|
||||
void disassembler::disassemble_local_call(const instruction::ptr& inst, bool thread)
|
||||
{
|
||||
const auto offset = 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_endian<std::uint8_t>()));
|
||||
}
|
||||
}
|
||||
|
||||
void disassembler::disassemble_far_call(const instruction::ptr& inst, bool thread)
|
||||
{
|
||||
script_->seek(3);
|
||||
|
||||
if (thread)
|
||||
{
|
||||
inst->data.push_back(utils::string::va("%i", script_->read_endian<std::uint8_t>()));
|
||||
}
|
||||
|
||||
const auto file_id = stack_->read_endian<std::uint16_t>();
|
||||
const auto file_name = file_id == 0 ? stack_->read_c_string() : resolver::token_name(file_id);
|
||||
const auto func_id = stack_->read_endian<std::uint16_t>();
|
||||
const auto func_name = func_id == 0 ? stack_->read_c_string() : resolver::token_name(func_id);
|
||||
|
||||
inst->data.emplace(inst->data.begin(), func_name);
|
||||
inst->data.emplace(inst->data.begin(), file_name);
|
||||
}
|
||||
|
||||
void disassembler::disassemble_switch(const instruction::ptr& inst)
|
||||
{
|
||||
const auto addr = inst->index + 4 + script_->read_endian<std::int32_t>();
|
||||
const auto label = utils::string::va("loc_%X", addr);
|
||||
|
||||
inst->data.push_back(label);
|
||||
labels_.insert({ addr, label });
|
||||
}
|
||||
|
||||
void disassembler::disassemble_end_switch(const instruction::ptr& inst)
|
||||
{
|
||||
const auto count = script_->read_endian<std::uint16_t>();
|
||||
inst->data.push_back(utils::string::va("%i", count));
|
||||
|
||||
std::uint32_t index = inst->index + 3;
|
||||
|
||||
if (count)
|
||||
{
|
||||
for (auto i = count; i > 0; i--)
|
||||
{
|
||||
const auto value = script_->read_endian<std::uint32_t>();
|
||||
|
||||
if (value < 0x40000)
|
||||
{
|
||||
const auto data = stack_->read_c_string();
|
||||
|
||||
if (data.data()[0] != 0x01)
|
||||
{
|
||||
inst->data.push_back("case");
|
||||
inst->data.push_back(utils::string::quote(data, false));
|
||||
}
|
||||
else
|
||||
inst->data.push_back("default");
|
||||
}
|
||||
else
|
||||
{
|
||||
inst->data.push_back("case");
|
||||
inst->data.push_back(utils::string::va("%i", (value - 0x800000) & 0xFFFFFF));
|
||||
}
|
||||
|
||||
index += 4;
|
||||
|
||||
const auto addr = disassemble_offset() + index;
|
||||
const auto label = utils::string::va("loc_%X", addr);
|
||||
|
||||
inst->data.push_back(label);
|
||||
labels_.insert({ addr, label });
|
||||
|
||||
index += 3;
|
||||
inst->size += 7;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void disassembler::disassemble_field_variable(const instruction::ptr& inst)
|
||||
{
|
||||
const auto id = script_->read_endian<std::uint16_t>();
|
||||
std::string name;
|
||||
|
||||
if (id > max_string_id)
|
||||
{
|
||||
auto temp = stack_->read_endian<std::uint16_t>();
|
||||
name = temp == 0 ? stack_->read_c_string() : std::to_string(temp);
|
||||
}
|
||||
else
|
||||
{
|
||||
name = resolver::token_name(id);
|
||||
}
|
||||
|
||||
inst->data.push_back(name);
|
||||
}
|
||||
|
||||
void disassembler::disassemble_jump(const instruction::ptr& inst, bool expr, bool back)
|
||||
{
|
||||
std::int32_t addr;
|
||||
|
||||
if (expr)
|
||||
{
|
||||
addr = inst->index + 3 + script_->read_endian<std::int16_t>();
|
||||
}
|
||||
else if (back)
|
||||
{
|
||||
addr = inst->index + 3 - script_->read_endian<std::uint16_t>();
|
||||
}
|
||||
else
|
||||
{
|
||||
addr = inst->index + 5 + script_->read_endian<std::int32_t>();
|
||||
}
|
||||
|
||||
const auto label = utils::string::va("loc_%X", addr);
|
||||
|
||||
inst->data.push_back(label);
|
||||
labels_.insert({ addr, label });
|
||||
}
|
||||
|
||||
auto disassembler::disassemble_offset() -> std::int32_t
|
||||
{
|
||||
std::array<std::uint8_t, 4> bytes = {};
|
||||
|
||||
for (auto i = 0; i < 3; i++)
|
||||
{
|
||||
bytes[2 - i] = script_->read_endian<std::uint8_t>();
|
||||
}
|
||||
|
||||
auto offset = *reinterpret_cast<std::int32_t*>(bytes.data());
|
||||
|
||||
offset = (offset << 8) >> 10;
|
||||
|
||||
return offset;
|
||||
}
|
||||
|
||||
void disassembler::resolve_local_functions()
|
||||
{
|
||||
for (const auto& func : functions_)
|
||||
{
|
||||
for (const auto& inst : func->instructions)
|
||||
{
|
||||
switch (static_cast<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[0] = 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 (const auto& func : functions_)
|
||||
{
|
||||
if (func->index == idx)
|
||||
{
|
||||
return func->name;
|
||||
}
|
||||
}
|
||||
|
||||
throw disasm_error(utils::string::va("couldn't resolve function name at index '0x%04X'!", idx));
|
||||
}
|
||||
|
||||
throw disasm_error(utils::string::va("\"%s\" is not valid function address!", index.data()));
|
||||
}
|
||||
|
||||
void disassembler::print_function(const function::ptr& func)
|
||||
{
|
||||
output_->write_string("\n");
|
||||
output_->write_string(utils::string::va("sub_%s\n", func->name.data()));
|
||||
|
||||
for (const auto& inst : func->instructions)
|
||||
{
|
||||
const auto itr = func->labels.find(inst->index);
|
||||
|
||||
if (itr != func->labels.end())
|
||||
{
|
||||
output_->write_string(utils::string::va("\t%s\n", itr->second.data()));
|
||||
}
|
||||
|
||||
print_instruction(inst);
|
||||
}
|
||||
|
||||
output_->write_string(utils::string::va("end_%s\n", func->name.data()));
|
||||
}
|
||||
|
||||
void disassembler::print_instruction(const instruction::ptr& inst)
|
||||
{
|
||||
output_->write_string(utils::string::va("\t\t%s", resolver::opcode_name(inst->opcode).data()));
|
||||
|
||||
switch (static_cast<opcode>(inst->opcode))
|
||||
{
|
||||
case opcode::OP_GetLocalFunction:
|
||||
case opcode::OP_ScriptLocalFunctionCall:
|
||||
case opcode::OP_ScriptLocalFunctionCall2:
|
||||
case opcode::OP_ScriptLocalMethodCall:
|
||||
output_->write_string(utils::string::va(" sub_%s", inst->data[0].data()));
|
||||
break;
|
||||
case opcode::OP_ScriptLocalThreadCall:
|
||||
case opcode::OP_ScriptLocalChildThreadCall:
|
||||
case opcode::OP_ScriptLocalMethodThreadCall:
|
||||
case opcode::OP_ScriptLocalMethodChildThreadCall:
|
||||
output_->write_string(utils::string::va(" sub_%s %s\n", inst->data[0].data(), inst->data[1].data()));
|
||||
break;
|
||||
case opcode::OP_endswitch:
|
||||
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:
|
||||
for (auto& data : inst->data)
|
||||
{
|
||||
output_->write_string(utils::string::va(" %s", data.data()));
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
output_->write_string("\n");
|
||||
}
|
||||
|
||||
} // namespace xsk::gsc::s1c
|
@ -1,42 +0,0 @@
|
||||
// Copyright 2022 xensik. All rights reserved.
|
||||
//
|
||||
// Use of this source code is governed by a GNU GPLv3 license
|
||||
// that can be found in the LICENSE file.
|
||||
|
||||
#pragma once
|
||||
|
||||
namespace xsk::gsc::s1c
|
||||
{
|
||||
|
||||
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<function::ptr> functions_;
|
||||
std::unordered_map<std::uint32_t, std::string> labels_;
|
||||
|
||||
public:
|
||||
auto output() -> std::vector<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 function::ptr& func);
|
||||
void dissasemble_instruction(const instruction::ptr& inst);
|
||||
void disassemble_builtin_call(const instruction::ptr& inst, bool method, bool args);
|
||||
void disassemble_local_call(const instruction::ptr& inst, bool thread);
|
||||
void disassemble_far_call(const instruction::ptr& inst, bool thread);
|
||||
void disassemble_switch(const instruction::ptr& inst);
|
||||
void disassemble_end_switch(const instruction::ptr& inst);
|
||||
void disassemble_field_variable(const instruction::ptr& inst);
|
||||
void disassemble_jump(const instruction::ptr& inst, bool expr, bool back);
|
||||
auto disassemble_offset() -> std::int32_t;
|
||||
void resolve_local_functions();
|
||||
auto resolve_function(const std::string& index) -> std::string;
|
||||
void print_function(const function::ptr& func);
|
||||
void print_instruction(const instruction::ptr& inst);
|
||||
};
|
||||
|
||||
} // namespace xsk::gsc::s1c
|
@ -1,849 +0,0 @@
|
||||
// Copyright 2022 xensik. All rights reserved.
|
||||
//
|
||||
// Use of this source code is governed by a GNU GPLv3 license
|
||||
// that can be found in the LICENSE file.
|
||||
|
||||
#include "stdafx.hpp"
|
||||
#include "s1c.hpp"
|
||||
#include "parser.hpp"
|
||||
#include "lexer.hpp"
|
||||
|
||||
xsk::gsc::s1c::parser::symbol_type S1Clex(xsk::gsc::s1c::lexer& lexer)
|
||||
{
|
||||
return lexer.lex();
|
||||
}
|
||||
|
||||
namespace xsk::gsc::s1c
|
||||
{
|
||||
|
||||
const std::unordered_map<std::string_view, parser::token::token_kind_type> keyword_map
|
||||
{{
|
||||
{ "#define", parser::token::SH_DEFINE },
|
||||
{ "#undef", parser::token::SH_UNDEF },
|
||||
{ "#ifdef", parser::token::SH_IFDEF },
|
||||
{ "#ifndef", parser::token::SH_IFNDEF },
|
||||
{ "#if", parser::token::SH_IF },
|
||||
{ "#elif", parser::token::SH_ELIF },
|
||||
{ "#else", parser::token::SH_ELSE },
|
||||
{ "#endif", parser::token::SH_ENDIF },
|
||||
{ "#inline", parser::token::INLINE },
|
||||
{ "#include", parser::token::INCLUDE },
|
||||
{ "#using_animtree", parser::token::USINGTREE },
|
||||
{ "#animtree", parser::token::ANIMTREE },
|
||||
{ "endon", parser::token::ENDON },
|
||||
{ "notify", parser::token::NOTIFY },
|
||||
{ "wait", parser::token::WAIT },
|
||||
{ "waittill", parser::token::WAITTILL },
|
||||
{ "waittillmatch", parser::token::WAITTILLMATCH },
|
||||
{ "waittillframeend", parser::token::WAITTILLFRAMEEND },
|
||||
{ "waitframe", parser::token::WAITFRAME },
|
||||
{ "if", parser::token::IF },
|
||||
{ "else", parser::token::ELSE },
|
||||
{ "do", parser::token::DO },
|
||||
{ "while", parser::token::WHILE },
|
||||
{ "for", parser::token::FOR },
|
||||
{ "foreach", parser::token::FOREACH },
|
||||
{ "in", parser::token::IN },
|
||||
{ "switch", parser::token::SWITCH },
|
||||
{ "case", parser::token::CASE },
|
||||
{ "default", parser::token::DEFAULT },
|
||||
{ "break", parser::token::BREAK },
|
||||
{ "continue", parser::token::CONTINUE },
|
||||
{ "return", parser::token::RETURN },
|
||||
{ "breakpoint", parser::token::BREAKPOINT },
|
||||
{ "prof_begin", parser::token::PROFBEGIN },
|
||||
{ "prof_end", parser::token::PROFEND },
|
||||
{ "thread", parser::token::THREAD },
|
||||
{ "childthread", parser::token::CHILDTHREAD },
|
||||
{ "thisthread", parser::token::THISTHREAD },
|
||||
{ "call", parser::token::CALL },
|
||||
{ "true", parser::token::TRUE },
|
||||
{ "false", parser::token::FALSE },
|
||||
{ "undefined", parser::token::UNDEFINED },
|
||||
{ "size", parser::token::SIZE },
|
||||
{ "game", parser::token::GAME },
|
||||
{ "self", parser::token::SELF },
|
||||
{ "anim", parser::token::ANIM },
|
||||
{ "level", parser::token::LEVEL },
|
||||
}};
|
||||
|
||||
buffer::buffer() : length(0)
|
||||
{
|
||||
data = static_cast<char*>(std::malloc(max_buf_size));
|
||||
}
|
||||
|
||||
buffer::~buffer()
|
||||
{
|
||||
if (data) std::free(data);
|
||||
}
|
||||
|
||||
bool buffer::push(char c)
|
||||
{
|
||||
if (length >= max_buf_size)
|
||||
return false;
|
||||
|
||||
data[length++] = c;
|
||||
return true;
|
||||
}
|
||||
|
||||
reader::reader() : buffer_pos(0), bytes_remaining(0), last_byte(0), current_byte(0), state(reader::end)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
void reader::init(const char* data, size_t size)
|
||||
{
|
||||
if (data && size)
|
||||
{
|
||||
state = reader::ok;
|
||||
buffer_pos = data;
|
||||
bytes_remaining = static_cast<std::uint32_t>(size);
|
||||
last_byte = 0;
|
||||
current_byte = *data;
|
||||
}
|
||||
else
|
||||
{
|
||||
state = reader::end;
|
||||
buffer_pos = 0;
|
||||
bytes_remaining = 0;
|
||||
last_byte = 0;
|
||||
current_byte = 0;
|
||||
}
|
||||
}
|
||||
|
||||
void reader::advance()
|
||||
{
|
||||
++buffer_pos;
|
||||
|
||||
if (bytes_remaining-- == 1)
|
||||
{
|
||||
state = reader::end;
|
||||
bytes_remaining = 0;
|
||||
last_byte = current_byte;
|
||||
current_byte = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
last_byte = current_byte;
|
||||
current_byte = *buffer_pos;
|
||||
}
|
||||
}
|
||||
|
||||
lexer::lexer(build mode, const std::string& name, const char* data, size_t size) : loc_(location(&name)),
|
||||
locs_(std::stack<location>()), readers_(std::stack<reader>()), header_top_(0), mode_(mode), indev_(false), clean_(true)
|
||||
{
|
||||
reader_.init(data, size);
|
||||
}
|
||||
|
||||
void lexer::push_header(const std::string& file)
|
||||
{
|
||||
try
|
||||
{
|
||||
if (header_top_++ >= 10)
|
||||
throw comp_error(loc_, "maximum gsh depth exceeded '10'");
|
||||
|
||||
auto data = resolver::file_data(file + ".gsh");
|
||||
|
||||
readers_.push(reader_);
|
||||
locs_.push(loc_);
|
||||
loc_.initialize(std::get<0>(data));
|
||||
reader_.init(std::get<1>(data), std::get<2>(data));
|
||||
clean_ = true;
|
||||
}
|
||||
catch (const std::exception& e)
|
||||
{
|
||||
throw error("parsing header file '" + file + "': " + e.what());
|
||||
}
|
||||
}
|
||||
|
||||
void lexer::pop_header()
|
||||
{
|
||||
header_top_--;
|
||||
loc_ = locs_.top();
|
||||
locs_.pop();
|
||||
reader_ = readers_.top();
|
||||
readers_.pop();
|
||||
}
|
||||
|
||||
void lexer::ban_header(const location& loc)
|
||||
{
|
||||
if (header_top_ > 0)
|
||||
{
|
||||
throw comp_error(loc, "not allowed inside a gsh file");
|
||||
}
|
||||
}
|
||||
|
||||
auto lexer::lex() -> parser::symbol_type
|
||||
{
|
||||
buffer_.length = 0;
|
||||
state_ = state::start;
|
||||
|
||||
while (true)
|
||||
{
|
||||
const auto& state = reader_.state;
|
||||
auto& last = reader_.last_byte;
|
||||
auto& curr = reader_.current_byte;
|
||||
auto path = false;
|
||||
loc_.step();
|
||||
|
||||
if (state == reader::end)
|
||||
{
|
||||
if (indev_)
|
||||
throw comp_error(loc_, "unmatched devblock start ('/#')");
|
||||
|
||||
if (header_top_ > 0)
|
||||
pop_header();
|
||||
else
|
||||
return parser::make_S1CEOF(loc_);
|
||||
}
|
||||
|
||||
if (clean_ && last != 0 && last != ' ' && last != '\t' && last != '\n')
|
||||
clean_ = false;
|
||||
|
||||
advance();
|
||||
|
||||
switch (last)
|
||||
{
|
||||
case ' ':
|
||||
case '\t':
|
||||
case '\r':
|
||||
loc_.step();
|
||||
continue;
|
||||
case '\n':
|
||||
loc_.lines();
|
||||
loc_.step();
|
||||
clean_ = true;
|
||||
continue;
|
||||
case '\\':
|
||||
throw comp_error(loc_, "invalid token ('\\')");
|
||||
case '/':
|
||||
if (curr != '=' && curr != '#' && curr != '@' && curr != '*' && curr != '/')
|
||||
return parser::make_DIV(loc_);
|
||||
|
||||
advance();
|
||||
|
||||
if (last == '=')
|
||||
return parser::make_ASSIGN_DIV(loc_);
|
||||
|
||||
if (last == '#')
|
||||
{
|
||||
if (indev_)
|
||||
throw comp_error(loc_, "cannot recurse devblock ('/#')");
|
||||
|
||||
if (mode_ == build::dev)
|
||||
{
|
||||
indev_ = true;
|
||||
return parser::make_DEVBEGIN(loc_);
|
||||
}
|
||||
else
|
||||
{
|
||||
while (true)
|
||||
{
|
||||
if (state == reader::end)
|
||||
throw comp_error(loc_, "unmatched devblock start ('/#')");
|
||||
|
||||
if (curr == '\n')
|
||||
{
|
||||
loc_.lines();
|
||||
loc_.step();
|
||||
}
|
||||
else if (last == '#' && curr == '/')
|
||||
{
|
||||
advance();
|
||||
break;
|
||||
}
|
||||
|
||||
advance();
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (last == '@')
|
||||
{
|
||||
while (true)
|
||||
{
|
||||
if (state == reader::end)
|
||||
throw comp_error(loc_, "unmatched script doc comment start ('/@')");
|
||||
|
||||
if (curr == '\n')
|
||||
{
|
||||
loc_.lines();
|
||||
loc_.step();
|
||||
}
|
||||
else if (last == '@' && curr == '/')
|
||||
{
|
||||
advance();
|
||||
break;
|
||||
}
|
||||
|
||||
advance();
|
||||
}
|
||||
}
|
||||
else if (last == '*')
|
||||
{
|
||||
while (true)
|
||||
{
|
||||
if (state == reader::end)
|
||||
throw comp_error(loc_, "unmatched multiline comment start ('/*')");
|
||||
|
||||
if (curr == '\n')
|
||||
{
|
||||
loc_.lines();
|
||||
loc_.step();
|
||||
}
|
||||
else if (last == '*' && curr == '/')
|
||||
{
|
||||
advance();
|
||||
break;
|
||||
}
|
||||
|
||||
advance();
|
||||
}
|
||||
}
|
||||
else if (last == '/')
|
||||
{
|
||||
while (true)
|
||||
{
|
||||
if (state == reader::end)
|
||||
break;
|
||||
|
||||
if (curr == '\n')
|
||||
break;
|
||||
|
||||
advance();
|
||||
}
|
||||
}
|
||||
continue;
|
||||
case '#':
|
||||
if (curr == '/')
|
||||
{
|
||||
if (!indev_)
|
||||
throw comp_error(loc_, "unmatched devblock end ('#/')");
|
||||
|
||||
advance();
|
||||
indev_ = false;
|
||||
return parser::make_DEVEND(loc_);
|
||||
}
|
||||
|
||||
buffer_.push(last);
|
||||
advance();
|
||||
|
||||
while (state == reader::ok)
|
||||
{
|
||||
if (last != ' ' || last != '\t')
|
||||
break;
|
||||
|
||||
advance();
|
||||
}
|
||||
|
||||
if (state == reader::end || !((last > 64 && last < 91) || (last > 96 && last < 123)))
|
||||
throw comp_error(loc_, "invalid preprocessor directive ('#')");
|
||||
|
||||
state_ = state::preprocessor;
|
||||
goto lex_name;
|
||||
case '*':
|
||||
if (curr != '=' && curr != '/')
|
||||
return parser::make_MUL(loc_);
|
||||
|
||||
advance();
|
||||
|
||||
if (last == '=')
|
||||
return parser::make_ASSIGN_MUL(loc_);
|
||||
|
||||
throw comp_error(loc_, "unmatched multiline comment end ('*/')");
|
||||
case '"':
|
||||
state_ = state::string;
|
||||
goto lex_string;
|
||||
case '.':
|
||||
if (curr < '0' || curr > '9')
|
||||
return parser::make_DOT(loc_);
|
||||
goto lex_number;
|
||||
case '(':
|
||||
return parser::make_LPAREN(loc_);
|
||||
case ')':
|
||||
return parser::make_RPAREN(loc_);
|
||||
case '{':
|
||||
return parser::make_LBRACE(loc_);
|
||||
case '}':
|
||||
return parser::make_RBRACE(loc_);
|
||||
case '[':
|
||||
return parser::make_LBRACKET(loc_);
|
||||
case ']':
|
||||
return parser::make_RBRACKET(loc_);
|
||||
case ',':
|
||||
return parser::make_COMMA(loc_);
|
||||
case ';':
|
||||
return parser::make_SEMICOLON(loc_);
|
||||
case ':':
|
||||
if (curr != ':')
|
||||
return parser::make_COLON(loc_);
|
||||
|
||||
advance();
|
||||
return parser::make_DOUBLECOLON(loc_);
|
||||
case '?':
|
||||
return parser::make_QMARK(loc_);
|
||||
case '=':
|
||||
if (curr != '=')
|
||||
return parser::make_ASSIGN(loc_);
|
||||
|
||||
advance();
|
||||
return parser::make_EQUALITY(loc_);
|
||||
case '+':
|
||||
if (curr != '+' && curr != '=')
|
||||
return parser::make_ADD(loc_);
|
||||
|
||||
advance();
|
||||
|
||||
if (last == '+')
|
||||
return parser::make_INCREMENT(loc_);
|
||||
|
||||
return parser::make_ASSIGN_ADD(loc_);
|
||||
case '-':
|
||||
if (curr != '-' && curr != '=')
|
||||
return parser::make_SUB(loc_);
|
||||
|
||||
advance();
|
||||
|
||||
if (last == '-')
|
||||
return parser::make_DECREMENT(loc_);
|
||||
|
||||
return parser::make_ASSIGN_SUB(loc_);
|
||||
case '%':
|
||||
if (curr != '=')
|
||||
return parser::make_MOD(loc_);
|
||||
|
||||
advance();
|
||||
|
||||
return parser::make_ASSIGN_MOD(loc_);
|
||||
case '|':
|
||||
if (curr != '|' && curr != '=')
|
||||
return parser::make_BITWISE_OR(loc_);
|
||||
|
||||
advance();
|
||||
|
||||
if (last == '|')
|
||||
return parser::make_OR(loc_);
|
||||
|
||||
return parser::make_ASSIGN_BW_OR(loc_);
|
||||
case '&':
|
||||
if (curr != '&' && curr != '=' && curr != '"')
|
||||
return parser::make_BITWISE_AND(loc_);
|
||||
|
||||
advance();
|
||||
|
||||
if (last == '&')
|
||||
return parser::make_AND(loc_);
|
||||
|
||||
if (last == '=')
|
||||
return parser::make_ASSIGN_BW_AND(loc_);
|
||||
|
||||
state_ = state::localize;
|
||||
goto lex_string;
|
||||
case '^':
|
||||
if (curr != '=')
|
||||
return parser::make_BITWISE_EXOR(loc_);
|
||||
|
||||
advance();
|
||||
return parser::make_ASSIGN_BW_EXOR(loc_);
|
||||
case '!':
|
||||
if (curr != '=')
|
||||
return parser::make_NOT(loc_);
|
||||
|
||||
advance();
|
||||
return parser::make_INEQUALITY(loc_);
|
||||
case '~':
|
||||
return parser::make_COMPLEMENT(loc_);
|
||||
case '<':
|
||||
if (curr != '<' && curr != '=')
|
||||
return parser::make_LESS(loc_);
|
||||
|
||||
advance();
|
||||
if (last == '=')
|
||||
return parser::make_LESS_EQUAL(loc_);
|
||||
|
||||
if (curr != '=')
|
||||
return parser::make_LSHIFT(loc_);
|
||||
|
||||
advance();
|
||||
return parser::make_ASSIGN_LSHIFT(loc_);
|
||||
case '>':
|
||||
if (curr != '>' && curr != '=')
|
||||
return parser::make_GREATER(loc_);
|
||||
|
||||
advance();
|
||||
|
||||
if (last == '=')
|
||||
return parser::make_GREATER_EQUAL(loc_);
|
||||
|
||||
if (curr != '=')
|
||||
return parser::make_RSHIFT(loc_);
|
||||
|
||||
advance();
|
||||
return parser::make_ASSIGN_RSHIFT(loc_);
|
||||
default:
|
||||
if (last >= '0' && last <= '9')
|
||||
goto lex_number;
|
||||
else if (last == '_' || (last >= 'A' && last <= 'Z') || (last >= 'a' && last <= 'z'))
|
||||
goto lex_name;
|
||||
|
||||
throw comp_error(loc_, utils::string::va("bad token: \'%c\'", last));
|
||||
}
|
||||
|
||||
lex_string:
|
||||
while (true)
|
||||
{
|
||||
if (state == reader::end)
|
||||
throw comp_error(loc_, "unmatched string start ('\"')");
|
||||
|
||||
if (curr == '"')
|
||||
{
|
||||
advance();
|
||||
break;
|
||||
}
|
||||
|
||||
if (curr == '\n')
|
||||
throw comp_error(loc_, "unterminated string literal");
|
||||
|
||||
if (curr == '\\')
|
||||
{
|
||||
advance();
|
||||
|
||||
if (state == reader::end)
|
||||
throw comp_error(loc_, "invalid token ('\')");
|
||||
|
||||
char c = curr;
|
||||
switch (curr)
|
||||
{
|
||||
case 't': c = '\t'; break;
|
||||
case 'r': c = '\r'; break;
|
||||
case 'n': c = '\n'; break;
|
||||
case '"': c = '\"'; break;
|
||||
case '\\': c = '\\'; break;
|
||||
default: break;
|
||||
}
|
||||
|
||||
if (!buffer_.push(c))
|
||||
throw comp_error(loc_, "max string size exceeded");
|
||||
}
|
||||
else if (!buffer_.push(curr))
|
||||
throw comp_error(loc_, "max string size exceeded");
|
||||
|
||||
advance();
|
||||
}
|
||||
|
||||
if (state_ == state::localize)
|
||||
return parser::make_ISTRING(std::string(buffer_.data, buffer_.length), loc_);
|
||||
|
||||
return parser::make_STRING(std::string(buffer_.data, buffer_.length), loc_);
|
||||
|
||||
lex_name:
|
||||
buffer_.push(last);
|
||||
|
||||
while (true)
|
||||
{
|
||||
if (state == reader::end)
|
||||
break;
|
||||
|
||||
if (!(curr == '\\' || curr == '_' || (curr > 64 && curr < 91) || (curr > 96 && curr < 123) || (curr > 47 && curr < 58)))
|
||||
break;
|
||||
|
||||
if (curr == '\\')
|
||||
{
|
||||
if (last == '\\')
|
||||
throw comp_error(loc_, "invalid path '\\\\'");
|
||||
|
||||
path = true;
|
||||
if (!buffer_.push('/'))
|
||||
throw comp_error(loc_, "max string size exceeded");
|
||||
}
|
||||
else if (!buffer_.push(curr))
|
||||
throw comp_error(loc_, "max string size exceeded");
|
||||
|
||||
advance();
|
||||
}
|
||||
|
||||
if (state_ == state::preprocessor)
|
||||
{
|
||||
auto token = parser::token::S1CUNDEF;
|
||||
|
||||
if (buffer_.length < 16)
|
||||
{
|
||||
const auto itr = keyword_map.find(std::string_view(buffer_.data, buffer_.length));
|
||||
|
||||
if (itr != keyword_map.end())
|
||||
{
|
||||
if (itr->second > parser::token::SH_ENDIF)
|
||||
return parser::symbol_type(itr->second, loc_);
|
||||
|
||||
token = itr->second;
|
||||
}
|
||||
}
|
||||
|
||||
preprocessor_run(token);
|
||||
|
||||
state_ = state::start;
|
||||
continue;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (buffer_.length < 17)
|
||||
{
|
||||
const auto itr = keyword_map.find(std::string_view(buffer_.data, buffer_.length));
|
||||
|
||||
if (itr != keyword_map.end())
|
||||
return parser::symbol_type(itr->second, loc_);
|
||||
}
|
||||
|
||||
if (path)
|
||||
{
|
||||
if (buffer_.data[buffer_.length - 1] == '/')
|
||||
throw comp_error(loc_, "invalid path end '\\'");
|
||||
|
||||
return parser::make_PATH(resolver::make_token(std::string_view(buffer_.data, buffer_.length)), loc_);
|
||||
}
|
||||
|
||||
return parser::make_IDENTIFIER(resolver::make_token(std::string_view(buffer_.data, buffer_.length)), loc_);
|
||||
}
|
||||
|
||||
lex_number:
|
||||
if (last == '.' || last != '0' || (last == '0' && (curr != 'o' && curr != 'b' && curr != 'x')))
|
||||
{
|
||||
buffer_.push(last);
|
||||
|
||||
auto dot = last == '.' ? 1 : 0;
|
||||
auto flt = 0;
|
||||
|
||||
while (true)
|
||||
{
|
||||
if (state == reader::end)
|
||||
break;
|
||||
|
||||
if (curr == '\'' && (last == '\'' || last == 'f' || last == '.'))
|
||||
throw comp_error(loc_, "invalid number literal");
|
||||
|
||||
if ((curr == '.' || curr == 'f') && last == '\'')
|
||||
throw comp_error(loc_, "invalid number literal");
|
||||
|
||||
if (curr == '\'')
|
||||
{
|
||||
advance();
|
||||
continue;
|
||||
}
|
||||
|
||||
if (curr == 'f')
|
||||
flt++;
|
||||
else if (curr == '.')
|
||||
dot++;
|
||||
else if (!(curr > 47 && curr < 58))
|
||||
break;
|
||||
|
||||
if (!buffer_.push(curr))
|
||||
throw comp_error(loc_, "number literal size exceeded");
|
||||
|
||||
advance();
|
||||
}
|
||||
|
||||
if (last == '\'')
|
||||
throw comp_error(loc_, "invalid number literal");
|
||||
|
||||
if (dot > 1 || flt > 1 || (flt && buffer_.data[buffer_.length - 1] != 'f'))
|
||||
throw comp_error(loc_, "invalid number literal");
|
||||
|
||||
if (dot || flt)
|
||||
return parser::make_FLOAT(std::string(buffer_.data, buffer_.length), loc_);
|
||||
|
||||
return parser::make_INTEGER(std::string(buffer_.data, buffer_.length), loc_);
|
||||
}
|
||||
else if (curr == 'o')
|
||||
{
|
||||
advance();
|
||||
|
||||
while (true)
|
||||
{
|
||||
if (state == reader::end)
|
||||
break;
|
||||
|
||||
if ((curr == '\'' && (last == '\'' || last == 'o')) || (curr == 'o' && last == '\''))
|
||||
throw comp_error(loc_, "invalid octal literal");
|
||||
|
||||
if (curr == '\'')
|
||||
{
|
||||
advance();
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!(curr > 47 && curr < 56))
|
||||
break;
|
||||
|
||||
if (!buffer_.push(curr))
|
||||
throw error("gsc lexer: out of memory!");
|
||||
|
||||
advance();
|
||||
}
|
||||
|
||||
if (last == '\'' || buffer_.length <= 0)
|
||||
throw comp_error(loc_, "invalid octal literal");
|
||||
|
||||
return parser::make_INTEGER(utils::string::oct_to_dec(buffer_.data), loc_);
|
||||
}
|
||||
else if (curr == 'b')
|
||||
{
|
||||
buffer_.push(last);
|
||||
buffer_.push(curr);
|
||||
advance();
|
||||
|
||||
while (true)
|
||||
{
|
||||
if (state == reader::end)
|
||||
break;
|
||||
|
||||
if ((curr == '\'' && (last == '\'' || last == 'b')) || (curr == 'b' && last == '\''))
|
||||
throw comp_error(loc_, "invalid binary literal");
|
||||
|
||||
if (curr == '\'')
|
||||
{
|
||||
advance();
|
||||
continue;
|
||||
}
|
||||
|
||||
if (curr != '0' && curr != '1')
|
||||
break;
|
||||
|
||||
if (!buffer_.push(curr))
|
||||
throw comp_error(loc_, "number literal size exceeded");
|
||||
|
||||
advance();
|
||||
}
|
||||
|
||||
if (last == '\'' || buffer_.length < 3)
|
||||
throw comp_error(loc_, "invalid binary literal");
|
||||
|
||||
return parser::make_INTEGER(utils::string::bin_to_dec(buffer_.data), loc_);
|
||||
}
|
||||
else if (curr == 'x')
|
||||
{
|
||||
buffer_.push(last);
|
||||
buffer_.push(curr);
|
||||
advance();
|
||||
|
||||
while (true)
|
||||
{
|
||||
if (state == reader::end)
|
||||
break;
|
||||
|
||||
if ((curr == '\'' && (last == '\'' || last == 'x')) || (curr == 'x' && last == '\''))
|
||||
throw comp_error(loc_, "invalid hexadecimal literal");
|
||||
|
||||
if (curr == '\'')
|
||||
{
|
||||
advance();
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!((curr > 47 && curr < 58) || (curr > 64 && curr < 71) || (curr > 96 && curr < 103)))
|
||||
break;
|
||||
|
||||
if (!buffer_.push(curr))
|
||||
throw error("gsc lexer: out of memory!");
|
||||
|
||||
advance();
|
||||
}
|
||||
|
||||
if (last == '\'' || buffer_.length < 3)
|
||||
throw comp_error(loc_, "invalid hexadecimal literal");
|
||||
|
||||
return parser::make_INTEGER(utils::string::hex_to_dec(buffer_.data), loc_);
|
||||
}
|
||||
|
||||
throw error("UNEXPECTED LEXER INTERNAL ERROR!");
|
||||
}
|
||||
}
|
||||
|
||||
void lexer::advance()
|
||||
{
|
||||
reader_.advance();
|
||||
loc_.end.column++;
|
||||
|
||||
if (reader_.current_byte == '\\') [[unlikely]]
|
||||
preprocessor_wrap();
|
||||
}
|
||||
|
||||
void lexer::preprocessor_wrap()
|
||||
{
|
||||
while (reader_.current_byte == '\\')
|
||||
{
|
||||
if (reader_.bytes_remaining == 1)
|
||||
throw comp_error(loc_, "invalid token ('\\')");
|
||||
|
||||
if (reader_.buffer_pos[1] != '\r' && reader_.buffer_pos[1] != '\n')
|
||||
break;
|
||||
|
||||
if (reader_.buffer_pos[1] == '\r')
|
||||
{
|
||||
if (reader_.bytes_remaining <= 3 || reader_.buffer_pos[2] != '\n')
|
||||
throw comp_error(loc_, "invalid token ('\\')");
|
||||
|
||||
reader_.buffer_pos += 3;
|
||||
reader_.bytes_remaining -= 3;
|
||||
}
|
||||
|
||||
if ((reader_.buffer_pos[1] == '\n'))
|
||||
{
|
||||
if (reader_.bytes_remaining == 2)
|
||||
throw comp_error(loc_, "invalid token ('\\')");
|
||||
|
||||
reader_.buffer_pos += 2;
|
||||
reader_.bytes_remaining -= 2;
|
||||
}
|
||||
|
||||
if (reader_.bytes_remaining == 0)
|
||||
{
|
||||
reader_.state = reader::end;
|
||||
reader_.current_byte = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
reader_.current_byte = *reader_.buffer_pos;
|
||||
}
|
||||
|
||||
loc_.lines();
|
||||
loc_.step();
|
||||
}
|
||||
}
|
||||
|
||||
void lexer::preprocessor_run(parser::token::token_kind_type token)
|
||||
{
|
||||
if (!clean_)
|
||||
throw comp_error(loc_, "invalid token ('#')");
|
||||
|
||||
switch (token)
|
||||
{
|
||||
case parser::token::SH_DEFINE:
|
||||
throw comp_error(loc_, "unimplemented preprocessor directive");
|
||||
break;
|
||||
case parser::token::SH_UNDEF:
|
||||
throw comp_error(loc_, "unimplemented preprocessor directive");
|
||||
break;
|
||||
case parser::token::SH_IFDEF:
|
||||
throw comp_error(loc_, "unimplemented preprocessor directive");
|
||||
break;
|
||||
case parser::token::SH_IFNDEF:
|
||||
throw comp_error(loc_, "unimplemented preprocessor directive");
|
||||
break;
|
||||
case parser::token::SH_IF:
|
||||
throw comp_error(loc_, "unimplemented preprocessor directive");
|
||||
break;
|
||||
case parser::token::SH_ELIF:
|
||||
throw comp_error(loc_, "unimplemented preprocessor directive");
|
||||
break;
|
||||
case parser::token::SH_ELSE:
|
||||
throw comp_error(loc_, "unimplemented preprocessor directive");
|
||||
break;
|
||||
case parser::token::SH_ENDIF:
|
||||
throw comp_error(loc_, "unimplemented preprocessor directive");
|
||||
break;
|
||||
default:
|
||||
throw comp_error(loc_, "unknown preprocessor directive");
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace xsk::gsc::s1c
|
@ -1,78 +0,0 @@
|
||||
// Copyright 2022 xensik. All rights reserved.
|
||||
//
|
||||
// Use of this source code is governed by a GNU GPLv3 license
|
||||
// that can be found in the LICENSE file.
|
||||
|
||||
#pragma once
|
||||
|
||||
namespace xsk::gsc::s1c
|
||||
{
|
||||
|
||||
constexpr size_t max_buf_size = 0x2000;
|
||||
|
||||
struct buffer
|
||||
{
|
||||
char* data;
|
||||
size_t length;
|
||||
|
||||
buffer();
|
||||
~buffer();
|
||||
bool push(char c);
|
||||
};
|
||||
|
||||
struct reader
|
||||
{
|
||||
enum state_type : std::uint8_t { end, ok };
|
||||
|
||||
const char* buffer_pos;
|
||||
std::uint32_t bytes_remaining;
|
||||
char last_byte;
|
||||
char current_byte;
|
||||
state_type state;
|
||||
|
||||
reader();
|
||||
|
||||
reader(const reader& obj)
|
||||
{
|
||||
std::memcpy(this, &obj, sizeof(reader));
|
||||
}
|
||||
|
||||
reader& operator=(const reader& obj)
|
||||
{
|
||||
std::memcpy(this, &obj, sizeof(reader));
|
||||
return *this;
|
||||
}
|
||||
|
||||
void init(const char* data, size_t size);
|
||||
void advance();
|
||||
};
|
||||
|
||||
class lexer
|
||||
{
|
||||
enum class state : std::uint8_t { start, string, localize, preprocessor };
|
||||
|
||||
reader reader_;
|
||||
buffer buffer_;
|
||||
location loc_;
|
||||
std::stack<location> locs_;
|
||||
std::stack<reader> readers_;
|
||||
std::uint32_t header_top_;
|
||||
state state_;
|
||||
build mode_;
|
||||
bool indev_;
|
||||
bool clean_;
|
||||
|
||||
public:
|
||||
lexer(build mode, const std::string& name, const char* data, size_t size);
|
||||
auto lex() -> parser::symbol_type;
|
||||
void push_header(const std::string& file);
|
||||
void pop_header();
|
||||
void ban_header(const location& loc);
|
||||
|
||||
private:
|
||||
void advance();
|
||||
void preprocessor_wrap();
|
||||
void preprocessor_run(parser::token::token_kind_type token);
|
||||
};
|
||||
|
||||
} // namespace xsk::gsc::s1c
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@ -1,520 +0,0 @@
|
||||
// Copyright 2022 xensik. All rights reserved.
|
||||
//
|
||||
// Use of this source code is governed by a GNU GPLv3 license
|
||||
// that can be found in the LICENSE file.
|
||||
|
||||
#include "stdafx.hpp"
|
||||
#include "s1c.hpp"
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#pragma warning(push)
|
||||
#pragma warning(disable:4244)
|
||||
#endif
|
||||
|
||||
namespace xsk::gsc::s1c
|
||||
{
|
||||
|
||||
std::unordered_map<std::uint8_t, std::string_view> opcode_map;
|
||||
std::unordered_map<std::uint16_t, std::string_view> function_map;
|
||||
std::unordered_map<std::uint16_t, std::string_view> method_map;
|
||||
std::unordered_map<std::uint16_t, std::string_view> token_map;
|
||||
std::unordered_map<std::string_view, std::uint8_t> opcode_map_rev;
|
||||
std::unordered_map<std::string_view, std::uint16_t> function_map_rev;
|
||||
std::unordered_map<std::string_view, std::uint16_t> method_map_rev;
|
||||
std::unordered_map<std::string_view, std::uint16_t> token_map_rev;
|
||||
std::unordered_map<std::string, std::vector<std::uint8_t>> files;
|
||||
read_cb_type read_callback = nullptr;
|
||||
std::set<std::string> string_map;
|
||||
|
||||
void resolver::init(read_cb_type callback)
|
||||
{
|
||||
read_callback = callback;
|
||||
}
|
||||
|
||||
void resolver::cleanup()
|
||||
{
|
||||
files.clear();
|
||||
}
|
||||
|
||||
auto resolver::opcode_id(const std::string& name) -> std::uint8_t
|
||||
{
|
||||
const auto itr = opcode_map_rev.find(name);
|
||||
|
||||
if (itr != opcode_map_rev.end())
|
||||
{
|
||||
return itr->second;
|
||||
}
|
||||
|
||||
throw error(utils::string::va("couldn't resolve opcode id for name '%s'!", name.data()));
|
||||
}
|
||||
|
||||
auto resolver::opcode_name(std::uint8_t id) -> std::string
|
||||
{
|
||||
const auto itr = opcode_map.find(id);
|
||||
|
||||
if (itr != opcode_map.end())
|
||||
{
|
||||
return std::string(itr->second);
|
||||
}
|
||||
|
||||
throw 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
|
||||
{
|
||||
if (name.starts_with("_func_"))
|
||||
{
|
||||
return static_cast<std::uint16_t>(std::stoul(name.substr(6), nullptr, 16));
|
||||
}
|
||||
|
||||
const auto itr = function_map_rev.find(name);
|
||||
|
||||
if (itr != function_map_rev.end())
|
||||
{
|
||||
return itr->second;
|
||||
}
|
||||
|
||||
throw 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 std::string(itr->second);
|
||||
}
|
||||
|
||||
return utils::string::va("_func_%04X", id);
|
||||
}
|
||||
|
||||
auto resolver::method_id(const std::string& name) -> std::uint16_t
|
||||
{
|
||||
if (name.starts_with("_meth_"))
|
||||
{
|
||||
return static_cast<std::uint16_t>(std::stoul(name.substr(6), nullptr, 16));
|
||||
}
|
||||
|
||||
const auto itr = method_map_rev.find(name);
|
||||
|
||||
if (itr != method_map_rev.end())
|
||||
{
|
||||
return itr->second;
|
||||
}
|
||||
|
||||
throw 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 std::string(itr->second);
|
||||
}
|
||||
|
||||
return utils::string::va("_meth_%04X", id);
|
||||
}
|
||||
|
||||
auto resolver::token_id(const std::string& name) -> std::uint16_t
|
||||
{
|
||||
if (name.starts_with("_id_"))
|
||||
{
|
||||
return static_cast<std::uint16_t>(std::stoul(name.substr(4), nullptr, 16));
|
||||
}
|
||||
|
||||
const auto itr = token_map_rev.find(name);
|
||||
|
||||
if (itr != token_map_rev.end())
|
||||
{
|
||||
return itr->second;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
auto resolver::token_name(std::uint16_t id) -> std::string
|
||||
{
|
||||
const auto itr = token_map.find(id);
|
||||
|
||||
if (itr != token_map.end())
|
||||
{
|
||||
return std::string(itr->second);
|
||||
}
|
||||
|
||||
return utils::string::va("_id_%04X", id);
|
||||
}
|
||||
|
||||
auto resolver::find_function(const std::string& name) -> bool
|
||||
{
|
||||
if (name.starts_with("_func_")) return true;
|
||||
|
||||
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
|
||||
{
|
||||
if (name.starts_with("_meth_")) return true;
|
||||
|
||||
const auto itr = method_map_rev.find(name);
|
||||
|
||||
if (itr != method_map_rev.end())
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void resolver::add_function(const std::string& name, std::uint16_t id)
|
||||
{
|
||||
const auto itr = function_map_rev.find(name);
|
||||
|
||||
if (itr != function_map_rev.end())
|
||||
{
|
||||
throw error(utils::string::va("builtin function '%s' already defined.", name.data()));
|
||||
}
|
||||
|
||||
const auto str = string_map.find(name);
|
||||
|
||||
if (str != string_map.end())
|
||||
{
|
||||
function_map.insert({ id, *str });
|
||||
function_map_rev.insert({ *str, id });
|
||||
}
|
||||
else
|
||||
{
|
||||
auto ins = string_map.insert(name);
|
||||
|
||||
if (ins.second)
|
||||
{
|
||||
function_map.insert({ id, *ins.first });
|
||||
function_map_rev.insert({ *ins.first, id });
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void resolver::add_method(const std::string& name, std::uint16_t id)
|
||||
{
|
||||
const auto itr = method_map_rev.find(name);
|
||||
|
||||
if (itr != method_map_rev.end())
|
||||
{
|
||||
throw error(utils::string::va("builtin method '%s' already defined.", name.data()));
|
||||
}
|
||||
|
||||
const auto str = string_map.find(name);
|
||||
|
||||
if (str != string_map.end())
|
||||
{
|
||||
method_map.insert({ id, *str });
|
||||
method_map_rev.insert({ *str, id });
|
||||
}
|
||||
else
|
||||
{
|
||||
auto ins = string_map.insert(name);
|
||||
|
||||
if (ins.second)
|
||||
{
|
||||
method_map.insert({ id, *ins.first });
|
||||
method_map_rev.insert({ *ins.first, id });
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
auto resolver::make_token(std::string_view str) -> std::string
|
||||
{
|
||||
if (str.starts_with("_id_") || str.starts_with("_func_") || str.starts_with("_meth_"))
|
||||
{
|
||||
return std::string(str);
|
||||
}
|
||||
|
||||
auto data = std::string(str.begin(), str.end());
|
||||
|
||||
for (std::size_t i = 0; i < data.size(); i++)
|
||||
{
|
||||
data[i] = static_cast<char>(std::tolower(static_cast<unsigned char>(str[i])));
|
||||
if (data[i] == '\\') data[i] = '/';
|
||||
}
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
auto resolver::file_data(const std::string& name) -> std::tuple<const std::string*, const char*, size_t>
|
||||
{
|
||||
const auto itr = files.find(name);
|
||||
|
||||
if (itr != files.end())
|
||||
{
|
||||
return { &itr->first ,reinterpret_cast<const char*>(itr->second.data()), itr->second.size() };
|
||||
}
|
||||
|
||||
auto data = read_callback(name);
|
||||
|
||||
const auto res = files.insert({ name, std::move(data)});
|
||||
|
||||
if (res.second)
|
||||
{
|
||||
return { &res.first->first, reinterpret_cast<const char*>(res.first->second.data()), res.first->second.size() };
|
||||
}
|
||||
|
||||
throw error("couldn't open gsc file '" + name + "'");
|
||||
}
|
||||
|
||||
std::set<std::string_view> paths
|
||||
{
|
||||
};
|
||||
|
||||
auto resolver::fs_to_game_path(const std::filesystem::path& file) -> std::filesystem::path
|
||||
{
|
||||
auto result = std::filesystem::path();
|
||||
auto root = false;
|
||||
|
||||
for (auto& entry : file)
|
||||
{
|
||||
if (!root && paths.contains(entry.string()))
|
||||
{
|
||||
result = entry;
|
||||
root = true;
|
||||
}
|
||||
else if (paths.contains(result.string()))
|
||||
{
|
||||
result /= entry;
|
||||
}
|
||||
}
|
||||
|
||||
return result.empty() ? file : result;
|
||||
}
|
||||
|
||||
const std::array<std::pair<std::uint8_t, const char*>, 154> opcode_list
|
||||
{{
|
||||
{ 0x1D, "OP_CastFieldObject" },
|
||||
{ 0x1E, "OP_SetLocalVariableFieldCached" },
|
||||
{ 0x1F, "OP_plus" },
|
||||
{ 0x20, "OP_RemoveLocalVariables" },
|
||||
{ 0x21, "OP_EvalSelfFieldVariableRef" },
|
||||
{ 0x22, "OP_ScriptFarMethodChildThreadCall" },
|
||||
{ 0x23, "OP_GetGameRef" },
|
||||
{ 0x24, "OP_EvalAnimFieldVariable" },
|
||||
{ 0x25, "OP_EvalLevelFieldVariableRef" },
|
||||
{ 0x26, "OP_GetThisthread" },
|
||||
{ 0x27, "OP_greater" },
|
||||
{ 0x28, "OP_waittillmatch" },
|
||||
{ 0x29, "OP_shift_right" },
|
||||
{ 0x2A, "OP_dec" },
|
||||
{ 0x2B, "OP_JumpOnTrue" },
|
||||
{ 0x2C, "OP_bit_or" },
|
||||
{ 0x2D, "OP_equality" },
|
||||
{ 0x2E, "OP_ClearLocalVariableFieldCached0" },
|
||||
{ 0x2F, "OP_notify" },
|
||||
{ 0x30, "OP_GetVector" },
|
||||
{ 0x31, "OP_ScriptMethodChildThreadCallPointer" },
|
||||
{ 0x32, "OP_PreScriptCall" },
|
||||
{ 0x33, "OP_GetByte" },
|
||||
{ 0x34, "OP_ScriptFarThreadCall" },
|
||||
{ 0x35, "OP_SetSelfFieldVariableField" },
|
||||
{ 0x36, "OP_JumpOnFalseExpr" },
|
||||
{ 0x37, "OP_GetUndefined" },
|
||||
{ 0x38, "OP_jumpback" },
|
||||
{ 0x39, "OP_JumpOnTrueExpr" },
|
||||
{ 0x3A, "OP_CallBuiltin0" },
|
||||
{ 0x3B, "OP_CallBuiltin1" },
|
||||
{ 0x3C, "OP_CallBuiltin2" },
|
||||
{ 0x3D, "OP_CallBuiltin3" },
|
||||
{ 0x3E, "OP_CallBuiltin4" },
|
||||
{ 0x3F, "OP_CallBuiltin5" },
|
||||
{ 0x40, "OP_CallBuiltin" },
|
||||
{ 0x41, "OP_SetLocalVariableFieldCached0" },
|
||||
{ 0x42, "OP_ClearFieldVariable" },
|
||||
{ 0x43, "OP_GetLevel" },
|
||||
{ 0x44, "OP_size" },
|
||||
{ 0x45, "OP_SafeSetWaittillVariableFieldCached" },
|
||||
{ 0x46, "OP_ScriptLocalMethodThreadCall" },
|
||||
{ 0x47, "OP_AddArray" },
|
||||
{ 0x48, "OP_endon" },
|
||||
{ 0x49, "OP_EvalFieldVariable" },
|
||||
{ 0x4A, "OP_shift_left" },
|
||||
{ 0x4B, "OP_EvalLocalArrayRefCached0" },
|
||||
{ 0x4C, "OP_Return" },
|
||||
{ 0x4D, "OP_CreateLocalVariable" },
|
||||
{ 0x4E, "OP_SafeSetVariableFieldCached0" },
|
||||
{ 0x4F, "OP_GetBuiltinMethod" },
|
||||
{ 0x50, "OP_ScriptLocalMethodCall" },
|
||||
{ 0x51, "OP_CallBuiltinMethodPointer" },
|
||||
{ 0x52, "OP_ScriptLocalChildThreadCall" },
|
||||
{ 0x53, "OP_GetSelfObject" },
|
||||
{ 0x54, "OP_GetGame" },
|
||||
{ 0x55, "OP_SetLevelFieldVariableField" },
|
||||
{ 0x56, "OP_EvalArray" },
|
||||
{ 0x57, "OP_GetSelf" },
|
||||
{ 0x58, "OP_End" },
|
||||
{ 0x59, "OP_EvalSelfFieldVariable" },
|
||||
{ 0x5A, "OP_less_equal" },
|
||||
{ 0x5B, "OP_EvalLocalVariableCached0" },
|
||||
{ 0x5C, "OP_EvalLocalVariableCached1" },
|
||||
{ 0x5D, "OP_EvalLocalVariableCached2" },
|
||||
{ 0x5E, "OP_EvalLocalVariableCached3" },
|
||||
{ 0x5F, "OP_EvalLocalVariableCached4" },
|
||||
{ 0x60, "OP_EvalLocalVariableCached5" },
|
||||
{ 0x61, "OP_EvalLocalVariableCached" },
|
||||
{ 0x62, "OP_EvalNewLocalArrayRefCached0" },
|
||||
{ 0x63, "OP_ScriptChildThreadCallPointer" },
|
||||
{ 0x64, "OP_EvalLocalVariableObjectCached" },
|
||||
{ 0x65, "OP_ScriptLocalThreadCall" },
|
||||
{ 0x66, "OP_GetInteger" },
|
||||
{ 0x67, "OP_ScriptMethodCallPointer" },
|
||||
{ 0x68, "OP_checkclearparams" },
|
||||
{ 0x69, "OP_SetAnimFieldVariableField" },
|
||||
{ 0x6A, "OP_waittillmatch2" },
|
||||
{ 0x6B, "OP_minus" },
|
||||
{ 0x6C, "OP_ScriptLocalFunctionCall2" },
|
||||
{ 0x6D, "OP_GetNegUnsignedShort" },
|
||||
{ 0x6E, "OP_GetNegByte" },
|
||||
{ 0x6F, "OP_SafeCreateVariableFieldCached" },
|
||||
{ 0x70, "OP_greater_equal" },
|
||||
{ 0x71, "OP_vector" },
|
||||
{ 0x72, "OP_GetBuiltinFunction" },
|
||||
{ 0x73, "OP_endswitch" },
|
||||
{ 0x74, "OP_ClearArray" },
|
||||
{ 0x75, "OP_DecTop" },
|
||||
{ 0x76, "OP_CastBool" },
|
||||
{ 0x77, "OP_EvalArrayRef" },
|
||||
{ 0x78, "OP_SetNewLocalVariableFieldCached0" },
|
||||
{ 0x79, "OP_GetZero" },
|
||||
{ 0x7A, "OP_wait" },
|
||||
{ 0x7B, "OP_waittill" },
|
||||
{ 0x7C, "OP_GetIString" },
|
||||
{ 0x7D, "OP_ScriptFarFunctionCall" },
|
||||
{ 0x7E, "OP_GetAnimObject" },
|
||||
{ 0x7F, "OP_GetAnimTree" },
|
||||
{ 0x80, "OP_EvalLocalArrayCached" },
|
||||
{ 0x81, "OP_mod" },
|
||||
{ 0x82, "OP_ScriptFarMethodThreadCall" },
|
||||
{ 0x83, "OP_GetUnsignedShort" },
|
||||
{ 0x84, "OP_clearparams" },
|
||||
{ 0x85, "OP_ScriptMethodThreadCallPointer" },
|
||||
{ 0x86, "OP_ScriptFunctionCallPointer" },
|
||||
{ 0x87, "OP_EmptyArray" },
|
||||
{ 0x88, "OP_SafeSetVariableFieldCached" },
|
||||
{ 0x89, "OP_UNK_2" },
|
||||
{ 0x8A, "OP_EvalFieldVariableRef" },
|
||||
{ 0x8B, "OP_ScriptLocalMethodChildThreadCall" },
|
||||
{ 0x8C, "OP_UNK_3" },
|
||||
{ 0x8D, "OP_GetFloat" },
|
||||
{ 0x8E, "OP_EvalLocalVariableRefCached" },
|
||||
{ 0x8F, "OP_JumpOnFalse" },
|
||||
{ 0x90, "OP_BoolComplement" },
|
||||
{ 0x91, "OP_ScriptThreadCallPointer" },
|
||||
{ 0x92, "OP_ScriptFarFunctionCall2" },
|
||||
{ 0x93, "OP_less" },
|
||||
{ 0x94, "OP_BoolNot" },
|
||||
{ 0x95, "OP_waittillFrameEnd" },
|
||||
{ 0x96, "OP_waitFrame" },
|
||||
{ 0x97, "OP_GetString" },
|
||||
{ 0x98, "OP_EvalLevelFieldVariable" },
|
||||
{ 0x99, "OP_GetLevelObject" },
|
||||
{ 0x9A, "OP_inc" },
|
||||
{ 0x9B, "OP_CallBuiltinMethod0" },
|
||||
{ 0x9C, "OP_CallBuiltinMethod1" },
|
||||
{ 0x9D, "OP_CallBuiltinMethod2" },
|
||||
{ 0x9E, "OP_CallBuiltinMethod3" },
|
||||
{ 0x9F, "OP_CallBuiltinMethod4" },
|
||||
{ 0xA0, "OP_CallBuiltinMethod5" },
|
||||
{ 0xA1, "OP_CallBuiltinMethod" },
|
||||
{ 0xA2, "OP_GetAnim" },
|
||||
{ 0xA3, "OP_switch" },
|
||||
{ 0xA4, "OP_SetVariableField" },
|
||||
{ 0xA5, "OP_divide" },
|
||||
{ 0xA6, "OP_GetLocalFunction" },
|
||||
{ 0xA7, "OP_ScriptFarChildThreadCall" },
|
||||
{ 0xA8, "OP_multiply" },
|
||||
{ 0xA9, "OP_ClearLocalVariableFieldCached" },
|
||||
{ 0xAA, "OP_EvalAnimFieldVariableRef" },
|
||||
{ 0xAB, "OP_EvalLocalArrayRefCached" },
|
||||
{ 0xAC, "OP_EvalLocalVariableRefCached0" },
|
||||
{ 0xAD, "OP_bit_and" },
|
||||
{ 0xAE, "OP_GetAnimation" },
|
||||
{ 0xAF, "OP_GetFarFunction" },
|
||||
{ 0xB0, "OP_CallBuiltinPointer" },
|
||||
{ 0xB1, "OP_jump" },
|
||||
{ 0xB2, "OP_voidCodepos" },
|
||||
{ 0xB3, "OP_ScriptFarMethodCall" },
|
||||
{ 0xB4, "OP_inequality" },
|
||||
{ 0xB5, "OP_ScriptLocalFunctionCall" },
|
||||
{ 0xB6, "OP_bit_ex_or" },
|
||||
}};
|
||||
|
||||
const std::array<std::pair<std::uint16_t, const char*>, 3> function_list
|
||||
{{
|
||||
{ 0x12, "isdefined" },
|
||||
{ 0xC0, "getfirstarraykey" },
|
||||
{ 0xC1, "getnextarraykey" },
|
||||
}};
|
||||
|
||||
const std::array<std::pair<std::uint16_t, const char*>, 0> method_list
|
||||
{{
|
||||
}};
|
||||
|
||||
const std::array<std::pair<std::uint16_t, const char*>, 0> token_list
|
||||
{{
|
||||
}};
|
||||
|
||||
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());
|
||||
token_map.reserve(token_list.size());
|
||||
token_map_rev.reserve(token_list.size());
|
||||
|
||||
for (const auto& entry : opcode_list)
|
||||
{
|
||||
opcode_map.insert({ entry.first, entry.second });
|
||||
opcode_map_rev.insert({ entry.second, entry.first });
|
||||
}
|
||||
|
||||
for (const auto& entry : function_list)
|
||||
{
|
||||
function_map.insert({ entry.first, entry.second });
|
||||
function_map_rev.insert({ entry.second, entry.first });
|
||||
}
|
||||
|
||||
for (const auto& entry : method_list)
|
||||
{
|
||||
method_map.insert({ entry.first, entry.second });
|
||||
method_map_rev.insert({ entry.second, entry.first });
|
||||
}
|
||||
|
||||
for (const auto& entry : token_list)
|
||||
{
|
||||
token_map.insert({ entry.first, entry.second });
|
||||
token_map_rev.insert({ entry.second, entry.first });
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
__init__ _;
|
||||
|
||||
} // namespace xsk::gsc::s1c
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#pragma warning(pop)
|
||||
#endif
|
@ -1,40 +0,0 @@
|
||||
// Copyright 2022 xensik. All rights reserved.
|
||||
//
|
||||
// Use of this source code is governed by a GNU GPLv3 license
|
||||
// that can be found in the LICENSE file.
|
||||
|
||||
#pragma once
|
||||
|
||||
namespace xsk::gsc::s1c
|
||||
{
|
||||
|
||||
class resolver
|
||||
{
|
||||
public:
|
||||
static void init(read_cb_type callback);
|
||||
static void cleanup();
|
||||
|
||||
static auto opcode_id(const std::string& name) -> std::uint8_t;
|
||||
static auto opcode_name(std::uint8_t id) -> std::string;
|
||||
|
||||
static auto 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 token_id(const std::string& name) -> std::uint16_t;
|
||||
static auto token_name(std::uint16_t id) -> std::string;
|
||||
|
||||
static auto find_function(const std::string& name) -> bool;
|
||||
static auto find_method(const std::string& name) -> bool;
|
||||
|
||||
static void add_function(const std::string& name, std::uint16_t id);
|
||||
static void add_method(const std::string& name, std::uint16_t id);
|
||||
|
||||
static auto make_token(std::string_view str) -> std::string;
|
||||
static auto file_data(const std::string& name) -> std::tuple<const std::string*, const char*, size_t>;
|
||||
static auto fs_to_game_path(const std::filesystem::path& file) -> std::filesystem::path;
|
||||
};
|
||||
|
||||
} // namespace xsk::gsc::s1c
|
@ -1,181 +0,0 @@
|
||||
// Copyright 2022 xensik. All rights reserved.
|
||||
//
|
||||
// Use of this source code is governed by a GNU GPLv3 license
|
||||
// that can be found in the LICENSE file.
|
||||
|
||||
#include "stdafx.hpp"
|
||||
#include "s1c.hpp"
|
||||
|
||||
namespace xsk::gsc::s1c
|
||||
{
|
||||
|
||||
auto opcode_size(std::uint8_t id) -> std::uint32_t
|
||||
{
|
||||
switch (static_cast<opcode>(id))
|
||||
{
|
||||
case opcode::OP_End:
|
||||
case opcode::OP_Return:
|
||||
case opcode::OP_GetUndefined:
|
||||
case opcode::OP_GetZero:
|
||||
case opcode::OP_waittillFrameEnd:
|
||||
case opcode::OP_waitFrame:
|
||||
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_EvalArray:
|
||||
case opcode::OP_EvalArrayRef:
|
||||
case opcode::OP_EvalLocalArrayRefCached0:
|
||||
case opcode::OP_ClearArray:
|
||||
case opcode::OP_EmptyArray:
|
||||
case opcode::OP_AddArray:
|
||||
case opcode::OP_PreScriptCall:
|
||||
case opcode::OP_ScriptFunctionCallPointer:
|
||||
case opcode::OP_ScriptMethodCallPointer:
|
||||
case opcode::OP_GetLevelObject:
|
||||
case opcode::OP_GetAnimObject:
|
||||
case opcode::OP_GetSelf:
|
||||
case opcode::OP_GetThisthread:
|
||||
case opcode::OP_GetLevel:
|
||||
case opcode::OP_GetGame:
|
||||
case opcode::OP_GetAnim:
|
||||
case opcode::OP_GetGameRef:
|
||||
case opcode::OP_inc:
|
||||
case opcode::OP_dec:
|
||||
case opcode::OP_bit_or:
|
||||
case opcode::OP_bit_ex_or:
|
||||
case opcode::OP_bit_and:
|
||||
case opcode::OP_equality:
|
||||
case opcode::OP_inequality:
|
||||
case opcode::OP_less:
|
||||
case opcode::OP_greater:
|
||||
case opcode::OP_less_equal:
|
||||
case opcode::OP_waittillmatch2:
|
||||
case opcode::OP_waittill:
|
||||
case opcode::OP_notify:
|
||||
case opcode::OP_endon:
|
||||
case opcode::OP_voidCodepos:
|
||||
case opcode::OP_vector:
|
||||
case opcode::OP_greater_equal:
|
||||
case opcode::OP_shift_left:
|
||||
case opcode::OP_shift_right:
|
||||
case opcode::OP_plus:
|
||||
case opcode::OP_minus:
|
||||
case opcode::OP_multiply:
|
||||
case opcode::OP_divide:
|
||||
case opcode::OP_mod:
|
||||
case opcode::OP_size:
|
||||
case opcode::OP_GetSelfObject:
|
||||
case opcode::OP_SafeSetVariableFieldCached0:
|
||||
case opcode::OP_clearparams:
|
||||
case opcode::OP_checkclearparams:
|
||||
case opcode::OP_EvalLocalVariableRefCached0:
|
||||
// case opcode::OP_EvalNewLocalVariableRefCached0:
|
||||
case opcode::OP_SetVariableField:
|
||||
// case opcode::OP_ClearVariableField:
|
||||
case opcode::OP_SetLocalVariableFieldCached0:
|
||||
case opcode::OP_ClearLocalVariableFieldCached0:
|
||||
case opcode::OP_wait:
|
||||
case opcode::OP_DecTop:
|
||||
case opcode::OP_CastFieldObject:
|
||||
case opcode::OP_CastBool:
|
||||
case opcode::OP_BoolNot:
|
||||
case opcode::OP_BoolComplement:
|
||||
return 1;
|
||||
case opcode::OP_GetByte:
|
||||
case opcode::OP_GetNegByte:
|
||||
case opcode::OP_CreateLocalVariable:
|
||||
case opcode::OP_RemoveLocalVariables:
|
||||
case opcode::OP_EvalLocalVariableCached:
|
||||
case opcode::OP_EvalLocalArrayCached:
|
||||
case opcode::OP_EvalNewLocalArrayRefCached0:
|
||||
case opcode::OP_EvalLocalArrayRefCached:
|
||||
case opcode::OP_ScriptThreadCallPointer:
|
||||
case opcode::OP_ScriptChildThreadCallPointer:
|
||||
case opcode::OP_ScriptMethodThreadCallPointer:
|
||||
case opcode::OP_ScriptMethodChildThreadCallPointer:
|
||||
case opcode::OP_CallBuiltinPointer:
|
||||
case opcode::OP_CallBuiltinMethodPointer:
|
||||
case opcode::OP_waittillmatch:
|
||||
case opcode::OP_SafeCreateVariableFieldCached:
|
||||
case opcode::OP_SafeSetVariableFieldCached:
|
||||
case opcode::OP_SafeSetWaittillVariableFieldCached:
|
||||
case opcode::OP_GetAnimTree:
|
||||
case opcode::OP_EvalLocalVariableRefCached:
|
||||
case opcode::OP_SetNewLocalVariableFieldCached0:
|
||||
case opcode::OP_SetLocalVariableFieldCached:
|
||||
case opcode::OP_ClearLocalVariableFieldCached:
|
||||
case opcode::OP_EvalLocalVariableObjectCached:
|
||||
return 2;
|
||||
case opcode::OP_GetUnsignedShort:
|
||||
case opcode::OP_GetNegUnsignedShort:
|
||||
case opcode::OP_GetBuiltinFunction:
|
||||
case opcode::OP_GetBuiltinMethod:
|
||||
case opcode::OP_GetString:
|
||||
case opcode::OP_GetIString:
|
||||
case opcode::OP_JumpOnFalseExpr:
|
||||
case opcode::OP_JumpOnTrueExpr:
|
||||
case opcode::OP_jumpback:
|
||||
case opcode::OP_endswitch:
|
||||
case opcode::OP_JumpOnFalse:
|
||||
case opcode::OP_JumpOnTrue:
|
||||
case opcode::OP_EvalLevelFieldVariable:
|
||||
case opcode::OP_EvalAnimFieldVariable:
|
||||
case opcode::OP_EvalSelfFieldVariable:
|
||||
case opcode::OP_EvalFieldVariable:
|
||||
case opcode::OP_EvalLevelFieldVariableRef:
|
||||
case opcode::OP_EvalAnimFieldVariableRef:
|
||||
case opcode::OP_EvalSelfFieldVariableRef:
|
||||
case opcode::OP_EvalFieldVariableRef:
|
||||
case opcode::OP_ClearFieldVariable:
|
||||
case opcode::OP_SetLevelFieldVariableField:
|
||||
case opcode::OP_SetAnimFieldVariableField:
|
||||
case opcode::OP_SetSelfFieldVariableField:
|
||||
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_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_ScriptLocalFunctionCall2:
|
||||
case opcode::OP_ScriptLocalFunctionCall:
|
||||
case opcode::OP_ScriptLocalMethodCall:
|
||||
case opcode::OP_GetLocalFunction:
|
||||
case opcode::OP_CallBuiltin:
|
||||
case opcode::OP_CallBuiltinMethod:
|
||||
case opcode::OP_ScriptFarFunctionCall2:
|
||||
case opcode::OP_ScriptFarFunctionCall:
|
||||
case opcode::OP_ScriptFarMethodCall:
|
||||
case opcode::OP_GetFarFunction:
|
||||
return 4;
|
||||
case opcode::OP_GetInteger:
|
||||
case opcode::OP_GetFloat:
|
||||
case opcode::OP_ScriptLocalThreadCall:
|
||||
case opcode::OP_ScriptLocalChildThreadCall:
|
||||
case opcode::OP_ScriptLocalMethodThreadCall:
|
||||
case opcode::OP_ScriptLocalMethodChildThreadCall:
|
||||
case opcode::OP_ScriptFarThreadCall:
|
||||
case opcode::OP_ScriptFarChildThreadCall:
|
||||
case opcode::OP_ScriptFarMethodThreadCall:
|
||||
case opcode::OP_ScriptFarMethodChildThreadCall:
|
||||
case opcode::OP_GetAnimation:
|
||||
case opcode::OP_switch:
|
||||
case opcode::OP_jump:
|
||||
return 5;
|
||||
case opcode::OP_GetVector:
|
||||
return 13;
|
||||
default:
|
||||
throw error("couldn't resolve instruction size for " + std::to_string(id));
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace xsk::gsc::s1c
|
@ -1,184 +0,0 @@
|
||||
// Copyright 2022 xensik. All rights reserved.
|
||||
//
|
||||
// Use of this source code is governed by a GNU GPLv3 license
|
||||
// that can be found in the LICENSE file.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "utils/xsk/utils.hpp"
|
||||
|
||||
#include "assembler.hpp"
|
||||
#include "disassembler.hpp"
|
||||
#include "compiler.hpp"
|
||||
#include "decompiler.hpp"
|
||||
#include "resolver.hpp"
|
||||
#include "context.hpp"
|
||||
|
||||
namespace xsk::gsc::s1c
|
||||
{
|
||||
|
||||
constexpr std::uint16_t max_string_id = 0xA51D;
|
||||
// ps3 ??
|
||||
// 360 0xA51D
|
||||
|
||||
enum class opcode : std::uint8_t
|
||||
{
|
||||
OP_CastFieldObject = 0x1D,
|
||||
OP_SetLocalVariableFieldCached = 0x1E,
|
||||
OP_plus = 0x1F,
|
||||
OP_RemoveLocalVariables = 0x20,
|
||||
OP_EvalSelfFieldVariableRef = 0x21,
|
||||
OP_ScriptFarMethodChildThreadCall = 0x22,
|
||||
OP_GetGameRef = 0x23,
|
||||
OP_EvalAnimFieldVariable = 0x24,
|
||||
OP_EvalLevelFieldVariableRef = 0x25,
|
||||
OP_GetThisthread = 0x26,
|
||||
OP_greater = 0x27,
|
||||
OP_waittillmatch = 0x28,
|
||||
OP_shift_right = 0x29,
|
||||
OP_dec = 0x2A,
|
||||
OP_JumpOnTrue = 0x2B,
|
||||
OP_bit_or = 0x2C,
|
||||
OP_equality = 0x2D,
|
||||
OP_ClearLocalVariableFieldCached0 = 0x2E,
|
||||
OP_notify = 0x2F,
|
||||
OP_GetVector = 0x30,
|
||||
OP_ScriptMethodChildThreadCallPointer = 0x31,
|
||||
OP_PreScriptCall = 0x32,
|
||||
OP_GetByte = 0x33,
|
||||
OP_ScriptFarThreadCall = 0x34,
|
||||
OP_SetSelfFieldVariableField = 0x35,
|
||||
OP_JumpOnFalseExpr = 0x36,
|
||||
OP_GetUndefined = 0x37,
|
||||
OP_jumpback = 0x38,
|
||||
OP_JumpOnTrueExpr = 0x39,
|
||||
OP_CallBuiltin0 = 0x3A,
|
||||
OP_CallBuiltin1 = 0x3B,
|
||||
OP_CallBuiltin2 = 0x3C,
|
||||
OP_CallBuiltin3 = 0x3D,
|
||||
OP_CallBuiltin4 = 0x3E,
|
||||
OP_CallBuiltin5 = 0x3F,
|
||||
OP_CallBuiltin = 0x40,
|
||||
OP_SetLocalVariableFieldCached0 = 0x41,
|
||||
OP_ClearFieldVariable = 0x42,
|
||||
OP_GetLevel = 0x43,
|
||||
OP_size = 0x44,
|
||||
OP_SafeSetWaittillVariableFieldCached = 0x45,
|
||||
OP_ScriptLocalMethodThreadCall = 0x46,
|
||||
OP_AddArray = 0x47,
|
||||
OP_endon = 0x48,
|
||||
OP_EvalFieldVariable = 0x49,
|
||||
OP_shift_left = 0x4A,
|
||||
OP_EvalLocalArrayRefCached0 = 0x4B,
|
||||
OP_Return = 0x4C,
|
||||
OP_CreateLocalVariable = 0x4D,
|
||||
OP_SafeSetVariableFieldCached0 = 0x4E,
|
||||
OP_GetBuiltinMethod = 0x4F,
|
||||
OP_ScriptLocalMethodCall = 0x50,
|
||||
OP_CallBuiltinMethodPointer = 0x51,
|
||||
OP_ScriptLocalChildThreadCall = 0x52,
|
||||
OP_GetSelfObject = 0x53,
|
||||
OP_GetGame = 0x54,
|
||||
OP_SetLevelFieldVariableField = 0x55,
|
||||
OP_EvalArray = 0x56,
|
||||
OP_GetSelf = 0x57,
|
||||
OP_End = 0x58,
|
||||
OP_EvalSelfFieldVariable = 0x59,
|
||||
OP_less_equal = 0x5A,
|
||||
OP_EvalLocalVariableCached0 = 0x5B,
|
||||
OP_EvalLocalVariableCached1 = 0x5C,
|
||||
OP_EvalLocalVariableCached2 = 0x5D,
|
||||
OP_EvalLocalVariableCached3 = 0x5E,
|
||||
OP_EvalLocalVariableCached4 = 0x5F,
|
||||
OP_EvalLocalVariableCached5 = 0x60,
|
||||
OP_EvalLocalVariableCached = 0x61,
|
||||
OP_EvalNewLocalArrayRefCached0 = 0x62,
|
||||
OP_ScriptChildThreadCallPointer = 0x63,
|
||||
OP_EvalLocalVariableObjectCached = 0x64,
|
||||
OP_ScriptLocalThreadCall = 0x65,
|
||||
OP_GetInteger = 0x66,
|
||||
OP_ScriptMethodCallPointer = 0x67,
|
||||
OP_checkclearparams = 0x68,
|
||||
OP_SetAnimFieldVariableField = 0x69,
|
||||
OP_waittillmatch2 = 0x6A,
|
||||
OP_minus = 0x6B,
|
||||
OP_ScriptLocalFunctionCall2 = 0x6C,
|
||||
OP_GetNegUnsignedShort = 0x6D,
|
||||
OP_GetNegByte = 0x6E,
|
||||
OP_SafeCreateVariableFieldCached = 0x6F,
|
||||
OP_greater_equal = 0x70,
|
||||
OP_vector = 0x71,
|
||||
OP_GetBuiltinFunction = 0x72,
|
||||
OP_endswitch = 0x73,
|
||||
OP_ClearArray = 0x74,
|
||||
OP_DecTop = 0x75,
|
||||
OP_CastBool = 0x76,
|
||||
OP_EvalArrayRef = 0x77,
|
||||
OP_SetNewLocalVariableFieldCached0 = 0x78,
|
||||
OP_GetZero = 0x79,
|
||||
OP_wait = 0x7A,
|
||||
OP_waittill = 0x7B,
|
||||
OP_GetIString = 0x7C,
|
||||
OP_ScriptFarFunctionCall = 0x7D,
|
||||
OP_GetAnimObject = 0x7E,
|
||||
OP_GetAnimTree = 0x7F,
|
||||
OP_EvalLocalArrayCached = 0x80,
|
||||
OP_mod = 0x81,
|
||||
OP_ScriptFarMethodThreadCall = 0x82,
|
||||
OP_GetUnsignedShort = 0x83,
|
||||
OP_clearparams = 0x84,
|
||||
OP_ScriptMethodThreadCallPointer = 0x85,
|
||||
OP_ScriptFunctionCallPointer = 0x86,
|
||||
OP_EmptyArray = 0x87,
|
||||
OP_SafeSetVariableFieldCached = 0x88,
|
||||
// ---- = 0x89,
|
||||
OP_EvalFieldVariableRef = 0x8A,
|
||||
OP_ScriptLocalMethodChildThreadCall = 0x8B,
|
||||
// ---- = 0x8C,
|
||||
OP_GetFloat = 0x8D,
|
||||
OP_EvalLocalVariableRefCached = 0x8E,
|
||||
OP_JumpOnFalse = 0x8F,
|
||||
OP_BoolComplement = 0x90,
|
||||
OP_ScriptThreadCallPointer = 0x91,
|
||||
OP_ScriptFarFunctionCall2 = 0x92,
|
||||
OP_less = 0x93,
|
||||
OP_BoolNot = 0x94,
|
||||
OP_waittillFrameEnd = 0x95,
|
||||
OP_waitFrame = 0x96,
|
||||
OP_GetString = 0x97,
|
||||
OP_EvalLevelFieldVariable = 0x98,
|
||||
OP_GetLevelObject = 0x99,
|
||||
OP_inc = 0x9A,
|
||||
OP_CallBuiltinMethod0 = 0x9B,
|
||||
OP_CallBuiltinMethod1 = 0x9C,
|
||||
OP_CallBuiltinMethod2 = 0x9D,
|
||||
OP_CallBuiltinMethod3 = 0x9E,
|
||||
OP_CallBuiltinMethod4 = 0x9F,
|
||||
OP_CallBuiltinMethod5 = 0xA0,
|
||||
OP_CallBuiltinMethod = 0xA1,
|
||||
OP_GetAnim = 0xA2,
|
||||
OP_switch = 0xA3,
|
||||
OP_SetVariableField = 0xA4,
|
||||
OP_divide = 0xA5,
|
||||
OP_GetLocalFunction = 0xA6,
|
||||
OP_ScriptFarChildThreadCall = 0xA7,
|
||||
OP_multiply = 0xA8,
|
||||
OP_ClearLocalVariableFieldCached = 0xA9,
|
||||
OP_EvalAnimFieldVariableRef = 0xAA,
|
||||
OP_EvalLocalArrayRefCached = 0xAB,
|
||||
OP_EvalLocalVariableRefCached0 = 0xAC,
|
||||
OP_bit_and = 0xAD,
|
||||
OP_GetAnimation = 0xAE,
|
||||
OP_GetFarFunction = 0xAF,
|
||||
OP_CallBuiltinPointer = 0xB0,
|
||||
OP_jump = 0xB1,
|
||||
OP_voidCodepos = 0xB2,
|
||||
OP_ScriptFarMethodCall = 0xB3,
|
||||
OP_inequality = 0xB4,
|
||||
OP_ScriptLocalFunctionCall = 0xB5,
|
||||
OP_bit_ex_or = 0xB6,
|
||||
};
|
||||
|
||||
auto opcode_size(std::uint8_t id) -> std::uint32_t;
|
||||
|
||||
} // namespace xsk::gsc::s1c
|
@ -1,6 +0,0 @@
|
||||
// Copyright 2022 xensik. All rights reserved.
|
||||
//
|
||||
// Use of this source code is governed by a GNU GPLv3 license
|
||||
// that can be found in the LICENSE file.
|
||||
|
||||
#include "stdafx.hpp"
|
@ -1,26 +0,0 @@
|
||||
// Copyright 2022 xensik. All rights reserved.
|
||||
//
|
||||
// Use of this source code is governed by a GNU GPLv3 license
|
||||
// that can be found in the LICENSE file.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <cstdio>
|
||||
#include <algorithm>
|
||||
#include <array>
|
||||
#include <filesystem>
|
||||
#include <fstream>
|
||||
#include <functional>
|
||||
#include <iostream>
|
||||
#include <map>
|
||||
#include <memory>
|
||||
#include <regex>
|
||||
#include <set>
|
||||
#include <sstream>
|
||||
#include <stack>
|
||||
#include <stdexcept>
|
||||
#include <string>
|
||||
#include <unordered_map>
|
||||
#include <vector>
|
||||
|
||||
using namespace std::literals;
|
@ -1,21 +0,0 @@
|
||||
// Copyright 2022 xensik. All rights reserved.
|
||||
//
|
||||
// Use of this source code is governed by a GNU GPLv3 license
|
||||
// that can be found in the LICENSE file.
|
||||
|
||||
#include "stdafx.hpp"
|
||||
#include "t4.hpp"
|
||||
|
||||
namespace xsk::gsc::t4
|
||||
{
|
||||
|
||||
auto opcode_size(std::uint8_t id) -> std::uint32_t
|
||||
{
|
||||
switch (opcode(id))
|
||||
{
|
||||
default:
|
||||
throw error("Couldn't resolve instruction size for " + std::to_string(id));
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace xsk::gsc::t4
|
@ -1,6 +0,0 @@
|
||||
// Copyright 2022 xensik. All rights reserved.
|
||||
//
|
||||
// Use of this source code is governed by a GNU GPLv3 license
|
||||
// that can be found in the LICENSE file.
|
||||
|
||||
#include "stdafx.hpp"
|
@ -1,26 +0,0 @@
|
||||
// Copyright 2022 xensik. All rights reserved.
|
||||
//
|
||||
// Use of this source code is governed by a GNU GPLv3 license
|
||||
// that can be found in the LICENSE file.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <cstdio>
|
||||
#include <algorithm>
|
||||
#include <array>
|
||||
#include <filesystem>
|
||||
#include <fstream>
|
||||
#include <functional>
|
||||
#include <iostream>
|
||||
#include <map>
|
||||
#include <memory>
|
||||
#include <regex>
|
||||
#include <set>
|
||||
#include <sstream>
|
||||
#include <stack>
|
||||
#include <stdexcept>
|
||||
#include <string>
|
||||
#include <unordered_map>
|
||||
#include <vector>
|
||||
|
||||
using namespace std::literals;
|
@ -1,21 +0,0 @@
|
||||
// Copyright 2022 xensik. All rights reserved.
|
||||
//
|
||||
// Use of this source code is governed by a GNU GPLv3 license
|
||||
// that can be found in the LICENSE file.
|
||||
|
||||
#include "stdafx.hpp"
|
||||
#include "t5.hpp"
|
||||
|
||||
namespace xsk::gsc::t5
|
||||
{
|
||||
|
||||
auto opcode_size(std::uint8_t id) -> std::uint32_t
|
||||
{
|
||||
switch (opcode(id))
|
||||
{
|
||||
default:
|
||||
throw error("Couldn't resolve instruction size for " + std::to_string(id));
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace xsk::gsc::t5
|
638
src/gsc/assembler.cpp
Normal file
638
src/gsc/assembler.cpp
Normal file
@ -0,0 +1,638 @@
|
||||
// Copyright 2023 xensik. All rights reserved.
|
||||
//
|
||||
// Use of this source code is governed by a GNU GPLv3 license
|
||||
// that can be found in the LICENSE file.
|
||||
|
||||
#include "stdinc.hpp"
|
||||
#include "assembler.hpp"
|
||||
#include "context.hpp"
|
||||
#include "utils/string.hpp"
|
||||
|
||||
namespace xsk::gsc
|
||||
{
|
||||
|
||||
assembler::assembler(context const* ctx) : ctx_{ ctx }, script_{ ctx->endian() == endian::big }, stack_{ ctx->endian() == endian::big }
|
||||
{
|
||||
}
|
||||
|
||||
auto assembler::assemble(assembly const& data) -> std::pair<buffer, buffer>
|
||||
{
|
||||
assembly_ = &data;
|
||||
script_.clear();
|
||||
stack_.clear();
|
||||
|
||||
script_.write<u8>(ctx_->opcode_id(opcode::OP_End));
|
||||
|
||||
for (auto const& func : data.functions)
|
||||
{
|
||||
assemble_function(*func);
|
||||
}
|
||||
|
||||
return { buffer{ script_.data(), script_.pos() }, buffer{ stack_.data(), stack_.pos() } };
|
||||
}
|
||||
|
||||
auto assembler::assemble_function(function const& func) -> void
|
||||
{
|
||||
func_ = &func;
|
||||
|
||||
stack_.write<u32>(func.size);
|
||||
|
||||
if (ctx_->props() & props::hash)
|
||||
{
|
||||
stack_.write<u64>(ctx_->hash_id(func.name));
|
||||
}
|
||||
else
|
||||
{
|
||||
if (ctx_->props() & props::tok4)
|
||||
stack_.write<u32>(func.id);
|
||||
else
|
||||
stack_.write<u16>(static_cast<u16>(func.id));
|
||||
|
||||
if (func.id == 0)
|
||||
{
|
||||
stack_.write_cstr(encrypt_string(func.name));
|
||||
}
|
||||
}
|
||||
|
||||
for (auto const& inst : func.instructions)
|
||||
{
|
||||
assemble_instruction(*inst);
|
||||
}
|
||||
}
|
||||
|
||||
auto assembler::assemble_instruction(instruction const& inst) -> void
|
||||
{
|
||||
script_.write<u8>(ctx_->opcode_id(inst.opcode));
|
||||
|
||||
switch (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_BoolNotAfterAnd:
|
||||
case opcode::OP_IsDefined:
|
||||
case opcode::OP_IsTrue:
|
||||
break;
|
||||
case opcode::OP_GetByte:
|
||||
case opcode::OP_GetNegByte:
|
||||
script_.write<u8>(static_cast<u8>(std::stoul(inst.data[0])));
|
||||
break;
|
||||
case opcode::OP_GetUnsignedShort:
|
||||
case opcode::OP_GetNegUnsignedShort:
|
||||
script_.write<u16>(static_cast<u16>(std::stoul(inst.data[0])));
|
||||
break;
|
||||
case opcode::OP_GetUnsignedInt:
|
||||
case opcode::OP_GetNegUnsignedInt:
|
||||
script_.write<u32>(static_cast<u32>(std::stoul(inst.data[0])));
|
||||
break;
|
||||
case opcode::OP_GetInteger:
|
||||
script_.write<i32>(std::stoi(inst.data[0]));
|
||||
break;
|
||||
case opcode::OP_GetInteger64:
|
||||
script_.write<i64>(std::stoll(inst.data[0]));
|
||||
break;
|
||||
case opcode::OP_GetFloat:
|
||||
script_.write<f32>(std::stof(inst.data[0]));
|
||||
break;
|
||||
case opcode::OP_GetVector:
|
||||
script_.align((ctx_->endian() == endian::little) ? 1 : 4);
|
||||
script_.write<f32>(std::stof(inst.data[0]));
|
||||
script_.write<f32>(std::stof(inst.data[1]));
|
||||
script_.write<f32>(std::stof(inst.data[2]));
|
||||
break;
|
||||
case opcode::OP_GetString:
|
||||
case opcode::OP_GetIString:
|
||||
if (ctx_->props() & props::str4)
|
||||
script_.write<u32>(0);
|
||||
else
|
||||
script_.write<u16>(0);
|
||||
stack_.write_cstr(encrypt_string(inst.data[0]));
|
||||
break;
|
||||
case opcode::OP_GetAnimation:
|
||||
if (ctx_->props() & props::str4)
|
||||
script_.write<u64>(0);
|
||||
else
|
||||
script_.write<u32>(0);
|
||||
stack_.write_cstr(encrypt_string(inst.data[0]));
|
||||
stack_.write_cstr(encrypt_string(inst.data[1]));
|
||||
break;
|
||||
case opcode::OP_GetAnimTree:
|
||||
script_.write<u8>(0);
|
||||
stack_.write_cstr(encrypt_string(inst.data[0]));
|
||||
break;
|
||||
case opcode::OP_GetUnkxHash:
|
||||
script_.write<u32>(std::stoul(inst.data[0], nullptr, 16));
|
||||
break;
|
||||
case opcode::OP_GetStatHash:
|
||||
case opcode::OP_GetEnumHash:
|
||||
case opcode::OP_GetDvarHash:
|
||||
script_.write<u64>(std::stoull(inst.data[0], nullptr, 16));
|
||||
break;
|
||||
case opcode::OP_waittillmatch:
|
||||
script_.write<u8>(static_cast<u8>(std::stoul(inst.data[0])));
|
||||
break;
|
||||
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_EvalLocalVariableObjectCached:
|
||||
case opcode::OP_EvalLocalArrayCached:
|
||||
script_.write<u8>(static_cast<u8>(std::stoul(inst.data[0])));
|
||||
break;
|
||||
case opcode::OP_CreateLocalVariable:
|
||||
case opcode::OP_EvalNewLocalArrayRefCached0:
|
||||
case opcode::OP_SafeCreateVariableFieldCached:
|
||||
case opcode::OP_SetNewLocalVariableFieldCached0:
|
||||
if (ctx_->props() & props::hash)
|
||||
script_.write<u64>(ctx_->hash_id(inst.data[0]));
|
||||
else
|
||||
script_.write<u8>(static_cast<u8>(std::stoul(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:
|
||||
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<u8>(static_cast<u8>(std::stoul(inst.data[0])));
|
||||
break;
|
||||
case opcode::OP_GetLocalFunction:
|
||||
case opcode::OP_ScriptLocalFunctionCall2:
|
||||
case opcode::OP_ScriptLocalFunctionCall:
|
||||
case opcode::OP_ScriptLocalMethodCall:
|
||||
assemble_local_call(inst, false);
|
||||
break;
|
||||
case opcode::OP_ScriptLocalThreadCall:
|
||||
case opcode::OP_ScriptLocalChildThreadCall:
|
||||
case opcode::OP_ScriptLocalMethodThreadCall:
|
||||
case opcode::OP_ScriptLocalMethodChildThreadCall:
|
||||
assemble_local_call(inst, true);
|
||||
break;
|
||||
case opcode::OP_GetFarFunction:
|
||||
case opcode::OP_ScriptFarFunctionCall2:
|
||||
case opcode::OP_ScriptFarFunctionCall:
|
||||
case opcode::OP_ScriptFarMethodCall:
|
||||
assemble_far_call(inst, false);
|
||||
break;
|
||||
case opcode::OP_ScriptFarThreadCall:
|
||||
case opcode::OP_ScriptFarChildThreadCall:
|
||||
case opcode::OP_ScriptFarMethodThreadCall:
|
||||
case opcode::OP_ScriptFarMethodChildThreadCall:
|
||||
assemble_far_call(inst, true);
|
||||
break;
|
||||
case opcode::OP_CallBuiltin:
|
||||
assemble_builtin_call(inst, false, true);
|
||||
break;
|
||||
case opcode::OP_CallBuiltinMethod:
|
||||
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:
|
||||
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:
|
||||
assemble_builtin_call(inst, true, false);
|
||||
break;
|
||||
case opcode::OP_JumpOnFalseExpr:
|
||||
case opcode::OP_JumpOnTrueExpr:
|
||||
case opcode::OP_JumpOnFalse:
|
||||
case opcode::OP_JumpOnTrue:
|
||||
assemble_jump(inst, true, false);
|
||||
break;
|
||||
case opcode::OP_jumpback:
|
||||
assemble_jump(inst, false, true);
|
||||
break;
|
||||
case opcode::OP_jump:
|
||||
assemble_jump(inst, false, false);
|
||||
break;
|
||||
case opcode::OP_switch:
|
||||
assemble_switch(inst);
|
||||
break;
|
||||
case opcode::OP_endswitch:
|
||||
assemble_end_switch(inst);
|
||||
break;
|
||||
case opcode::OP_FormalParams:
|
||||
assemble_formal_params(inst);
|
||||
break;
|
||||
default:
|
||||
throw asm_error(fmt::format("unhandled opcode {} at index {:04X}", opcode_name(inst.opcode), inst.index));
|
||||
}
|
||||
}
|
||||
|
||||
auto assembler::assemble_builtin_call(instruction const& inst, bool method, bool args) -> void
|
||||
{
|
||||
if (args)
|
||||
{
|
||||
script_.write<u8>(static_cast<u8>(std::stoi(inst.data[1])));
|
||||
}
|
||||
|
||||
if (ctx_->props() & props::hash)
|
||||
{
|
||||
stack_.write_cstr(fmt::format("#xS{:x}", ctx_->hash_id(inst.data[0])));
|
||||
script_.write<u16>(0);
|
||||
}
|
||||
else
|
||||
{
|
||||
auto const id = method ? ctx_->meth_id(inst.data[0]) : ctx_->func_id(inst.data[0]);
|
||||
|
||||
script_.write<u16>(id);
|
||||
}
|
||||
}
|
||||
|
||||
auto assembler::assemble_local_call(instruction const& inst, bool thread) -> void
|
||||
{
|
||||
auto const addr = resolve_function(inst.data[0]);
|
||||
auto const offset = static_cast<i32>(addr - inst.index - 1);
|
||||
|
||||
assemble_offset(offset);
|
||||
|
||||
if (thread)
|
||||
{
|
||||
script_.write<u8>(static_cast<u8>(std::stoi(inst.data[1])));
|
||||
}
|
||||
}
|
||||
|
||||
auto assembler::assemble_far_call(instruction const& inst, bool thread) -> void
|
||||
{
|
||||
if (ctx_->props() & props::farcall)
|
||||
{
|
||||
if (inst.data[0].empty())
|
||||
{
|
||||
auto const addr = resolve_function(inst.data[1]);
|
||||
auto const offset = static_cast<i32>(addr - inst.index - 1);
|
||||
|
||||
script_.write<i32>(static_cast<i32>(offset)); // unsigned?
|
||||
stack_.write<u64>(0);
|
||||
stack_.write<u64>(0);
|
||||
}
|
||||
else
|
||||
{
|
||||
script_.write<u32>(0);
|
||||
stack_.write<u64>(ctx_->hash_id(inst.data[0]));
|
||||
stack_.write<u64>(ctx_->hash_id(inst.data[1]));
|
||||
}
|
||||
|
||||
if (thread)
|
||||
{
|
||||
script_.write<u8>(static_cast<u8>(std::stoi(inst.data[2])));
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
script_.write<u8>(0);
|
||||
script_.write<u16>(0);
|
||||
|
||||
if (thread)
|
||||
{
|
||||
script_.write<u8>(static_cast<u8>(std::stoi(inst.data[2])));
|
||||
}
|
||||
|
||||
auto const file_id = ctx_->token_id(inst.data[0]);
|
||||
auto const func_id = ctx_->token_id(inst.data[1]);
|
||||
|
||||
if (ctx_->props() & props::tok4)
|
||||
stack_.write<u32>(file_id);
|
||||
else
|
||||
stack_.write<u16>(static_cast<u16>(file_id));
|
||||
|
||||
if (file_id == 0)
|
||||
stack_.write_cstr(encrypt_string(inst.data[0]));
|
||||
|
||||
if (ctx_->props() & props::tok4)
|
||||
stack_.write<u32>(func_id);
|
||||
else
|
||||
stack_.write<u16>(static_cast<u16>(func_id));
|
||||
|
||||
if (func_id == 0)
|
||||
stack_.write_cstr(encrypt_string(inst.data[1]));
|
||||
}
|
||||
}
|
||||
|
||||
auto assembler::assemble_switch(instruction const& inst) -> void
|
||||
{
|
||||
auto const addr = resolve_label(inst.data[0]);
|
||||
|
||||
script_.write<i32>(addr - inst.index - 4);
|
||||
}
|
||||
|
||||
auto assembler::assemble_end_switch(instruction const& inst) -> void
|
||||
{
|
||||
auto const count = std::stoul(inst.data[0]);
|
||||
|
||||
script_.write<u16>(static_cast<u16>(count));
|
||||
|
||||
auto type = static_cast<switch_type>(std::stoul(inst.data.back()));
|
||||
auto index = inst.index + 3u;
|
||||
|
||||
for (auto i = 0u; i < count; i++)
|
||||
{
|
||||
if (ctx_->engine() == engine::iw9)
|
||||
{
|
||||
if (inst.data[1 + (4 * i)] == "case")
|
||||
{
|
||||
type = static_cast<switch_type>(std::stoul(inst.data[1 + (4 * i) + 1]));
|
||||
|
||||
if (type == switch_type::integer)
|
||||
{
|
||||
script_.write<u32>(std::stoi(inst.data[1 + (4 * i) + 2])); //signed?
|
||||
}
|
||||
else
|
||||
{
|
||||
script_.write<u32>(0);
|
||||
stack_.write_cstr(inst.data[1 + (4 * i) + 2]);
|
||||
}
|
||||
|
||||
auto const addr = resolve_label(inst.data[1 + (4 * i) + 3]);
|
||||
|
||||
script_.write<i16>(static_cast<i16>(addr - index - 4));
|
||||
script_.write<u8>(0);
|
||||
script_.write<u8>(static_cast<u8>(type));
|
||||
|
||||
index += 8;
|
||||
}
|
||||
else if (inst.data[1 + (4 * i)] == "default")
|
||||
{
|
||||
auto const addr = resolve_label(inst.data[1 + (4 * i) + 1]);
|
||||
|
||||
script_.write<u32>(0);
|
||||
script_.write<i16>(static_cast<i16>(addr - index - 4));
|
||||
script_.write<u16>(0);
|
||||
|
||||
index += 8;
|
||||
}
|
||||
else
|
||||
{
|
||||
throw asm_error(fmt::format("invalid switch case {}", inst.data[1 + (4 * i)]));
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (inst.data[1 + (3 * i)] == "case")
|
||||
{
|
||||
if (type == switch_type::integer)
|
||||
{
|
||||
script_.write<u32>((std::stoi(inst.data[1 + (3 * i) + 1]) & 0xFFFFFF) + 0x800000);
|
||||
}
|
||||
else
|
||||
{
|
||||
script_.write<u32>(i + 1);
|
||||
stack_.write_cstr(encrypt_string(inst.data[1 + (3 * i) + 1]));
|
||||
}
|
||||
|
||||
auto const addr = resolve_label(inst.data[1 + (3 * i) + 2]);
|
||||
|
||||
assemble_offset(addr - index - 4);
|
||||
|
||||
index += 7;
|
||||
}
|
||||
else if (inst.data[1 + (3 * i)] == "default")
|
||||
{
|
||||
script_.write<u32>(0);
|
||||
stack_.write_cstr("\x01");
|
||||
|
||||
auto const addr = resolve_label(inst.data[1 + (3 * i) + 1]);
|
||||
|
||||
assemble_offset(addr - index - 4);
|
||||
|
||||
index += 7;
|
||||
}
|
||||
else
|
||||
{
|
||||
throw asm_error(fmt::format("invalid switch case {}", inst.data[1 + (3 * i)]));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
auto assembler::assemble_field_variable(instruction const& inst) -> void
|
||||
{
|
||||
if (ctx_->props() & props::hash)
|
||||
{
|
||||
script_.write<u64>(ctx_->hash_id(inst.data[0]));
|
||||
}
|
||||
else
|
||||
{
|
||||
auto id = ctx_->token_id(inst.data[0]);
|
||||
|
||||
if (id == 0) id = 0xFFFFFFFF;
|
||||
|
||||
if (ctx_->props() & props::tok4)
|
||||
script_.write<u32>(id);
|
||||
else
|
||||
script_.write<u16>(static_cast<u16>(id));
|
||||
|
||||
if (id > ctx_->str_count())
|
||||
{
|
||||
if (ctx_->props() & props::tok4)
|
||||
stack_.write<u32>(0);
|
||||
else
|
||||
stack_.write<u16>(0);
|
||||
|
||||
stack_.write_cstr(encrypt_string(inst.data[0]));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
auto assembler::assemble_formal_params(instruction const& inst) -> void
|
||||
{
|
||||
auto const count = std::stoul(inst.data[0]);
|
||||
|
||||
script_.write<u8>(static_cast<u8>(count));
|
||||
|
||||
for (auto i = 1u; i <= count; i++)
|
||||
{
|
||||
if (ctx_->props() & props::hash)
|
||||
{
|
||||
script_.write<u64>(ctx_->hash_id(inst.data[i]));
|
||||
}
|
||||
else
|
||||
{
|
||||
script_.write<u8>(static_cast<u8>(std::stoi(inst.data[i])));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
auto assembler::assemble_jump(instruction const& inst, bool expr, bool back) -> void
|
||||
{
|
||||
auto const addr = resolve_label(inst.data[0]);
|
||||
|
||||
if (expr)
|
||||
{
|
||||
script_.write<i16>(static_cast<i16>(addr - inst.index - 3));
|
||||
}
|
||||
else if (back)
|
||||
{
|
||||
script_.write<i16>(static_cast<i16>((inst.index + 3) - addr));
|
||||
}
|
||||
else
|
||||
{
|
||||
script_.write<i32>(static_cast<i32>(addr - inst.index - 5));
|
||||
}
|
||||
}
|
||||
|
||||
auto assembler::assemble_offset(i32 offs) -> void
|
||||
{
|
||||
auto bytes = std::array<u8, 4>{};
|
||||
|
||||
auto const shift = (ctx_->props() & props::offs8) ? 8 : (ctx_->props() & props::offs9) ? 9 : 10;
|
||||
|
||||
offs = (offs << shift) >> 8;
|
||||
|
||||
*reinterpret_cast<i32*>(bytes.data()) = offs;
|
||||
|
||||
if (ctx_->endian() == endian::little)
|
||||
{
|
||||
script_.write<u8>(bytes[0]);
|
||||
script_.write<u8>(bytes[1]);
|
||||
script_.write<u8>(bytes[2]);
|
||||
}
|
||||
else
|
||||
{
|
||||
script_.write<u8>(bytes[2]);
|
||||
script_.write<u8>(bytes[1]);
|
||||
script_.write<u8>(bytes[0]);
|
||||
}
|
||||
}
|
||||
|
||||
auto assembler::resolve_function(std::string const& name) -> std::int32_t
|
||||
{
|
||||
for (auto const& entry : assembly_->functions)
|
||||
{
|
||||
if (entry->name == name)
|
||||
{
|
||||
return entry->index;
|
||||
}
|
||||
}
|
||||
|
||||
throw asm_error(fmt::format("couldn't resolve local function address of {}", name));
|
||||
}
|
||||
|
||||
auto assembler::resolve_label(std::string const& name) -> std::int32_t
|
||||
{
|
||||
for (auto const& entry : func_->labels)
|
||||
{
|
||||
if (entry.second == name)
|
||||
{
|
||||
return entry.first;
|
||||
}
|
||||
}
|
||||
|
||||
throw asm_error(fmt::format("couldn't resolve label address of {}", name));
|
||||
}
|
||||
|
||||
auto assembler::encrypt_string(std::string const& str) -> std::string
|
||||
{
|
||||
if (str.starts_with("_encstr_") && str.size() % 2 == 0)
|
||||
{
|
||||
auto data = std::string{};
|
||||
|
||||
data.reserve(str.size() / 2);
|
||||
|
||||
for (auto i = 8u; i < str.size(); i += 2)
|
||||
{
|
||||
data += static_cast<char>(std::stoul(str.substr(i, 2), 0, 16));
|
||||
}
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
return str;
|
||||
}
|
||||
|
||||
} // namespace xsk::gsc
|
43
src/gsc/assembler.hpp
Normal file
43
src/gsc/assembler.hpp
Normal file
@ -0,0 +1,43 @@
|
||||
// Copyright 2023 xensik. All rights reserved.
|
||||
//
|
||||
// Use of this source code is governed by a GNU GPLv3 license
|
||||
// that can be found in the LICENSE file.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "misc/types.hpp"
|
||||
#include "utils/writer.hpp"
|
||||
|
||||
namespace xsk::gsc
|
||||
{
|
||||
|
||||
class assembler
|
||||
{
|
||||
context const* ctx_;
|
||||
function const* func_;
|
||||
assembly const* assembly_;
|
||||
utils::writer script_;
|
||||
utils::writer stack_;
|
||||
|
||||
public:
|
||||
assembler(context const* ctx);
|
||||
auto assemble(assembly const& data) -> std::pair<buffer, buffer>;
|
||||
|
||||
private:
|
||||
auto assemble_function(function const& func) -> void;
|
||||
auto assemble_instruction(instruction const& inst) -> void;
|
||||
auto assemble_builtin_call(instruction const& inst, bool method, bool args) -> void;
|
||||
auto assemble_local_call(instruction const& inst, bool thread) -> void;
|
||||
auto assemble_far_call(instruction const& inst, bool thread) -> void;
|
||||
auto assemble_switch(instruction const& inst) -> void;
|
||||
auto assemble_end_switch(instruction const& inst) -> void;
|
||||
auto assemble_field_variable(instruction const& inst) -> void;
|
||||
auto assemble_formal_params(instruction const& inst) -> void;
|
||||
auto assemble_jump(instruction const& inst, bool expr, bool back) -> void;
|
||||
auto assemble_offset(i32 offs) -> void;
|
||||
auto resolve_function(std::string const& name) -> i32;
|
||||
auto resolve_label(std::string const& name) -> i32;
|
||||
auto encrypt_string(std::string const& str) -> std::string;
|
||||
};
|
||||
|
||||
} // namespace xsk::gsc
|
2983
src/gsc/compiler.cpp
Normal file
2983
src/gsc/compiler.cpp
Normal file
File diff suppressed because it is too large
Load Diff
152
src/gsc/compiler.hpp
Normal file
152
src/gsc/compiler.hpp
Normal file
@ -0,0 +1,152 @@
|
||||
// Copyright 2023 xensik. All rights reserved.
|
||||
//
|
||||
// Use of this source code is governed by a GNU GPLv3 license
|
||||
// that can be found in the LICENSE file.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "misc/types.hpp"
|
||||
|
||||
namespace xsk::gsc
|
||||
{
|
||||
|
||||
class compiler
|
||||
{
|
||||
context* ctx_;
|
||||
assembly::ptr assembly_;
|
||||
function::ptr function_;
|
||||
std::vector<std::string> stackframe_;
|
||||
std::vector<std::string> localfuncs_;
|
||||
std::unordered_map<node*, scope::ptr> scopes_;
|
||||
std::vector<scope*> break_blks_;
|
||||
std::vector<scope*> continue_blks_;
|
||||
std::string animname_;
|
||||
u32 index_;
|
||||
u32 label_idx_;
|
||||
bool can_break_;
|
||||
bool can_continue_;
|
||||
bool developer_thread_;
|
||||
bool animload_;
|
||||
|
||||
public:
|
||||
compiler(context* ctx);
|
||||
auto compile(program const& data) -> assembly::ptr;
|
||||
auto compile(std::string const& file, std::vector<u8>& data) -> assembly::ptr;
|
||||
|
||||
private:
|
||||
auto emit_program(program const& prog) -> void;
|
||||
auto emit_decl(decl const& dec) -> void;
|
||||
auto emit_decl_usingtree(decl_usingtree const& animtree) -> void;
|
||||
auto emit_decl_function(decl_function const& func) -> void;
|
||||
auto emit_stmt(stmt const& stm, scope& scp, bool last) -> void;
|
||||
auto emit_stmt_list(stmt_list const& stm, scope& scp, bool last) -> void;
|
||||
auto emit_stmt_dev(stmt_dev const& stm, scope& scp, bool last) -> void;
|
||||
auto emit_stmt_expr(stmt_expr const& stm, scope& scp) -> void;
|
||||
auto emit_stmt_call(stmt_call const& stm, scope& scp) -> void;
|
||||
auto emit_stmt_assign(stmt_assign const& stm, scope& scp) -> void;
|
||||
auto emit_stmt_endon(stmt_endon const& stm, scope& scp) -> void;
|
||||
auto emit_stmt_notify(stmt_notify const& stm, scope& scp) -> void;
|
||||
auto emit_stmt_wait(stmt_wait const& stm, scope& scp) -> void;
|
||||
auto emit_stmt_waittill(stmt_waittill const& stm, scope& scp) -> void;
|
||||
auto emit_stmt_waittillmatch(stmt_waittillmatch const& stm, scope& scp) -> void;
|
||||
auto emit_stmt_waittillframeend(stmt_waittillframeend const& stm, scope& scp) -> void;
|
||||
auto emit_stmt_waitframe(stmt_waitframe const& stm, scope& scp) -> void;
|
||||
auto emit_stmt_if(stmt_if const& stm, scope& scp, bool last) -> void;
|
||||
auto emit_stmt_ifelse(stmt_ifelse const& stm, scope& scp, bool last) -> void;
|
||||
auto emit_stmt_while(stmt_while const& stm, scope& scp) -> void;
|
||||
auto emit_stmt_dowhile(stmt_dowhile const& stm, scope& scp) -> void;
|
||||
auto emit_stmt_for(stmt_for const& stm, scope& scp) -> void;
|
||||
auto emit_stmt_foreach(stmt_foreach const& stm, scope& scp) -> void;
|
||||
auto emit_stmt_switch(stmt_switch const& stm, scope& scp) -> void;
|
||||
auto emit_stmt_case(stmt_case const& stm, scope& scp) -> void;
|
||||
auto emit_stmt_default(stmt_default const& stm, scope& scp) -> void;
|
||||
auto emit_stmt_break(stmt_break const& stm, scope& scp) -> void;
|
||||
auto emit_stmt_continue(stmt_continue const& stm, scope& scp) -> void;
|
||||
auto emit_stmt_return(stmt_return const& stm, scope& scp) -> void;
|
||||
auto emit_stmt_breakpoint(stmt_breakpoint const& stm, scope& scp) -> void;
|
||||
auto emit_stmt_prof_begin(stmt_prof_begin const& stm, scope& scp) -> void;
|
||||
auto emit_stmt_prof_end(stmt_prof_end const& stm, scope& scp) -> void;
|
||||
auto emit_expr(expr const& exp, scope& scp) -> void;
|
||||
auto emit_expr_assign(expr_assign const& exp, scope& scp) -> void;
|
||||
auto emit_expr_clear(expr const& exp, scope& scp) -> void;
|
||||
auto emit_expr_clear_local(expr_identifier const& exp, scope& scp) -> void;
|
||||
auto emit_expr_increment(expr_increment const& exp, scope& scp, bool is_stmt) -> void;
|
||||
auto emit_expr_decrement(expr_decrement const& exp, scope& scp, bool is_stmt) -> void;
|
||||
auto emit_expr_ternary(expr_ternary const& exp, scope& scp) -> void;
|
||||
auto emit_expr_binary(expr_binary const& exp, scope& scp) -> void;
|
||||
auto emit_expr_and(expr_and const& exp, scope& scp) -> void;
|
||||
auto emit_expr_or(expr_or const& exp, scope& scp) -> void;
|
||||
auto emit_expr_complement(expr_complement const& exp, scope& scp) -> void;
|
||||
auto emit_expr_negate(expr_negate const& exp, scope& scp) -> void;
|
||||
auto emit_expr_not(expr_not const& exp, scope& scp) -> void;
|
||||
auto emit_expr_call(expr_call const& exp, scope& scp, bool is_stmt) -> void;
|
||||
auto emit_expr_call_pointer(expr_pointer const& exp, scope& scp, bool is_stmt) -> void;
|
||||
auto emit_expr_call_function(expr_function const& exp, scope& scp, bool is_stmt) -> void;
|
||||
auto emit_expr_method(expr_method const& exp, scope& scp, bool is_stmt) -> void;
|
||||
auto emit_expr_method_pointer(expr_pointer const& exp, expr const& obj, scope& scp, bool is_stmt) -> void;
|
||||
auto emit_expr_method_function(expr_function const& exp, expr const& obj, scope& scp, bool is_stmt) -> void;
|
||||
auto emit_expr_add_array(expr_add_array const& exp, scope& scp) -> void;
|
||||
auto emit_expr_parameters(expr_parameters const& exp, scope& scp) -> void;
|
||||
auto emit_expr_arguments(expr_arguments const& exp, scope& scp) -> void;
|
||||
auto emit_expr_isdefined(expr_isdefined const& exp, scope& scp) -> void;
|
||||
auto emit_expr_istrue(expr_istrue const& exp, scope& scp) -> void;
|
||||
auto emit_expr_reference(expr_reference const& exp, scope& scp) -> void;
|
||||
auto emit_expr_size(expr_size const& exp, scope& scp) -> void;
|
||||
auto emit_expr_tuple(expr_tuple const& exp, scope& scp) -> void;
|
||||
auto emit_expr_variable_ref(expr const& exp, scope& scp, bool set) -> void;
|
||||
auto emit_expr_array_ref(expr_array const& exp, scope& scp, bool set) -> void;
|
||||
auto emit_expr_field_ref(expr_field const& exp, scope& scp, bool set) -> void;
|
||||
auto emit_expr_local_ref(expr_identifier const& exp, scope& scp, bool set) -> void;
|
||||
auto emit_expr_variable(expr const& exp, scope& scp) -> void;
|
||||
auto emit_expr_array(expr_array const& exp, scope& scp) -> void;
|
||||
auto emit_expr_field(expr_field const& exp, scope& scp) -> void;
|
||||
auto emit_expr_local(expr_identifier const& exp, scope& scp) -> void;
|
||||
auto emit_expr_object(expr const& exp, scope& scp) -> void;
|
||||
auto emit_expr_vector(expr_vector const& exp, scope& scp) -> void;
|
||||
auto emit_expr_animation(expr_animation const& exp) -> void;
|
||||
auto emit_expr_animtree(expr_animtree const& exp) -> void;
|
||||
auto emit_expr_istring(expr_istring const& exp) -> void;
|
||||
auto emit_expr_string(expr_string const& exp) -> void;
|
||||
auto emit_expr_float(expr_float const& exp) -> void;
|
||||
auto emit_expr_integer(expr_integer const& exp) -> void;
|
||||
auto emit_expr_false(expr_false const& exp) -> void;
|
||||
auto emit_expr_true(expr_true const& exp) -> void;
|
||||
auto emit_create_local_vars(scope& scp) -> void;
|
||||
auto emit_remove_local_vars(scope& scp) -> void;
|
||||
auto emit_opcode(opcode op) -> void;
|
||||
auto emit_opcode(opcode op, std::string const& data) -> void;
|
||||
auto emit_opcode(opcode op, std::vector<std::string> const& data) -> void;
|
||||
auto process_function(decl_function const& func) -> void;
|
||||
auto process_stmt(stmt const& stm, scope& scp) -> void;
|
||||
auto process_stmt_list(stmt_list const& stm, scope& scp) -> void;
|
||||
auto process_stmt_dev(stmt_dev const& stm, scope& scp) -> void;
|
||||
auto process_stmt_expr(stmt_expr const& stm, scope& scp) -> void;
|
||||
auto process_stmt_assign(stmt_assign const& stm, scope& scp) -> void;
|
||||
auto process_stmt_waittill(stmt_waittill const& stm, scope& scp) -> void;
|
||||
auto process_stmt_if(stmt_if const& stm, scope& scp) -> void;
|
||||
auto process_stmt_ifelse(stmt_ifelse const& stm, scope& scp) -> void;
|
||||
auto process_stmt_while(stmt_while const& stm, scope& scp) -> void;
|
||||
auto process_stmt_dowhile(stmt_dowhile const& stm, scope& scp) -> void;
|
||||
auto process_stmt_for(stmt_for const& stm, scope& scp) -> void;
|
||||
auto process_stmt_foreach(stmt_foreach const& stm, scope& scp) -> void;
|
||||
auto process_stmt_switch(stmt_switch const& stm, scope& scp) -> void;
|
||||
auto process_stmt_break(stmt_break const& stm, scope& scp) -> void;
|
||||
auto process_stmt_continue(stmt_continue const& stm, scope& scp) -> void;
|
||||
auto process_stmt_return(stmt_return const& stm, scope& scp) -> void;
|
||||
auto process_expr(expr const& exp, scope& scp) -> void;
|
||||
auto process_expr_tuple(expr_tuple const& exp, scope& scp) -> void;
|
||||
auto process_expr_parameters(expr_parameters const& exp, scope& scp) -> void;
|
||||
auto variable_register(expr_identifier const& exp, scope& scp) -> void;
|
||||
auto variable_initialized(expr_identifier const& exp, scope& scp) -> bool;
|
||||
auto variable_initialize(expr_identifier const& exp, scope& scp) -> u8;
|
||||
auto variable_create(expr_identifier const& exp, scope& scp) -> u8;
|
||||
auto variable_access(expr_identifier const& exp, scope& scp) -> u8;
|
||||
auto resolve_function_type(expr_function const& exp, std::string& path) -> call::type;
|
||||
auto resolve_reference_type(expr_reference const& exp, std::string& path, bool& method) -> call::type;
|
||||
auto is_constant_condition(expr const& exp) -> bool;
|
||||
auto insert_label(std::string const& label) -> void;
|
||||
auto create_label() -> std::string;
|
||||
auto insert_label() -> std::string;
|
||||
};
|
||||
|
||||
} // namespace xsk::gsc
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user