diff options
Diffstat (limited to 'src/map/magic-interpreter-parser.ypp')
-rw-r--r-- | src/map/magic-interpreter-parser.ypp | 1441 |
1 files changed, 0 insertions, 1441 deletions
diff --git a/src/map/magic-interpreter-parser.ypp b/src/map/magic-interpreter-parser.ypp deleted file mode 100644 index ef8b159..0000000 --- a/src/map/magic-interpreter-parser.ypp +++ /dev/null @@ -1,1441 +0,0 @@ -%code requires -{ -#include "magic-interpreter.hpp" - -extern -AString current_magic_filename; -} // %code requires - -%code -{ -#include "magic-interpreter-parser.hpp" - -#include <cassert> -#include <cstdarg> // exception to "no va_list" rule, even after cxxstdio - -#include "../strings/rstring.hpp" -#include "../strings/astring.hpp" -#include "../strings/zstring.hpp" - -#include "../generic/const_array.hpp" - -#include "../io/cxxstdio.hpp" - -#include "itemdb.hpp" -#include "magic-expr.hpp" - -AString current_magic_filename; - -// can't use src/warnings.hpp in generated code -#pragma GCC diagnostic warning "-Wall" -#pragma GCC diagnostic warning "-Wextra" -#pragma GCC diagnostic warning "-Wformat" -#ifndef __clang__ -# pragma GCC diagnostic ignored "-Wmissing-field-initializers" -#endif - -static -size_t intern_id(ZString id_name); - -static -dumb_ptr<expr_t> fun_expr(AString name, const_array<dumb_ptr<expr_t>> argv, int line, int column); - -static -dumb_ptr<expr_t> dot_expr(dumb_ptr<expr_t> lhs, int id); - -static -void BIN_EXPR(dumb_ptr<expr_t>& x, AString name, dumb_ptr<expr_t> arg1, dumb_ptr<expr_t> arg2, int line, int column) -{ - dumb_ptr<expr_t> e[2]; - e[0] = arg1; - e[1] = arg2; - x = fun_expr(name, const_array<dumb_ptr<expr_t>>(e, 2), line, column); -} - -static -int failed_flag = 0; - -static -void magic_frontend_error(const char *msg); - -static __attribute__((format(printf, 3, 4))) -void fail(int line, int column, const char *fmt, ...); - -static -dumb_ptr<spell_t> new_spell(dumb_ptr<spellguard_t> guard); - -static -dumb_ptr<spellguard_t> spellguard_implication(dumb_ptr<spellguard_t> a, dumb_ptr<spellguard_t> b); - -static -dumb_ptr<spellguard_t> new_spellguard(SPELLGUARD ty); - -static -dumb_ptr<effect_t> new_effect(EFFECT ty); - -static -dumb_ptr<effect_t> set_effect_continuation(dumb_ptr<effect_t> src, dumb_ptr<effect_t> continuation); - -static -void add_spell(dumb_ptr<spell_t> spell, int line_nr); - -static -void add_teleport_anchor(dumb_ptr<teleport_anchor_t> anchor, int line_nr); - -static -dumb_ptr<effect_t> op_effect(AString name, const_array<dumb_ptr<expr_t>> argv, int line, int column); - -// in magic-interpreter-lexer.cpp -int magic_frontend_lex(void); - -static -void install_proc(dumb_ptr<proc_t> proc); - -static -dumb_ptr<effect_t> call_proc(ZString name, dumb_ptr<std::vector<dumb_ptr<expr_t>>> argvp, int line_nr, int column); - -static -void bind_constant(RString name, val_t *val, int line_nr); - -static -val_t *find_constant(RString name); - -} // %code - -%name-prefix="magic_frontend_" - -%locations - -%union -{ - int i; - SPELL_FLAG spell_flags; - SPELLARG spell_arg; - FOREACH_FILTER foreach_filter; - dumb_string s; - int op; - // magic_conf_t *magic_conf; - val_t value; - dumb_ptr<expr_t> expr; - e_location_t location; - e_area_t area; - args_rec_t arg_list; - dumb_ptr<std::vector<letdef_t>> letdefvp; - dumb_ptr<spell_t> spell; - struct { int id; SPELLARG ty; } spellarg_def; - letdef_t vardef; - dumb_ptr<spellguard_t> spellguard; - dumb_ptr<component_t> components; - struct { int id, count; } component; - dumb_ptr<effect_t> effect; - dumb_ptr<proc_t> proc; - - // evil hackery - YYSTYPE() { really_memzero_this(this); } - ~YYSTYPE() = default; - YYSTYPE(const YYSTYPE& rhs) = default; - YYSTYPE& operator = (const YYSTYPE& rhs) = default; -} // %union - -%expect 7 - -%token <i> INT -%token <s> STRING -%token <s> ID -%token <i> DIR - -%token '=' -%token '<' -%token '>' -%token '+' -%token '-' -%token '*' -%token '/' -%token '%' -%token '@' -%token ',' -%token '.' -%token ':' -%token ';' -%token '|' -%token '[' -%token ']' -%token '&' -%token '^' - -%token CONST -%token PROCEDURE -%token CALL -%token SILENT -%token LOCAL -%token NONMAGIC -%token SHL -%token SHR -%token EQ -%token NEQ -%token GTE -%token LTE -%token ANDAND -%token OROR -%token <s> SCRIPT_DATA -%token TO -%token TOWARDS -%token TELEPORT_ANCHOR -%token SPELL -%token LET -%token IN -%token END -%token DARROW -%token STRING_TY -%token REQUIRE -%token CATALYSTS -%token COMPONENTS -%token MANA -%token CASTTIME -%token SKIP -%token ABORT -%token BREAK -%token EFFECT_ -%token ATEND -%token ATTRIGGER -%token PC_F -%token NPC_F -%token MOB_F -%token ENTITY_F -%token TARGET_F -%token IF -%token THEN -%token ELSE -%token FOREACH -%token FOR -%token DO -%token SLEEP - -%type <value> value -%type <location> location -%type <area> area -%type <arg_list> arg_list -%type <arg_list> arg_list_ne -%type <letdefvp> defs -%type <spell> spelldef -%type <spellarg_def> argopt -%type <vardef> def -%type <spellguard> spellbody_list -%type <spellguard> spellbody -%type <spellguard> spellguard -%type <spellguard> spellguard_list -%type <spellguard> prereq -%type <component> item -%type <components> items -%type <components> item_list -%type <i> item_name -%type <foreach_filter> selection; -%type <effect> effect -%type <effect> effect_list -%type <effect> maybe_trigger -%type <effect> maybe_end -%type <spell_flags> spell_flags; - -%type <expr> expr -%type <spell_arg> arg_ty -%type <proc> proc_formals_list -%type <proc> proc_formals_list_ne - -%left OROR -%left ANDAND -%left '<' '>' GTE LTE NEQ EQ -%left '+' '-' -%left '*' '/' '%' -%left SHL SHR '&' '^' '|' -%right '=' -%left OR -%left DARROW -%left '.' - -%% - -spellconf - -: /* empty */ -{} - -| spellconf_option semicolons spellconf -{} - -; - - -semicolons - -: /* empty */ -{} - -| semicolons ';' -{} - -; - - -proc_formals_list - -: /* empty */ -{ - $$ = dumb_ptr<proc_t>::make(); -} - -| proc_formals_list_ne -{ - $$ = $1; -} - -; - - -proc_formals_list_ne - -: ID -{ - $$ = dumb_ptr<proc_t>::make(); - $$->argv.push_back(intern_id($1)); - $1.delete_(); -} - -| proc_formals_list_ne ',' ID -{ - $$ = $1; - $$->argv.push_back(intern_id($3)); - $3.delete_(); -} - -; - - -spellconf_option - -: ID '=' expr -{ - if (find_constant($1.str())) - { - fail(@1.first_line, 0, "Attempt to redefine constant `%s' as global\n", $1.c_str()); - } - else - { - int var_id = intern_id($1); - magic_eval(dumb_ptr<env_t>(&magic_default_env), &magic_conf.varv[var_id].val, $3); - } - $1.delete_(); -} - -| CONST ID '=' expr -{ - val_t var; - magic_eval(dumb_ptr<env_t>(&magic_default_env), &var, $4); - bind_constant($2.str(), &var, @1.first_line); - $2.delete_(); -} - -| TELEPORT_ANCHOR ID ':' expr '=' expr -{ - auto anchor = dumb_ptr<teleport_anchor_t>::make(); - anchor->name = $2.str(); - $2.delete_(); - anchor->invocation = magic_eval_str(dumb_ptr<env_t>(&magic_default_env), $4); - anchor->location = $6; - - if (!failed_flag) - add_teleport_anchor(anchor, @1.first_line); - else - anchor.delete_(); - failed_flag = 0; -} - -| PROCEDURE ID '(' proc_formals_list ')' '=' effect_list -{ - dumb_ptr<proc_t> proc = $4; - proc->name = $2.str(); - $2.delete_(); - proc->body = $7; - if (!failed_flag) - install_proc(proc); - proc.delete_(); - failed_flag = 0; -} - -| spell_flags SPELL ID argopt ':' expr '=' spelldef -{ - dumb_ptr<spell_t> spell = $8; - spell->name = $3.str(); - $3.delete_(); - spell->invocation = magic_eval_str(dumb_ptr<env_t>(&magic_default_env), $6); - spell->arg = $4.id; - spell->spellarg_ty = $4.ty; - spell->flags = $1; - if (!failed_flag) - add_spell(spell, @1.first_line); - failed_flag = 0; -} - -; - - -spell_flags - -: /* empty */ -{ - $$ = SPELL_FLAG::ZERO; -} - -| LOCAL spell_flags -{ - if (bool($2 & SPELL_FLAG::LOCAL)) - fail(@1.first_line, @1.first_column, "`LOCAL' specified more than once"); - $$ = $2 | SPELL_FLAG::LOCAL; -} - -| NONMAGIC spell_flags -{ - if (bool($2 & SPELL_FLAG::NONMAGIC)) - fail(@1.first_line, @1.first_column, "`NONMAGIC' specified more than once"); - $$ = $2 | SPELL_FLAG::NONMAGIC; -} - -| SILENT spell_flags -{ - if (bool($2 & SPELL_FLAG::SILENT)) - fail(@1.first_line, @1.first_column, "`SILENT' specified more than once"); - $$ = $2 | SPELL_FLAG::SILENT; -} - -; - - -argopt - -: /* empty */ -{ - $$.ty = SPELLARG::NONE; -} - -| '(' ID ':' arg_ty ')' -{ - $$.id = intern_id($2); - $2.delete_(); - $$.ty = $4; -} - -; - - -arg_ty - -: PC_F -{ - $$ = SPELLARG::PC; -} - -| STRING_TY -{ - $$ = SPELLARG::STRING; -} - -; - - -value - -: DIR -{ - $$.ty = TYPE::DIR; - $$.v.v_int = $1; -} - -| INT -{ - $$.ty = TYPE::INT; - $$.v.v_int = $1; -} - -| STRING -{ - $$.ty = TYPE::STRING; - $$.v.v_string = $1; -} - -; - - -expr - -: value -{ - $$ = magic_new_expr(EXPR::VAL); - $$->e.e_val = $1; -} - -| ID -{ - val_t *val = find_constant($1.str()); - if (val) - { - $$ = magic_new_expr(EXPR::VAL); - $$->e.e_val = *val; - } - else - { - $$ = magic_new_expr(EXPR::ID); - $$->e.e_id = intern_id($1); - } - $1.delete_(); -} - -| area -{ - $$ = magic_new_expr(EXPR::AREA); - $$->e.e_area = $1; -} - -| expr '+' expr -{ - BIN_EXPR($$, "+", $1, $3, @1.first_line, @1.first_column); -} - -| expr '-' expr -{ - BIN_EXPR($$, "-", $1, $3, @1.first_line, @1.first_column); -} - -| expr '*' expr -{ - BIN_EXPR($$, "*", $1, $3, @1.first_line, @1.first_column); -} - -| expr '%' expr -{ - BIN_EXPR($$, "%", $1, $3, @1.first_line, @1.first_column); -} - -| expr '/' expr -{ - BIN_EXPR($$, "/", $1, $3, @1.first_line, @1.first_column); -} - -| expr '<' expr -{ - BIN_EXPR($$, ">", $3, $1, @1.first_line, @1.first_column); -} - -| expr '>' expr -{ - BIN_EXPR($$, ">", $1, $3, @1.first_line, @1.first_column); -} - -| expr '&' expr -{ - BIN_EXPR($$, "&", $1, $3, @1.first_line, @1.first_column); -} - -| expr '^' expr -{ - BIN_EXPR($$, "^", $1, $3, @1.first_line, @1.first_column); -} - -| expr '|' expr -{ - BIN_EXPR($$, "|", $1, $3, @1.first_line, @1.first_column); -} - -| expr SHL expr -{ - BIN_EXPR($$, "<<", $1, $3, @1.first_line, @1.first_column); -} - -| expr SHR expr -{ - BIN_EXPR($$, ">>", $1, $3, @1.first_line, @1.first_column); -} - -| expr LTE expr -{ - BIN_EXPR($$, ">=", $3, $1, @1.first_line, @1.first_column); -} - -| expr GTE expr -{ - BIN_EXPR($$, ">=", $1, $3, @1.first_line, @1.first_column); -} - -| expr ANDAND expr -{ - BIN_EXPR($$, "&&", $1, $3, @1.first_line, @1.first_column); -} - -| expr OROR expr -{ - BIN_EXPR($$, "||", $1, $3, @1.first_line, @1.first_column); -} - -| expr EQ expr -{ - BIN_EXPR($$, "=", $1, $3, @1.first_line, @1.first_column); -} - -| expr '=' expr -{ - BIN_EXPR($$, "=", $1, $3, @1.first_line, @1.first_column); -} - -| expr NEQ expr -{ - BIN_EXPR($$, "=", $1, $3, @1.first_line, @1.first_column); - $$ = fun_expr("not", const_array<dumb_ptr<expr_t>>(&$$, 1), @1.first_line, @1.first_column); -} - -| ID '(' arg_list ')' -{ - $$ = fun_expr($1.str(), *$3.argvp, @1.first_line, @1.first_column); - $3.argvp.delete_(); - $1.delete_(); // allocated from m-i-lexer.lpp -} - -| '(' expr ')' -{ - $$ = $2; -} - -| expr '.' ID -{ - $$ = dot_expr($1, intern_id($3)); - $3.delete_(); -} - -; - - -arg_list - -: /* empty */ -{ - $$.argvp.new_(); -} - -| arg_list_ne -{ - $$ = $1; -} - -; - - -arg_list_ne - -: expr -{ - $$.argvp.new_(); - $$.argvp->push_back($1); -} - -| arg_list_ne ',' expr -{ - // yikes! Fate is officially banned from ever touching my code again. - $$ = $1; - $$.argvp->push_back($3); -} - -; - - -location - -: '@' '(' expr ',' expr ',' expr ')' -{ - $$.m = $3; - $$.x = $5; - $$.y = $7; -} - -; - - -area - -: location -{ - $$.ty = AREA::LOCATION; - $$.a.a_loc = $1; -} - -| location '@' '+' '(' expr ',' expr ')' -{ - $$.ty = AREA::RECT; - $$.a.a_rect.loc = $1; - $$.a.a_rect.width = $5; - $$.a.a_rect.height = $7; -} - -| location TOWARDS expr ':' '(' expr ',' expr ')' -{ - $$.ty = AREA::BAR; - $$.a.a_bar.loc = $1; - $$.a.a_bar.width = $6; - $$.a.a_bar.depth = $8; - $$.a.a_bar.dir = $3; -} - -; - - -spelldef - -: spellbody_list -{ - $$ = new_spell($1); -} - -| LET defs IN spellbody_list -{ - $$ = new_spell($4); - $$->letdefv = std::move(*$2); - $2.delete_(); - $$->spellguard = $4; -} - -; - - -defs - -: semicolons -{ - $$.new_(); -} - -| defs def semicolons -{ - $$ = $1; - $$->push_back($2); -} - -; - - -def - -: ID '=' expr -{ - if (find_constant($1.str())) - { - fail(@1.first_line, @1.first_column, "Attempt to re-define constant `%s' as LET-bound variable.\n", $1.c_str()); - } - else - { - $$.id = intern_id($1); - $$.expr = $3; - } - $1.delete_(); -} - -; - - -spellbody_list - -: spellbody -{ - $$ = $1; -} - -| spellbody '|' spellbody_list -{ - dumb_ptr<spellguard_t> sg = new_spellguard(SPELLGUARD::CHOICE); - sg->next = $1; - sg->s.s_alt = $3; - $$ = sg; -} - -; - - -spellbody - -: spellguard DARROW spellbody -{ - $$ = spellguard_implication($1, $3); -} - -| '(' spellbody_list ')' -{ - $$ = $2; -} - -| EFFECT_ effect_list maybe_trigger maybe_end -{ - dumb_ptr<spellguard_t> sg = new_spellguard(SPELLGUARD::EFFECT); - sg->s.s_effect.effect = $2; - sg->s.s_effect.at_trigger = $3; - sg->s.s_effect.at_end = $4; - $$ = sg; -} - -; - - -maybe_trigger - -: /* empty */ -{ - $$ = NULL; -} - -| ATTRIGGER effect_list -{ - $$ = $2; -} - -; - - -maybe_end - -: /* empty */ -{ - $$ = NULL; -} - -| ATEND effect_list -{ - $$ = $2; -} - -; - - -spellguard - -: prereq -{ - $$ = $1; -} - -| spellguard OR spellguard -{ - dumb_ptr<spellguard_t> sg = new_spellguard(SPELLGUARD::CHOICE); - sg->next = $1; - sg->s.s_alt = $3; - $$ = sg; -} - -| '(' spellguard_list ')' -{ - $$ = $2; -} - -; - - -spellguard_list - -: spellguard -{ - $$ = $1; -} - -| spellguard ',' spellguard_list -{ - $$ = spellguard_implication($1, $3); -} - -; - - -prereq - -: REQUIRE expr -{ - $$ = new_spellguard(SPELLGUARD::CONDITION); - $$->s.s_condition = $2; -} - -| CATALYSTS items -{ - $$ = new_spellguard(SPELLGUARD::CATALYSTS); - $$->s.s_catalysts = $2; -} - -| COMPONENTS items -{ - $$ = new_spellguard(SPELLGUARD::COMPONENTS); - $$->s.s_components = $2; -} - -| MANA expr -{ - $$ = new_spellguard(SPELLGUARD::MANA); - $$->s.s_mana = $2; -} - -| CASTTIME expr -{ - $$ = new_spellguard(SPELLGUARD::CASTTIME); - $$->s.s_casttime = $2; -} - -; - - -items - -: '[' item_list ']' -{ - $$ = $2; -} - -; - - -item_list - -: item -{ - $$ = NULL; - magic_add_component(&$$, $1.id, $1.count); -} - -| item_list ',' item -{ - $$ = $1; - magic_add_component(&$$, $3.id, $3.count); -} - -; - - -item - -: INT '*' item_name -{ - $$.id = $3; - $$.count = $1; -} - -| item_name -{ - $$.id = $1; - $$.count = 1; -} - -; - - -item_name - -: STRING -{ - struct item_data *item = itemdb_searchname(stringish<ItemName>(ZString($1))); - if (!item) - { - fail(@1.first_line, @1.first_column, "Unknown item `%s'\n", $1.c_str()); - $$ = 0; - } - else - $$ = item->nameid; - $1.delete_(); -} - -| INT -{ - $$ = $1; -} - -; - - -selection - -: PC_F -{ - $$ = FOREACH_FILTER::PC; -} - -| MOB_F -{ - $$ = FOREACH_FILTER::MOB; -} - -| ENTITY_F -{ - $$ = FOREACH_FILTER::ENTITY; -} - -| SPELL -{ - $$ = FOREACH_FILTER::SPELL; -} - -| TARGET_F -{ - $$ = FOREACH_FILTER::TARGET; -} - -| NPC_F -{ - $$ = FOREACH_FILTER::NPC; -} - -; - - -effect - -: '(' effect_list ')' -{ - $$ = $2; -} - -| SKIP ';' -{ - $$ = new_effect(EFFECT::SKIP); -} - -| ABORT ';' -{ - $$ = new_effect(EFFECT::ABORT); -} - -| END ';' -{ - $$ = new_effect(EFFECT::END); -} - -| BREAK ';' -{ - $$ = new_effect(EFFECT::BREAK); -} - -| ID '=' expr ';' -{ - if (find_constant($1.str())) - { - fail(@1.first_line, @1.first_column, "Attempt to re-define constant `%s' in assignment.", $1.c_str()); - } - else - { - $$ = new_effect(EFFECT::ASSIGN); - $$->e.e_assign.id = intern_id($1); - $$->e.e_assign.expr = $3; - } - $1.delete_(); -} - -| FOREACH selection ID IN expr DO effect -{ - $$ = new_effect(EFFECT::FOREACH); - $$->e.e_foreach.id = intern_id($3); - $3.delete_(); - $$->e.e_foreach.area = $5; - $$->e.e_foreach.body = $7; - $$->e.e_foreach.filter = $2; -} - -| FOR ID '=' expr TO expr DO effect -{ - $$ = new_effect(EFFECT::FOR); - $$->e.e_for.id = intern_id($2); - $2.delete_(); - $$->e.e_for.start = $4; - $$->e.e_for.stop = $6; - $$->e.e_for.body = $8; -} - -| IF expr THEN effect ELSE effect -{ - $$ = new_effect(EFFECT::IF); - $$->e.e_if.cond = $2; - $$->e.e_if.true_branch = $4; - $$->e.e_if.false_branch = $6; -} - -| IF expr THEN effect -{ - $$ = new_effect(EFFECT::IF); - $$->e.e_if.cond = $2; - $$->e.e_if.true_branch = $4; - $$->e.e_if.false_branch = new_effect(EFFECT::SKIP); -} - -| SLEEP expr ';' -{ - $$ = new_effect(EFFECT::SLEEP); - $$->e.e_sleep = $2; -} - -| ID '(' arg_list ')' ';' -{ - $$ = op_effect($1.str(), *$3.argvp, @1.first_line, @1.first_column); - $1.delete_(); -} - -| SCRIPT_DATA -{ - $$ = new_effect(EFFECT::SCRIPT); - $$->e.e_script = dumb_ptr<const ScriptBuffer>(parse_script(ZString($1), @1.first_line).release()); - $1.delete_(); - if ($$->e.e_script == NULL) - fail(@1.first_line, @1.first_column, "Failed to compile script\n"); -} - -| CALL ID '(' arg_list ')' ';' -{ - $$ = call_proc($2, $4.argvp, @1.first_line, @1.first_column); - $2.delete_(); -} - -; - - -effect_list - -: /* empty */ -{ - $$ = new_effect(EFFECT::SKIP); -} - -| effect semicolons effect_list -{ - $$ = set_effect_continuation($1, $3); -} - -; - - -%% - -size_t intern_id(ZString id_name) -{ - size_t i; - for (i = 0; i < magic_conf.varv.size(); i++) - if (id_name == magic_conf.varv[i].name) - return i; - - // i = magic_conf.varv.size(); - /* Must add new */ - magic_conf_t::mcvar new_var {}; - new_var.name = id_name; - new_var.val.ty = TYPE::UNDEF; - magic_conf.varv.push_back(new_var); - - return i; -} - -void add_spell(dumb_ptr<spell_t> spell, int line_nr) -{ - auto pair1 = magic_conf.spells_by_name.insert({spell->name, spell}); - if (!pair1.second) - { - fail(line_nr, 0, "Attempt to redefine spell `%s'\n", spell->name.c_str()); - return; - } - - auto pair2 = magic_conf.spells_by_invocation.insert({spell->invocation, spell}); - if (!pair2.second) - { - fail(line_nr, 0, "Attempt to redefine spell invocation `%s' between spells `%s' and `%s'\n", - spell->invocation.c_str(), pair1.first->second->name.c_str(), spell->name.c_str()); - magic_conf.spells_by_name.erase(pair1.first); - return; - } -} - -void add_teleport_anchor(dumb_ptr<teleport_anchor_t> anchor, int line_nr) -{ - auto pair1 = magic_conf.anchors_by_name.insert({anchor->name, anchor}); - if (!pair1.second) - { - fail(line_nr, 0, "Attempt to redefine teleport anchor `%s'\n", anchor->name.c_str()); - return; - } - - auto pair2 = magic_conf.anchors_by_invocation.insert({anchor->name, anchor}); - if (!pair2.second) - { - fail(line_nr, 0, "Attempt to redefine anchor invocation `%s' between anchors `%s' and `%s'\n", - anchor->invocation.c_str(), pair1.first->second->name.c_str(), anchor->name.c_str()); - magic_conf.anchors_by_name.erase(pair1.first); - return; - } -} - - -void fail(int line, int column, const char *fmt, ...) -{ - va_list ap; - FPRINTF(stderr, "[magic-init] L%d:%d: ", line, column); - va_start(ap, fmt); - vfprintf(stderr, fmt, ap); - failed_flag = 1; -} - -dumb_ptr<expr_t> dot_expr(dumb_ptr<expr_t> expr, int id) -{ - dumb_ptr<expr_t> retval = magic_new_expr(EXPR::SPELLFIELD); - retval->e.e_field.id = id; - retval->e.e_field.expr = expr; - - return retval; -} - -dumb_ptr<expr_t> fun_expr(AString name, const_array<dumb_ptr<expr_t>> argv, int line, int column) -{ - dumb_ptr<expr_t> expr; - fun_t *fun = magic_get_fun(name); - - if (!fun) - fail(line, column, "Unknown function `%s'\n", name.c_str()); - else if (fun->signature.size() != argv.size()) - { - fail(line, column, "Incorrect number of arguments to function `%s': Expected %zu, found %zu\n", - name.c_str(), fun->signature.size(), argv.size()); - fun = NULL; - } - - if (fun) - { - expr = magic_new_expr(EXPR::FUNAPP); - expr->e.e_funapp.line_nr = line; - expr->e.e_funapp.column = column; - expr->e.e_funapp.funp = fun; - - assert (argv.size() <= MAX_ARGS); - expr->e.e_funapp.args_nr = argv.size(); - - std::copy(argv.begin(), argv.end(), expr->e.e_funapp.args); - } - else - { - /* failure */ - expr = magic_new_expr(EXPR::VAL); - expr->e.e_val.ty = TYPE::FAIL; - } - - return expr; -} - -dumb_ptr<spell_t> new_spell(dumb_ptr<spellguard_t> guard) -{ - auto retval = dumb_ptr<spell_t>::make(); - retval->spellguard = guard; - return retval; -} - -dumb_ptr<spellguard_t> new_spellguard(SPELLGUARD ty) -{ - dumb_ptr<spellguard_t> retval = dumb_ptr<spellguard_t>::make(); - retval->ty = ty; - return retval; -} - -dumb_ptr<spellguard_t> spellguard_implication(dumb_ptr<spellguard_t> a, dumb_ptr<spellguard_t> b) -{ - dumb_ptr<spellguard_t> retval = a; - - if (a == b) - { - /* This can happen due to reference sharing: - * e.g., - * (R0 -> (R1 | R2)) => (R3) - * yields - * (R0 -> (R1 -> R3 | R2 -> R3)) - * - * So if we now add => R4 to that, we want - * (R0 -> (R1 -> R3 -> R4 | R2 -> R3 -> R4)) - * - * but we only need to add it once, because the R3 reference is shared. - */ - return retval; - } - - /* If the premise is a disjunction, b is the continuation of _all_ branches */ - if (a->ty == SPELLGUARD::CHOICE) - spellguard_implication(a->s.s_alt, b); - if (a->next) - spellguard_implication(a->next, b); - else - a->next = b; - - return retval; -} - -dumb_ptr<effect_t> new_effect(EFFECT ty) -{ - auto effect = dumb_ptr<effect_t>::make(); - effect->ty = ty; - return effect; -} - -dumb_ptr<effect_t> set_effect_continuation(dumb_ptr<effect_t> src, dumb_ptr<effect_t> continuation) -{ - dumb_ptr<effect_t> retval = src; - /* This function is completely analogous to `spellguard_implication' above; read the control flow implications above first before pondering it. */ - - if (src == continuation) - return retval; - - /* For FOR and FOREACH, we use special stack handlers and thus don't have to set - * the continuation. It's only IF that we need to handle in this fashion. */ - if (src->ty == EFFECT::IF) - { - set_effect_continuation(src->e.e_if.true_branch, continuation); - set_effect_continuation(src->e.e_if.false_branch, continuation); - } - if (src->next) - set_effect_continuation(src->next, continuation); - else - src->next = continuation; - - return retval; -} - -dumb_ptr<effect_t> op_effect(AString name, const_array<dumb_ptr<expr_t>> argv, int line, int column) -{ - dumb_ptr<effect_t> effect; - op_t *op = magic_get_op(name); - - if (!op) - fail(line, column, "Unknown operation `%s'\n", name.c_str()); - else if (op->signature.size() != argv.size()) - { - fail(line, column, "Incorrect number of arguments to operation `%s': Expected %zu, found %zu\n", - name.c_str(), op->signature.size(), argv.size()); - op = NULL; - } - - if (op) - { - effect = new_effect(EFFECT::OP); - effect->e.e_op.line_nr = line; - effect->e.e_op.column = column; - effect->e.e_op.opp = op; - assert (argv.size() <= MAX_ARGS); - effect->e.e_op.args_nr = argv.size(); - - std::copy(argv.begin(), argv.end(), effect->e.e_op.args); - } - else /* failure */ - effect = new_effect(EFFECT::SKIP); - - return effect; -} - - -std::map<RString, proc_t> procs; - -// I think this was a memory leak (or undefined behavior) -void install_proc(dumb_ptr<proc_t> proc) -{ - procs.insert({proc->name, std::move(*proc)}); -} - -dumb_ptr<effect_t> call_proc(ZString name, dumb_ptr<std::vector<dumb_ptr<expr_t>>> argvp, int line_nr, int column) -{ - auto pi = procs.find(name); - if (pi == procs.end()) - { - fail(line_nr, column, "Unknown procedure `%s'\n", name.c_str()); - return new_effect(EFFECT::SKIP); - } - - proc_t *p = &pi->second; - - if (p->argv.size() != argvp->size()) - { - fail(line_nr, column, "Procedure %s/%zu invoked with %zu parameters\n", - name.c_str(), p->argv.size(), argvp->size()); - return new_effect(EFFECT::SKIP); - } - - dumb_ptr<effect_t> retval = new_effect(EFFECT::CALL); - retval->e.e_call.body = p->body; - retval->e.e_call.formalv = &p->argv; - retval->e.e_call.actualvp = argvp; - return retval; -} - -std::map<RString, val_t> const_defm; - -void bind_constant(RString name, val_t *val, int line_nr) -{ - if (!const_defm.insert({name, *val}).second) - { - fail(line_nr, 0, "Redefinition of constant `%s'\n", name.c_str()); - } -} - -val_t *find_constant(RString name) -{ - auto it = const_defm.find(name); - if (it != const_defm.end()) - return &it->second; - - return NULL; -} - - -static -int error_flag; - -inline -void INTERN_ASSERT(ZString name, int id) -{ - int zid = intern_id(name); - if (zid != id) - { - FPRINTF(stderr, - "[magic-conf] INTERNAL ERROR: Builtin special var %s interned to %d, not %d as it should be!\n", - name, zid, id); - error_flag = 1; - } -} - -extern FILE *magic_frontend_in; - -bool magic_init0() -{ - error_flag = 0; - - INTERN_ASSERT("min_casttime", VAR_MIN_CASTTIME); - INTERN_ASSERT("obscure_chance", VAR_OBSCURE_CHANCE); - INTERN_ASSERT("caster", VAR_CASTER); - INTERN_ASSERT("spellpower", VAR_SPELLPOWER); - INTERN_ASSERT("self_spell", VAR_SPELL); - INTERN_ASSERT("self_invocation", VAR_INVOCATION); - INTERN_ASSERT("target", VAR_TARGET); - INTERN_ASSERT("script_target", VAR_SCRIPTTARGET); - INTERN_ASSERT("location", VAR_LOCATION); - - return !error_flag; -} - -// must be called after itemdb initialisation -bool magic_init1(ZString conffile) -{ - current_magic_filename = conffile; - magic_frontend_in = fopen(conffile.c_str(), "r"); - if (!magic_frontend_in) - { - FPRINTF(stderr, "[magic-conf] Magic configuration file `%s' not found -> no magic.\n", conffile); - return false; - } - magic_frontend_parse(); - - PRINTF("[magic-conf] Magic initialised. %zu spells, %zu teleport anchors.\n", - magic_conf.spells_by_name.size(), magic_conf.anchors_by_name.size()); - - return !error_flag; -} - -extern int magic_frontend_lineno; - -void magic_frontend_error(const char *msg) -{ - FPRINTF(stderr, "[magic-conf] Parse error: %s at line %d\n", msg, magic_frontend_lineno); - failed_flag = 1; -} |