summaryrefslogtreecommitdiff
path: root/src/map/magic-interpreter-parser.ypp
diff options
context:
space:
mode:
Diffstat (limited to 'src/map/magic-interpreter-parser.ypp')
-rw-r--r--src/map/magic-interpreter-parser.ypp1441
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;
-}