/* 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 {ARC} %define api.namespace {xsk::arc} %define api.location.type {xsk::arc::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::arc::context const* ctx_ } %lex-param { xsk::arc::preprocessor& ppr } %parse-param { xsk::arc::context const* ctx_ } %parse-param { xsk::arc::preprocessor& ppr } %parse-param { xsk::arc::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::arc { class preprocessor; } } %code top { #include "xsk/stdinc.hpp" #include "xsk/arc/parser.hpp" #include "xsk/arc/preprocessor.hpp" using namespace xsk::arc; namespace xsk::arc { auto ARClex(context const* ctx_, preprocessor& ppr) -> parser::symbol_type; auto parse_switch(stmt_switch& stm) -> void; } } %token HASH "#" %token DEVBEGIN "/#" %token DEVEND "#/" %token INLINE "#inline" %token INCLUDE "#include" %token USINGTREE "#using_animtree" %token ANIMTREE "#animtree" %token AUTOEXEC "autoexec" %token CODECALL "codecall" %token PRIVATE "private" %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 PROFBEGIN "prof_begin" %token PROFEND "prof_end" %token THREAD "thread" %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 CONST "const" %token GETNEXTARRAYKEY "getnextarraykey" %token GETFIRSTARRAYKEY "getfirstarraykey" %token GETDVARCOLORALPHA "getdvarcoloralpha" %token GETDVARCOLORBLUE "getdvarcolorblue" %token GETDVARCOLORGREEN "getdvarcolorgreen" %token GETDVARCOLORRED "getdvarcolorred" %token GETDVARVECTOR "getdvarvector" %token GETDVARFLOAT "getdvarfloat" %token GETDVARINT "getdvarint" %token GETDVAR "getdvar" %token GETTIME "gettime" %token ABS "abs" %token VECTORTOANGLES "vectortoangles" %token ANGLECLAMP180 "angleclamp180" %token ANGLESTOFORWARD "anglestoforward" %token ANGLESTORIGHT "anglestoright" %token ANGLESTOUP "anglestoup" %token VECTORSCALE "vectorscale" %token ISDEFINED "isdefined" %token LPAREN "(" %token RPAREN ")" %token LBRACE "{" %token RBRACE "}" %token LBRACKET "[" %token RBRACKET "]" %token COMMA "," %token DOT "." %token DOUBLEDOT ".." %token ELLIPSIS "..." %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 PATH "path" %token IDENTIFIER "identifier" %token STRING "string literal" %token ISTRING "localized string" %token HASHSTR "hash string" %token FLOAT "float" %token INTEGER "integer" %type program %type include %type declaration %type decl_usingtree %type decl_function %type stmt %type stmt_or_dev %type stmt_list %type stmt_or_dev_list %type stmt_dev %type stmt_comp %type stmt_expr %type stmt_call %type stmt_const %type stmt_assign %type stmt_endon %type stmt_notify %type stmt_wait %type stmt_waittill %type stmt_waittillmatch %type stmt_waittillframeend %type stmt_if %type stmt_ifelse %type stmt_while %type stmt_dowhile %type stmt_for %type stmt_foreach %type stmt_switch %type stmt_case %type stmt_default %type stmt_break %type stmt_continue %type stmt_return %type stmt_prof_begin %type stmt_prof_end %type expr %type expr_or_empty %type expr_increment %type expr_decrement %type expr_assign %type expr_ternary %type expr_binary %type expr_primitive %type expr_complement %type expr_negate %type expr_not %type expr_call %type expr_method %type expr_function %type expr_pointer %type expr_parameters %type expr_parameters_default %type expr_arguments %type expr_arguments_no_empty %type expr_getnextarraykey %type expr_getfirstarraykey %type expr_getdvarcoloralpha %type expr_getdvarcolorblue %type expr_getdvarcolorgreen %type expr_getdvarcolorred %type expr_getdvarvector %type expr_getdvarfloat %type expr_getdvarint %type expr_getdvar %type expr_gettime %type expr_abs %type expr_vectortoangles %type expr_angleclamp180 %type expr_anglestoforward %type expr_anglestoright %type expr_anglestoup %type expr_vectorscale %type expr_isdefined %type expr_reference %type expr_array %type expr_field %type expr_size %type expr_paren %type expr_object %type expr_empty_array %type expr_undefined %type expr_game %type expr_self %type expr_anim %type expr_level %type expr_animation %type expr_animtree %type expr_identifier_nosize %type expr_identifier %type expr_path %type expr_istring %type expr_string %type expr_vector %type expr_hash %type expr_float %type expr_integer %type expr_false %type expr_true %nonassoc SIZEOF %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 = program::make(@$); } ; program : program SEMICOLON { $$ = std::move($1); } | 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)); } | SEMICOLON { $$ = program::make(@$); } | inline { $$ = program::make(@$); } | include { $$ = program::make(@$); $$->includes.push_back(std::move($1)); } | declaration { $$ = program::make(@$); $$->declarations.push_back(std::move($1)); } ; inline : INLINE expr_path SEMICOLON { ppr.push_header($2->value); } ; include : INCLUDE expr_path SEMICOLON { $$ = include::make(@$, std::move($2)); } ; declaration : DEVBEGIN { $$ = decl_dev_begin::make(@$); } | DEVEND { $$ = decl_dev_end::make(@$); } | decl_usingtree { $$ = std::move($1); } | decl_function { $$ = std::move($1); } ; decl_usingtree : USINGTREE LPAREN expr_string RPAREN SEMICOLON { ppr.ban_header(@$); $$ = decl_usingtree::make(@$, std::move($3)); } ; decl_function : expr_identifier LPAREN expr_parameters RPAREN stmt_comp { ppr.ban_header(@$); $$ = decl_function::make(@$, expr_identifier::make(@$, ""), std::move($1), std::move($3), std::move($5), export_flags::export_none); } | AUTOEXEC expr_identifier LPAREN expr_parameters RPAREN stmt_comp { ppr.ban_header(@$); $$ = decl_function::make(@$, expr_identifier::make(@$, ""), std::move($2), std::move($4), std::move($6), export_flags::export_autoexec); } | CODECALL expr_identifier LPAREN expr_parameters RPAREN stmt_comp { ppr.ban_header(@$); $$ = decl_function::make(@$, expr_identifier::make(@$, ""), std::move($2), std::move($4), std::move($6), export_flags::export_codecall); } | PRIVATE expr_identifier LPAREN expr_parameters RPAREN stmt_comp { ppr.ban_header(@$); $$ = decl_function::make(@$, expr_identifier::make(@$, ""), std::move($2), std::move($4), std::move($6), export_flags::export_private2); } ; stmt : stmt_comp { $$ = std::move($1); } | stmt_call { $$ = std::move($1); } | stmt_const { $$ = std::move($1); } | stmt_assign { $$ = std::move($1); } | stmt_endon { $$ = std::move($1); } | stmt_notify { $$ = std::move($1); } | stmt_wait { $$ = std::move($1); } | stmt_waittill { $$ = std::move($1); } | stmt_waittillmatch { $$ = std::move($1); } | stmt_waittillframeend { $$ = std::move($1); } | stmt_if { $$ = std::move($1); } | stmt_ifelse { $$ = std::move($1); } | stmt_while { $$ = std::move($1); } | stmt_dowhile { $$ = std::move($1); } | stmt_for { $$ = std::move($1); } | stmt_foreach { $$ = std::move($1); } | stmt_switch { $$ = std::move($1); } | stmt_case { $$ = std::move($1); } | stmt_default { $$ = std::move($1); } | stmt_break { $$ = std::move($1); } | stmt_continue { $$ = std::move($1); } | stmt_return { $$ = std::move($1); } | stmt_prof_begin { $$ = std::move($1); } | stmt_prof_end { $$ = std::move($1); } ; stmt_or_dev : stmt { $$ = std::move($1); } | stmt_dev { $$ = std::move($1); } ; stmt_list : stmt_list stmt { $$ = std::move($1); $$->list.push_back(std::move($2)); } | stmt { $$ = stmt_list::make(@$); $$->list.push_back(std::move($1)); } | stmt_list SEMICOLON { $$ = std::move($1); } | SEMICOLON { $$ = stmt_list::make(@$); } ; stmt_or_dev_list : stmt_or_dev_list stmt_or_dev { $$ = std::move($1); $$->list.push_back(std::move($2)); } | stmt_or_dev { $$ = stmt_list::make(@$); $$->list.push_back(std::move($1)); } | stmt_or_dev_list SEMICOLON { $$ = std::move($1); } | SEMICOLON { $$ = stmt_list::make(@$); } ; stmt_dev : DEVBEGIN stmt_list DEVEND { $$ = stmt_dev::make(@$, std::move($2)); } | DEVBEGIN DEVEND { $$ = stmt_dev::make(@$, stmt_list::make(@$)); } ; stmt_comp : LBRACE stmt_or_dev_list RBRACE { $$ = stmt_comp::make(@$, std::move($2)); } | LBRACE RBRACE { $$ = stmt_comp::make(@$, stmt_list::make(@$)); } ; stmt_expr : expr_assign { $$ = stmt_expr::make(@$, std::move($1)); } | expr_increment { $$ = stmt_expr::make(@$, std::move($1)); } | expr_decrement { $$ = stmt_expr::make(@$, std::move($1)); } | { $$ = stmt_expr::make(@$, expr_empty::make(@$)); } ; stmt_call : expr_call SEMICOLON { $$ = stmt_expr::make(@$, std::move($1)); } | expr_method SEMICOLON { $$ = stmt_expr::make(@$, std::move($1)); } ; stmt_const : CONST expr_identifier ASSIGN expr SEMICOLON { $$ = stmt_expr::make(@$, expr_const::make(@$, std::move($2), std::move($4))); } ; stmt_assign : expr_assign SEMICOLON { $$ = stmt_expr::make(@$, std::move($1)); } | expr_increment SEMICOLON { $$ = stmt_expr::make(@$, std::move($1)); } | expr_decrement SEMICOLON { $$ = stmt_expr::make(@$, std::move($1)); } ; stmt_endon : expr_object ENDON LPAREN expr RPAREN SEMICOLON { $$ = stmt_endon::make(@$, std::move($1), std::move($4)); } ; stmt_notify : expr_object NOTIFY LPAREN expr COMMA expr_arguments_no_empty RPAREN SEMICOLON { $$ = stmt_notify::make(@$, std::move($1), std::move($4), std::move($6)); } | expr_object NOTIFY LPAREN expr RPAREN SEMICOLON { $$ = stmt_notify::make(@$, std::move($1), std::move($4), expr_arguments::make(@$)); } ; stmt_wait : WAIT expr SEMICOLON { $$ = stmt_wait::make(@$, std::move($2)); } ; stmt_waittill : expr_object WAITTILL LPAREN expr COMMA expr_arguments_no_empty RPAREN SEMICOLON { $$ = stmt_waittill::make(@$, std::move($1), std::move($4), std::move($6)); } | expr_object WAITTILL LPAREN expr RPAREN SEMICOLON { $$ = stmt_waittill::make(@$, std::move($1), std::move($4), expr_arguments::make(@$)); } ; stmt_waittillmatch : expr_object WAITTILLMATCH LPAREN expr COMMA expr_arguments_no_empty RPAREN SEMICOLON { $$ = stmt_waittillmatch::make(@$, std::move($1), std::move($4), std::move($6)); } | expr_object WAITTILLMATCH LPAREN expr RPAREN SEMICOLON { $$ = stmt_waittillmatch::make(@$, std::move($1), std::move($4), expr_arguments::make(@$)); } ; stmt_waittillframeend : WAITTILLFRAMEEND SEMICOLON { $$ = stmt_waittillframeend::make(@$); } ; stmt_if : IF LPAREN expr RPAREN stmt %prec THEN { $$ = stmt_if::make(@$, std::move($3), std::move($5)); } ; stmt_ifelse : IF LPAREN expr RPAREN stmt ELSE stmt { $$ = stmt_ifelse::make(@$, std::move($3), std::move($5), std::move($7)); } ; stmt_while : WHILE LPAREN expr RPAREN stmt { $$ = stmt_while::make(@$, std::move($3), std::move($5)); } ; stmt_dowhile : DO stmt WHILE LPAREN expr RPAREN SEMICOLON { $$ = stmt_dowhile::make(@$, std::move($5), std::move($2)); } ; stmt_for : FOR LPAREN stmt_expr SEMICOLON expr_or_empty SEMICOLON stmt_expr RPAREN stmt { $$ = stmt_for::make(@$, std::move($3), std::move($5), std::move($7), std::move($9)); } ; stmt_foreach : FOREACH LPAREN expr_identifier IN expr RPAREN stmt { auto array = expr_identifier::make(@$, fmt::format("_a{}", ++index)); auto key = expr_identifier::make(@$, fmt::format("_k{}", ++index)); $$ = stmt_foreach::make(@$, std::move($5), std::move($3), std::move(array), std::move(key), std::move($7), false); } | FOREACH LPAREN expr_identifier COMMA expr_identifier IN expr RPAREN stmt { auto array = expr_identifier::make(@$, fmt::format("_a{}", ++index)); $$ = stmt_foreach::make(@$, std::move($7), std::move($5), std::move(array), std::move($3), std::move($9), true); } ; stmt_switch : SWITCH LPAREN expr RPAREN stmt_comp { $$ = stmt_switch::make(@$, std::move($3), std::move($5)); parse_switch(*$$); } ; stmt_case : CASE expr_integer COLON { $$ = stmt_case::make(@$, std::move($2), stmt_list::make(@$)); } | CASE expr_string COLON { $$ = stmt_case::make(@$, std::move($2), stmt_list::make(@$)); } ; stmt_default : DEFAULT COLON { $$ = stmt_default::make(@$, stmt_list::make(@$)); } ; stmt_break : BREAK SEMICOLON { $$ = stmt_break::make(@$); } ; stmt_continue : CONTINUE SEMICOLON { $$ = stmt_continue::make(@$); } ; stmt_return : RETURN expr SEMICOLON { $$ = stmt_return::make(@$, std::move($2)); } | RETURN SEMICOLON { $$ = stmt_return::make(@$, expr_empty::make(@$)); } ; stmt_prof_begin : PROFBEGIN LPAREN expr_arguments RPAREN SEMICOLON { $$ = stmt_prof_begin::make(@$, std::move($3)); } ; stmt_prof_end : PROFEND LPAREN expr_arguments RPAREN SEMICOLON { $$ = stmt_prof_end::make(@$, 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); } | { $$ = expr_empty::make(@$); } ; expr_increment : INCREMENT expr_object %prec PREINC { $$ = expr_increment::make(@$, std::move($2), true); } | expr_object INCREMENT %prec POSTINC { $$ = expr_increment::make(@$, std::move($1), false); } ; expr_decrement : DECREMENT expr_object %prec PREDEC { $$ = expr_decrement::make(@$, std::move($2), true); } | expr_object DECREMENT %prec POSTDEC { $$ = expr_decrement::make(@$, std::move($1), false); } ; expr_assign : expr_object ASSIGN expr { $$ = expr_assign::make(@$, std::move($1), std::move($3), expr_assign::op::eq); } | expr_object ASSIGN_BW_OR expr { $$ = expr_assign::make(@$, std::move($1), std::move($3), expr_assign::op::bwor); } | expr_object ASSIGN_BW_AND expr { $$ = expr_assign::make(@$, std::move($1), std::move($3), expr_assign::op::bwand); } | expr_object ASSIGN_BW_EXOR expr { $$ = expr_assign::make(@$, std::move($1), std::move($3), expr_assign::op::bwexor); } | expr_object ASSIGN_LSHIFT expr { $$ = expr_assign::make(@$, std::move($1), std::move($3), expr_assign::op::shl); } | expr_object ASSIGN_RSHIFT expr { $$ = expr_assign::make(@$, std::move($1), std::move($3), expr_assign::op::shr); } | expr_object ASSIGN_ADD expr { $$ = expr_assign::make(@$, std::move($1), std::move($3), expr_assign::op::add); } | expr_object ASSIGN_SUB expr { $$ = expr_assign::make(@$, std::move($1), std::move($3), expr_assign::op::sub); } | expr_object ASSIGN_MUL expr { $$ = expr_assign::make(@$, std::move($1), std::move($3), expr_assign::op::mul); } | expr_object ASSIGN_DIV expr { $$ = expr_assign::make(@$, std::move($1), std::move($3), expr_assign::op::div); } | expr_object ASSIGN_MOD expr { $$ = expr_assign::make(@$, std::move($1), std::move($3), expr_assign::op::mod); } ; expr_ternary : expr QMARK expr COLON expr %prec TERN { $$ = expr_ternary::make(@$, std::move($1), std::move($3), std::move($5)); } ; expr_binary : expr OR expr { $$ = expr_binary::make(@$, std::move($1), std::move($3), expr_binary::op::bool_or); } | expr AND expr { $$ = expr_binary::make(@$, std::move($1), std::move($3), expr_binary::op::bool_and); } | expr EQUALITY expr { $$ = expr_binary::make(@$, std::move($1), std::move($3), expr_binary::op::eq); } | expr INEQUALITY expr { $$ = expr_binary::make(@$, std::move($1), std::move($3), expr_binary::op::ne); } | expr LESS_EQUAL expr { $$ = expr_binary::make(@$, std::move($1), std::move($3), expr_binary::op::le); } | expr GREATER_EQUAL expr { $$ = expr_binary::make(@$, std::move($1), std::move($3), expr_binary::op::ge); } | expr LESS expr { $$ = expr_binary::make(@$, std::move($1), std::move($3), expr_binary::op::lt); } | expr GREATER expr { $$ = expr_binary::make(@$, std::move($1), std::move($3), expr_binary::op::gt); } | expr BITWISE_OR expr { $$ = expr_binary::make(@$, std::move($1), std::move($3), expr_binary::op::bwor); } | expr BITWISE_AND expr { $$ = expr_binary::make(@$, std::move($1), std::move($3), expr_binary::op::bwand); } | expr BITWISE_EXOR expr { $$ = expr_binary::make(@$, std::move($1), std::move($3), expr_binary::op::bwexor); } | expr LSHIFT expr { $$ = expr_binary::make(@$, std::move($1), std::move($3), expr_binary::op::shl); } | expr RSHIFT expr { $$ = expr_binary::make(@$, std::move($1), std::move($3), expr_binary::op::shr); } | expr ADD expr { $$ = expr_binary::make(@$, std::move($1), std::move($3), expr_binary::op::add); } | expr SUB expr { $$ = expr_binary::make(@$, std::move($1), std::move($3), expr_binary::op::sub); } | expr MUL expr { $$ = expr_binary::make(@$, std::move($1), std::move($3), expr_binary::op::mul); } | expr DIV expr { $$ = expr_binary::make(@$, std::move($1), std::move($3), expr_binary::op::div); } | expr MOD expr { $$ = expr_binary::make(@$, std::move($1), std::move($3), expr_binary::op::mod); } ; expr_primitive : expr_complement { $$ = std::move($1); } | expr_negate { $$ = std::move($1); } | expr_not { $$ = std::move($1); } | expr_call { $$ = std::move($1); } | expr_method { $$ = std::move($1); } | expr_getnextarraykey { $$ = std::move($1); } | expr_getfirstarraykey { $$ = std::move($1); } | expr_getdvarcoloralpha { $$ = std::move($1); } | expr_getdvarcolorblue { $$ = std::move($1); } | expr_getdvarcolorgreen { $$ = std::move($1); } | expr_getdvarcolorred { $$ = std::move($1); } | expr_getdvarvector { $$ = std::move($1); } | expr_getdvarfloat { $$ = std::move($1); } | expr_getdvarint { $$ = std::move($1); } | expr_getdvar { $$ = std::move($1); } | expr_gettime { $$ = std::move($1); } | expr_abs { $$ = std::move($1); } | expr_vectortoangles { $$ = std::move($1); } | expr_angleclamp180 { $$ = std::move($1); } | expr_anglestoforward { $$ = std::move($1); } | expr_anglestoright { $$ = std::move($1); } | expr_anglestoup { $$ = std::move($1); } | expr_vectorscale { $$ = std::move($1); } | expr_isdefined { $$ = std::move($1); } | expr_reference { $$ = std::move($1); } | expr_array { $$ = std::move($1); } | expr_field { $$ = std::move($1); } | expr_size { $$ = std::move($1); } | expr_paren { $$ = std::move($1); } | expr_empty_array { $$ = std::move($1); } | expr_undefined { $$ = std::move($1); } | expr_game { $$ = std::move($1); } | expr_self { $$ = std::move($1); } | expr_anim { $$ = std::move($1); } | expr_level { $$ = std::move($1); } | expr_animation { $$ = std::move($1); } | expr_animtree { $$ = std::move($1); } | expr_identifier { $$ = std::move($1); } | expr_istring { $$ = std::move($1); } | expr_string { $$ = std::move($1); } | expr_vector { $$ = std::move($1); } | expr_hash { $$ = std::move($1); } | expr_float { $$ = std::move($1); } | expr_integer { $$ = std::move($1); } | expr_false { $$ = std::move($1); } | expr_true { $$ = std::move($1); } ; expr_complement : COMPLEMENT expr { $$ = expr_complement::make(@$, std::move($2)); } ; expr_negate : SUB expr_identifier %prec NEG { $$ = expr_negate::make(@$, std::move($2)); } | SUB expr_paren %prec NEG { $$ = expr_negate::make(@$, std::move($2)); } | SUB expr_array %prec NEG { $$ = expr_negate::make(@$, std::move($2)); } | SUB expr_field %prec NEG { $$ = expr_negate::make(@$, std::move($2)); } ; expr_not : NOT expr { $$ = expr_not::make(@$, std::move($2)); } ; expr_call : expr_function { $$ = expr_call::make(@$, std::move($1)); } | expr_pointer { $$ = expr_call::make(@$, std::move($1)); } ; expr_method : expr_object expr_function { if ($1->loc().begin.line != $2->loc().begin.line) error($2->loc(), "missing ';' ?"); $$ = expr_method::make(@$, std::move($1), std::move($2)); } | expr_object expr_pointer { if ($1->loc().begin.line != $2->loc().begin.line) error($2->loc(), "missing ';' ?"); $$ = expr_method::make(@$, std::move($1), std::move($2)); } ; expr_function : expr_identifier LPAREN expr_arguments RPAREN { $$ = expr_function::make(@$, expr_path::make(@$), std::move($1), std::move($3), call::mode::normal); } | expr_path DOUBLECOLON expr_identifier LPAREN expr_arguments RPAREN { $$ = expr_function::make(@$, std::move($1), std::move($3), std::move($5), call::mode::normal); } | THREAD expr_identifier LPAREN expr_arguments RPAREN { $$ = expr_function::make(@$, expr_path::make(@$), std::move($2), std::move($4), call::mode::thread); } | THREAD expr_path DOUBLECOLON expr_identifier LPAREN expr_arguments RPAREN { $$ = expr_function::make(@$, std::move($2), std::move($4), std::move($6), call::mode::thread); } ; expr_pointer : LBRACKET LBRACKET expr RBRACKET RBRACKET LPAREN expr_arguments RPAREN { $$ = expr_pointer::make(@$, std::move($3), std::move($7), call::mode::normal); } | THREAD LBRACKET LBRACKET expr RBRACKET RBRACKET LPAREN expr_arguments RPAREN { $$ = expr_pointer::make(@$, std::move($4), std::move($8), call::mode::thread); } ; expr_parameters : expr_parameters COMMA expr_parameters_default { $$ = std::move($1); $$->list.push_back(std::move($3)); } | expr_parameters COMMA expr_identifier { $$ = std::move($1); $$->list.push_back(std::move($3)); } | expr_parameters_default { $$ = expr_parameters::make(@$); $$->list.push_back(std::move($1)); } | expr_identifier { $$ = expr_parameters::make(@$); $$->list.push_back(std::move($1)); } | { $$ = expr_parameters::make(@$); } ; expr_parameters_default : expr_identifier ASSIGN expr { $$ = expr_assign::make(@$, std::move($1), std::move($3), expr_assign::op::eq); } ; expr_arguments : expr_arguments_no_empty { $$ = std::move($1); } | { $$ = expr_arguments::make(@$); } ; expr_arguments_no_empty : expr_arguments COMMA expr { $$ = std::move($1); $$->list.push_back(std::move($3)); } | expr { $$ = expr_arguments::make(@$); $$->list.push_back(std::move($1)); } ; expr_getnextarraykey : GETNEXTARRAYKEY LPAREN expr COMMA expr RPAREN { $$ = expr_getnextarraykey::make(@$, std::move($3), std::move($5)); } ; expr_getfirstarraykey : GETFIRSTARRAYKEY LPAREN expr RPAREN { $$ = expr_getfirstarraykey::make(@$, std::move($3)); } ; expr_getdvarcoloralpha : GETDVARCOLORALPHA LPAREN expr RPAREN { $$ = expr_getdvarcoloralpha::make(@$, std::move($3)); } ; expr_getdvarcolorblue : GETDVARCOLORBLUE LPAREN expr RPAREN { $$ = expr_getdvarcolorblue::make(@$, std::move($3)); } ; expr_getdvarcolorgreen : GETDVARCOLORGREEN LPAREN expr RPAREN { $$ = expr_getdvarcolorgreen::make(@$, std::move($3)); } ; expr_getdvarcolorred : GETDVARCOLORRED LPAREN expr RPAREN { $$ = expr_getdvarcolorred::make(@$, std::move($3)); } ; expr_getdvarvector : GETDVARVECTOR LPAREN expr RPAREN { $$ = expr_getdvarvector::make(@$, std::move($3)); } ; expr_getdvarfloat : GETDVARFLOAT LPAREN expr RPAREN { $$ = expr_getdvarfloat::make(@$, std::move($3)); } ; expr_getdvarint : GETDVARINT LPAREN expr RPAREN { $$ = expr_getdvarint::make(@$, std::move($3)); } ; expr_getdvar : GETDVAR LPAREN expr RPAREN { $$ = expr_getdvar::make(@$, std::move($3)); } ; expr_gettime : GETTIME LPAREN RPAREN { $$ = expr_gettime::make(@$); } ; expr_abs : ABS LPAREN expr RPAREN { $$ = expr_abs::make(@$, std::move($3)); } ; expr_vectortoangles : VECTORTOANGLES LPAREN expr RPAREN { $$ = expr_vectortoangles::make(@$, std::move($3)); } ; expr_angleclamp180 : ANGLECLAMP180 LPAREN expr RPAREN { $$ = expr_angleclamp180::make(@$, std::move($3)); } ; expr_anglestoforward : ANGLESTOFORWARD LPAREN expr RPAREN { $$ = expr_anglestoforward::make(@$, std::move($3)); } ; expr_anglestoright : ANGLESTORIGHT LPAREN expr RPAREN { $$ = expr_anglestoright::make(@$, std::move($3)); } ; expr_anglestoup : ANGLESTOUP LPAREN expr RPAREN { $$ = expr_anglestoup::make(@$, std::move($3)); } ; expr_vectorscale : VECTORSCALE LPAREN expr COMMA expr RPAREN { $$ = expr_vectorscale::make(@$, std::move($3), std::move($5)); } ; expr_isdefined : ISDEFINED LPAREN expr RPAREN { $$ = expr_isdefined::make(@$, std::move($3)); } ; expr_reference : DOUBLECOLON expr_identifier { $$ = expr_reference::make(@$, expr_path::make(@$), std::move($2)); } | expr_path DOUBLECOLON expr_identifier { $$ = expr_reference::make(@$, std::move($1), std::move($3)); } ; expr_array : expr_object LBRACKET expr RBRACKET { $$ = expr_array::make(@$, std::move($1), std::move($3)); } | expr_getdvarvector LBRACKET expr RBRACKET { $$ = expr_array::make(@$, std::move($1), std::move($3)); } | expr_vectortoangles LBRACKET expr RBRACKET { $$ = expr_array::make(@$, std::move($1), std::move($3)); } | expr_angleclamp180 LBRACKET expr RBRACKET { $$ = expr_array::make(@$, std::move($1), std::move($3)); } | expr_anglestoforward LBRACKET expr RBRACKET { $$ = expr_array::make(@$, std::move($1), std::move($3)); } | expr_anglestoright LBRACKET expr RBRACKET { $$ = expr_array::make(@$, std::move($1), std::move($3)); } | expr_anglestoup LBRACKET expr RBRACKET { $$ = expr_array::make(@$, std::move($1), std::move($3)); } | expr_vectorscale LBRACKET expr RBRACKET { $$ = expr_array::make(@$, std::move($1), std::move($3)); } ; expr_field : expr_object DOT expr_identifier_nosize { $$ = expr_field::make(@$, std::move($1), std::move($3)); } ; expr_size : expr_object DOT SIZE %prec SIZEOF { $$ = expr_size::make(@$, std::move($1)); } ; expr_paren : LPAREN expr RPAREN { $$ = expr_paren::make(@$, std::move($2)); } ; expr_object : expr_call { $$ = std::move($1); } | expr_method { $$ = std::move($1); } | expr_array { $$ = std::move($1); } | expr_field { $$ = std::move($1); } | expr_game { $$ = std::move($1); } | expr_self { $$ = std::move($1); } | expr_anim { $$ = std::move($1); } | expr_level { $$ = std::move($1); } | expr_identifier { $$ = std::move($1); } ; expr_empty_array : LBRACKET RBRACKET { $$ = expr_empty_array::make(@$); }; ; expr_undefined : UNDEFINED { $$ = expr_undefined::make(@$); }; ; expr_game : GAME { $$ = expr_game::make(@$); }; ; expr_self : SELF { $$ = expr_self::make(@$); }; ; expr_anim : ANIM { $$ = expr_anim::make(@$); }; ; expr_level : LEVEL { $$ = expr_level::make(@$); }; ; expr_animation : MOD IDENTIFIER %prec ANIMREF { $$ = expr_animation::make(@$, $2); }; ; expr_animtree : ANIMTREE { $$ = expr_animtree::make(@$); }; ; expr_identifier_nosize : IDENTIFIER { $$ = expr_identifier::make(@$, $1); }; ; expr_identifier : IDENTIFIER { $$ = expr_identifier::make(@$, $1); }; | SIZE { $$ = expr_identifier::make(@$, "size"); }; ; expr_path : PATH DIV IDENTIFIER { $$ = expr_path::make(@$, $1 + "/" + $3); }; | IDENTIFIER { $$ = expr_path::make(@$, $1); }; | PATH { $$ = expr_path::make(@$, $1); }; ; expr_istring : ISTRING { $$ = expr_istring::make(@$, $1); }; ; expr_string : STRING { $$ = expr_string::make(@$, $1); }; ; expr_vector : LPAREN expr COMMA expr COMMA expr RPAREN { $$ = expr_vector::make(@$, std::move($2), std::move($4), std::move($6)); }; ; expr_hash : HASHSTR { $$ = expr_hash::make(@$, $1); }; ; expr_float : SUB FLOAT %prec NEG { $$ = expr_float::make(@$, "-" + $2); }; | FLOAT { $$ = expr_float::make(@$, $1); }; ; expr_integer : SUB INTEGER %prec NEG { $$ = expr_integer::make(@$, "-" + $2); }; | INTEGER { $$ = expr_integer::make(@$, $1); }; ; expr_false : FALSE { $$ = expr_false::make(@$); }; ; expr_true : TRUE { $$ = expr_true::make(@$); }; ; %% namespace xsk::arc { void parser::error(location const& loc, std::string const& msg) { throw comp_error(loc, msg); } auto parse_switch(stmt_switch& stm) -> void { auto body = stmt_list::make(stm.body->block->loc()); auto curr = stmt::ptr{ nullptr }; auto num = stm.body->block->list.size(); for (auto i = 0u; i < num; i++) { auto& entry = stm.body->block->list[0]; if (entry->is() || entry->is()) { if (curr != nullptr) { body->list.push_back(std::move(curr)); } curr = std::move(stm.body->block->list[0]); stm.body->block->list.erase(stm.body->block->list.begin()); } else { if (curr != nullptr) { if (curr->is()) { curr->as().body->list.push_back(std::move(entry)); stm.body->block->list.erase(stm.body->block->list.begin()); } else { curr->as().body->list.push_back(std::move(entry)); stm.body->block->list.erase(stm.body->block->list.begin()); } } else { throw comp_error(entry->loc(), "missing case statement"); } } } if (curr != nullptr) { body->list.push_back(std::move(curr)); } stm.body->block = std::move(body); } extern std::unordered_map const tok_to_parser; extern std::unordered_map const keyword_map; auto map_token(context const* ctx_, token& tok) -> parser::symbol_type { if (tok.type == token::NAME) { tok.data = ctx_->make_token(tok.data); auto const it = keyword_map.find(tok.data); if (it != keyword_map.end()) { return parser::symbol_type(it->second, tok.pos); } return parser::symbol_type(parser::token::IDENTIFIER, std::move(tok.data), tok.pos); } else if (tok.type == token::PATH ||tok.type == token::HASHSTR ||tok.type == token::STRING ||tok.type == token::ISTRING || tok.type == token::INT ||tok.type == token::FLT) { auto it = tok_to_parser.find(tok.type); if (it != tok_to_parser.end()) { return parser::symbol_type(it->second, std::move(tok.data), tok.pos); } } else { auto it = tok_to_parser.find(tok.type); if (it != tok_to_parser.end()) { return parser::symbol_type(it->second, tok.pos); } } throw error(fmt::format("unmapped token! {}", (u8)tok.type)); } auto ARClex(context const* ctx_, preprocessor& ppr) -> parser::symbol_type { auto tok = ppr.process(); return map_token(ctx_, tok); } std::unordered_map const tok_to_parser {{ { token::NAME, parser::token::IDENTIFIER }, { token::PATH, parser::token::PATH }, { token::STRING, parser::token::STRING }, { token::ISTRING, parser::token::ISTRING }, { token::HASHSTR, parser::token::HASHSTR }, { token::INT, parser::token::INTEGER }, { token::FLT, parser::token::FLOAT }, { token::PLUS, parser::token::ADD }, { token::MINUS, parser::token::SUB }, { token::STAR, parser::token::MUL }, { token::DIV, parser::token::DIV }, { token::MOD, parser::token::MOD }, { token::BITOR, parser::token::BITWISE_OR }, { token::BITAND, parser::token::BITWISE_AND }, { token::BITEXOR, parser::token::BITWISE_EXOR }, { token::ASSIGN, parser::token::ASSIGN }, { token::PLUSEQ, parser::token::ASSIGN_ADD }, { token::MINUSEQ, parser::token::ASSIGN_SUB }, { token::STAREQ, parser::token::ASSIGN_MUL }, { token::DIVEQ, parser::token::ASSIGN_DIV }, { token::MODEQ, parser::token::ASSIGN_MOD }, { token::BITOREQ, parser::token::ASSIGN_BW_OR }, { token::BITANDEQ, parser::token::ASSIGN_BW_AND }, { token::BITEXOREQ, parser::token::ASSIGN_BW_EXOR }, { token::SHLEQ, parser::token::ASSIGN_LSHIFT }, { token::SHREQ, parser::token::ASSIGN_RSHIFT }, { token::TILDE, parser::token::COMPLEMENT }, { token::BANG, parser::token::NOT }, { token::GT, parser::token::GREATER }, { token::LT, parser::token::LESS }, { token::GE, parser::token::GREATER_EQUAL }, { token::LE, parser::token::LESS_EQUAL }, { token::NE, parser::token::INEQUALITY }, { token::EQ, parser::token::EQUALITY }, { token::OR, parser::token::OR }, { token::AND, parser::token::AND }, { token::SHL, parser::token::LSHIFT }, { token::SHR, parser::token::RSHIFT }, { token::INC, parser::token::INCREMENT }, { token::DEC, parser::token::DECREMENT }, { token::QMARK, parser::token::QMARK }, { token::DOT, parser::token::DOT }, { token::DOUBLEDOT, parser::token::DOUBLEDOT }, { token::ELLIPSIS, parser::token::ELLIPSIS }, { token::COMMA, parser::token::COMMA }, { token::COLON, parser::token::COLON }, { token::SEMICOLON, parser::token::SEMICOLON }, { token::DOUBLECOLON, parser::token::DOUBLECOLON }, { token::LBRACKET, parser::token::LBRACKET }, { token::RBRACKET, parser::token::RBRACKET }, { token::LBRACE, parser::token::LBRACE }, { token::RBRACE, parser::token::RBRACE }, { token::LPAREN, parser::token::LPAREN }, { token::RPAREN, parser::token::RPAREN }, { token::DEVBEGIN, parser::token::DEVBEGIN }, { token::DEVEND, parser::token::DEVEND }, { token::INLINE, parser::token::INLINE }, { token::INCLUDE, parser::token::INCLUDE }, { token::USINGTREE, parser::token::USINGTREE }, { token::ANIMTREE, parser::token::ANIMTREE }, { token::AUTOEXEC, parser::token::AUTOEXEC }, { token::CODECALL, parser::token::CODECALL }, { token::PRIVATE, parser::token::PRIVATE }, { token::ENDON, parser::token::ENDON }, { token::NOTIFY, parser::token::NOTIFY }, { token::WAIT, parser::token::WAIT }, { token::WAITTILL, parser::token::WAITTILL }, { token::WAITTILLMATCH, parser::token::WAITTILLMATCH }, { token::WAITTILLFRAMEEND, parser::token::WAITTILLFRAMEEND }, { token::IF, parser::token::IF }, { token::ELSE, parser::token::ELSE }, { token::DO, parser::token::DO }, { token::WHILE, parser::token::WHILE }, { token::FOR, parser::token::FOR }, { token::FOREACH, parser::token::FOREACH }, { token::IN, parser::token::IN }, { token::SWITCH, parser::token::SWITCH }, { token::CASE, parser::token::CASE }, { token::DEFAULT, parser::token::DEFAULT }, { token::BREAK, parser::token::BREAK }, { token::CONTINUE, parser::token::CONTINUE }, { token::RETURN, parser::token::RETURN }, { token::PROFBEGIN, parser::token::PROFBEGIN }, { token::PROFEND, parser::token::PROFEND }, { token::THREAD, parser::token::THREAD }, { token::TRUE, parser::token::TRUE }, { token::FALSE, parser::token::FALSE }, { token::UNDEFINED, parser::token::UNDEFINED }, { token::SIZE, parser::token::SIZE }, { token::GAME, parser::token::GAME }, { token::SELF, parser::token::SELF }, { token::ANIM, parser::token::ANIM }, { token::LEVEL, parser::token::LEVEL }, { token::CONST, parser::token::CONST }, { token::ISDEFINED, parser::token::ISDEFINED }, { token::VECTORSCALE, parser::token::VECTORSCALE }, { token::ANGLESTOUP, parser::token::ANGLESTOUP }, { token::ANGLESTORIGHT, parser::token::ANGLESTORIGHT }, { token::ANGLESTOFORWARD, parser::token::ANGLESTOFORWARD }, { token::ANGLECLAMP180, parser::token::ANGLECLAMP180 }, { token::VECTORTOANGLES, parser::token::VECTORTOANGLES }, { token::ABS, parser::token::ABS }, { token::GETTIME, parser::token::GETTIME }, { token::GETDVAR, parser::token::GETDVAR }, { token::GETDVARINT, parser::token::GETDVARINT }, { token::GETDVARFLOAT, parser::token::GETDVARFLOAT }, { token::GETDVARVECTOR, parser::token::GETDVARVECTOR }, { token::GETDVARCOLORRED, parser::token::GETDVARCOLORRED }, { token::GETDVARCOLORGREEN, parser::token::GETDVARCOLORGREEN }, { token::GETDVARCOLORBLUE, parser::token::GETDVARCOLORBLUE }, { token::GETDVARCOLORALPHA, parser::token::GETDVARCOLORALPHA }, { token::GETFIRSTARRAYKEY, parser::token::GETFIRSTARRAYKEY }, { token::GETNEXTARRAYKEY, parser::token::GETNEXTARRAYKEY }, { token::EOS, parser::token::ARCEOF }, { token::HASH, parser::token::HASH } }}; std::unordered_map const keyword_map {{ { "autoexec", parser::token::AUTOEXEC }, { "codecall", parser::token::CODECALL }, { "private", parser::token::PRIVATE }, { "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 }, { "prof_begin", parser::token::PROFBEGIN }, { "prof_end", parser::token::PROFEND }, { "thread", parser::token::THREAD }, { "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 }, { "const", parser::token::CONST }, { "isdefined", parser::token::ISDEFINED }, { "vectorscale", parser::token::VECTORSCALE }, { "anglestoup", parser::token::ANGLESTOUP }, { "anglestoright", parser::token::ANGLESTORIGHT }, { "anglestoforward", parser::token::ANGLESTOFORWARD }, { "angleclamp180", parser::token::ANGLECLAMP180 }, { "vectortoangles", parser::token::VECTORTOANGLES }, { "abs", parser::token::ABS }, { "gettime", parser::token::GETTIME }, { "getdvar", parser::token::GETDVAR }, { "getdvarint", parser::token::GETDVARINT }, { "getdvarfloat", parser::token::GETDVARFLOAT }, { "getdvarvector", parser::token::GETDVARVECTOR }, { "getdvarcolorred", parser::token::GETDVARCOLORRED }, { "getdvarcolorgreen", parser::token::GETDVARCOLORGREEN }, { "getdvarcolorblue", parser::token::GETDVARCOLORBLUE }, { "getdvarcoloralpha", parser::token::GETDVARCOLORALPHA }, { "getfirstarraykey", parser::token::GETFIRSTARRAYKEY }, { "getnextarraykey", parser::token::GETNEXTARRAYKEY }, }}; } // namespace xsk::arc