diff options
Diffstat (limited to 'src/spell-convert')
-rw-r--r-- | src/spell-convert/ast.cpp | 260 | ||||
-rw-r--r-- | src/spell-convert/ast.hpp | 432 | ||||
-rw-r--r-- | src/spell-convert/lexer.lpp | 117 | ||||
-rw-r--r-- | src/spell-convert/main.cpp | 7 | ||||
-rw-r--r-- | src/spell-convert/parser.ypp | 882 |
5 files changed, 1698 insertions, 0 deletions
diff --git a/src/spell-convert/ast.cpp b/src/spell-convert/ast.cpp new file mode 100644 index 0000000..eb66752 --- /dev/null +++ b/src/spell-convert/ast.cpp @@ -0,0 +1,260 @@ +#include "ast.hpp" + +#include "../io/cxxstdio.hpp" + +void Constant::dump() +{ + PRINTF("(CONST %s\n", name); + body->show(); + PRINTF(")\n"); +} +void Teleport::dump() +{ + PRINTF("(TELEPORT-ANCHOR %s\n", name); + ident->show(); + body->show(); + PRINTF(")\n"); +} +void Procedure::dump() +{ + PRINTF("(PROCEDURE %s\n", name); + PRINTF("("); + for (RString& a : *args) + PRINTF(" %s ", a); + PRINTF(")\n"); + for (Effect *f : *body) + { + f->print(); + } + PRINTF(")\n"); +} +void Spell::dump() +{ + PRINTF("(SPELL \n"); + PRINTF("("); + for (RString fl : *flags) + PRINTF(" %s ", fl); + PRINTF(")"); + PRINTF("%s", name); + ident->show(); + PRINTF("( %s %s )", arg->vartype, arg->varname); + for (Assignment *a : *body->lets) + { + PRINTF("(LET %s ", a->name); + a->body->show(); + PRINTF(")\n"); + } + for (SpellBod *b : *body->body) + { + b->say(); + } + PRINTF(")\n"); +} +void Assignment::dump() +{ + PRINTF("(SET %s\n", name); + body->show(); + PRINTF(")\n"); +} + +void EffectList::print() +{ + PRINTF("(BLOCK\n"); + for (Effect *ef : *body) + ef->print(); + PRINTF(")\n"); +} +void SimpleEffect::print() +{ + PRINTF("( %s )", text); +} +void ScriptEffect::print() +{ + PRINTF("(SCRIPT %s )", text); +} +void Assignment::print() +{ + PRINTF("(SET %s\n", name); + body->show(); + PRINTF(")\n"); +} +void ForeachEffect::print() +{ + PRINTF("(FOREACH %s %s ", selection, var); + expr->show(); + PRINTF("\n"); + effect->print(); + PRINTF(")"); +} +void ForEffect::print() +{ + PRINTF("(FOR %s", var); + low->show(); + high->show(); + effect->print(); + PRINTF(")"); +} +void IfEffect::print() +{ + PRINTF("(IF "); + cond->show(); + if_true->print(); + if (if_false_maybe) + if_false_maybe->print(); + PRINTF(")"); +} +void ExplicitCallEffect::print() +{ + PRINTF("(CALL %s ", userfunc); + for (Expression *x : *args) + x->show(); + PRINTF(")"); +} +void SleepEffect::print() +{ + PRINTF("(WAIT "); + time->show(); + PRINTF(")"); +} +void CallExpr::print() +{ + PRINTF("(%s ", func); + for (Expression *x : *args) + x->show(); + PRINTF(")"); +} + +void SimpleExpr::show() +{ + PRINTF(" %s ", content); +} +void BinExpr::show() +{ + PRINTF("(%s ", op); + left->show(); + right->show(); + PRINTF(")"); +} +void CallExpr::show() +{ + PRINTF("(%s ", func); + for (Expression *x : *args) + x->show(); + PRINTF(")"); +} +void AreaLoc::show() +{ + PRINTF("(@ "); + loc->map->show(); + loc->x->show(); + loc->y->show(); + PRINTF(")"); +} +void AreaRect::show() +{ + PRINTF("(@+ "); + AreaLoc{loc}.show(); + width->show(); + height->show(); + PRINTF(")"); +} +void AreaBar::show() +{ + PRINTF("(TOWARD "); + AreaLoc{loc}.show(); + dir->show(); + width->show(); + depth->show(); + PRINTF(")"); +} + +void SpellBodGuarded::say() +{ + PRINTF("(=> "); + guard->declare(); + body->say(); + PRINTF(")"); +} +void SpellBodList::say() +{ + PRINTF("(|\n"); + for (SpellBod *b : *body) + b->say(); + PRINTF(")"); +} +void SpellBodEffect::say() +{ + PRINTF("(EFFECT\n"); + for (Effect *f : *body) + f->print(); + if (maybe_trigger) + { + PRINTF("(ATTRIGGER\n"); + for (Effect *f : *maybe_trigger) + f->print(); + PRINTF(")"); + } + if (maybe_end) + { + PRINTF("(ATEND\n"); + for (Effect *f : *maybe_end) + f->print(); + PRINTF(")"); + } + PRINTF(")"); +} + +void SpellGuardOr::declare() +{ + PRINTF("(OR\n"); + for (SpellGuard *sg : *any) + sg->declare(); + PRINTF(")"); +} +void SpellGuardList::declare() +{ + PRINTF("(GUARD\n"); + for (SpellGuard *sg : *all) + sg->declare(); + PRINTF(")"); +} +void SpellGuardRequire::declare() +{ + PRINTF("(REQUIRE "); + expr->show(); + PRINTF(")"); +} +static +void do_item(Item *itm) +{ + if (itm->count) + PRINTF("( %s %s )", itm->count, itm->item); + else + PRINTF(" %s ", itm->item); +} +void SpellGuardCatalysts::declare() +{ + PRINTF("(CATALYSTS "); + for (Item *itm : *items) + do_item(itm); + PRINTF(")"); +} +void SpellGuardComponents::declare() +{ + PRINTF("(COMPONENTS "); + for (Item *itm : *items) + do_item(itm); + PRINTF(")"); +} +void SpellGuardMana::declare() +{ + PRINTF("(MANA "); + sp->show(); + PRINTF(")"); +} +void SpellGuardCasttime::declare() +{ + PRINTF("(CASTTIME "); + time->show(); + PRINTF(")"); +} diff --git a/src/spell-convert/ast.hpp b/src/spell-convert/ast.hpp new file mode 100644 index 0000000..e5319fc --- /dev/null +++ b/src/spell-convert/ast.hpp @@ -0,0 +1,432 @@ +#ifndef AST_HPP +#define AST_HPP + +# include <deque> +# include <vector> + +# include "../strings/rstring.hpp" + +// We just leak +# pragma GCC diagnostic ignored "-Wnon-virtual-dtor" + +struct TopLevel; +struct Constant; +struct Teleport; +struct Procedure; +struct Spell; +struct SpellArg; +struct Effect; +struct EffectList; +struct SimpleEffect; +struct ScriptEffect; +struct Assignment; +struct ForeachEffect; +struct ForEffect; +struct IfEffect; +struct ExplicitCallEffect; +struct SleepEffect; +struct SpellDef; +struct SpellBod; +struct SpellBodGuarded; +struct SpellBodList; +struct SpellBodEffect; +struct SpellGuard; +struct SpellGuardOr; +struct SpellGuardList; +struct SpellGuardRequire; +struct SpellGuardCatalysts; +struct SpellGuardComponents; +struct SpellGuardMana; +struct SpellGuardCasttime; +struct Item; +struct Expression; +struct SimpleExpr; +struct BinExpr; +struct CallExpr; +struct Location; +struct AreaLoc; +struct AreaRect; +struct AreaBar; + + +struct TopLevel +{ + virtual void dump() = 0; +}; + +struct Constant : TopLevel +{ + RString name; + Expression *body; + + Constant(RString n, Expression *b) + : name(n), body(b) + {} + + virtual void dump() override; +}; + +struct Teleport : TopLevel +{ + RString name; + Expression *ident; + Expression *body; + + Teleport(RString n, Expression *i, Expression *b) + : name(n), ident(i), body(b) + {} + + virtual void dump() override; +}; + +struct Procedure : TopLevel +{ + RString name; + std::vector<RString> *args; + std::deque<Effect *> *body; + + Procedure(RString n, std::vector<RString> *a, std::deque<Effect *> *b) + : name(n), args(a), body(b) + {} + + virtual void dump() override; +}; + +struct Spell : TopLevel +{ + std::vector<RString> *flags; + RString name; + SpellArg *arg; + Expression *ident; + SpellDef *body; + + Spell(std::vector<RString> *f, RString n, SpellArg *a, Expression *i, SpellDef *b) + : flags(f), name(n), arg(a), ident(i), body(b) + {} + + virtual void dump() override; +}; + +struct SpellArg +{ + RString varname; + RString vartype; +}; + +struct Effect +{ + virtual void print() = 0; +}; + +struct EffectList : Effect +{ + std::deque<Effect *> *body; + + EffectList(std::deque<Effect *> *b) + : body(b) + {} + + virtual void print() override; +}; +struct SimpleEffect : Effect +{ + RString text; + + SimpleEffect(RString t) : text(t) {} + + virtual void print() override; +}; +struct ScriptEffect : Effect +{ + RString text; + + ScriptEffect(RString t) : text(t) {} + + virtual void print() override; +}; + +struct Assignment : TopLevel, Effect +{ + RString name; + Expression *body; + + Assignment(RString n, Expression *b) + : name(n), body(b) + {} + + // toplevel + virtual void dump() override; + // effect + virtual void print() override; +}; + +struct ForeachEffect : Effect +{ + RString selection; + RString var; + Expression *expr; + Effect *effect; + + ForeachEffect(RString s, RString v, Expression *x, Effect *f) + : selection(s), var(v), expr(x), effect(f) + {} + + virtual void print() override; +}; + +struct ForEffect : Effect +{ + RString var; + Expression *low; + Expression *high; + Effect *effect; + + ForEffect(RString v, Expression *l, Expression *h, Effect *f) + : var(v), low(l), high(h), effect(f) + {} + + virtual void print() override; +}; + +struct IfEffect : Effect +{ + Expression *cond; + Effect *if_true; + Effect *if_false_maybe; + + IfEffect(Expression *c, Effect *t, Effect *f=nullptr) + : cond(c), if_true(t), if_false_maybe(f) + {} + + virtual void print() override; +}; + +struct ExplicitCallEffect : Effect +{ + RString userfunc; + std::vector<Expression *> *args; + + ExplicitCallEffect(RString f, std::vector<Expression *> *a) + : userfunc(f), args(a) + {} + + virtual void print() override; +}; + +struct SleepEffect : Effect +{ + Expression *time; + + SleepEffect(Expression *t) + : time(t) + {} + + virtual void print() override; +}; + +struct SpellDef +{ + std::vector<Assignment *> *lets; + std::vector<SpellBod *> *body; +}; + +struct SpellBod +{ + virtual void say() = 0; +}; + +struct SpellBodGuarded : SpellBod +{ + SpellGuard *guard; + SpellBod *body; + + SpellBodGuarded(SpellGuard *g, SpellBod *b) + : guard(g), body(b) + {} + + virtual void say() override; +}; + +struct SpellBodList : SpellBod +{ + std::vector<SpellBod *> *body; + + SpellBodList(std::vector<SpellBod *> *b) + : body(b) + {} + + virtual void say() override; +}; + +struct SpellBodEffect : SpellBod +{ + std::deque<Effect *> *body; + std::deque<Effect *> *maybe_trigger; + std::deque<Effect *> *maybe_end; + + SpellBodEffect(std::deque<Effect *> *b, std::deque<Effect *> *t, std::deque<Effect *> *e) + : body(b), maybe_trigger(t), maybe_end(e) + {} + + virtual void say() override; +}; + +struct SpellGuard +{ + virtual void declare() = 0; +}; + +struct SpellGuardOr : SpellGuard +{ + std::vector<SpellGuard *> *any; + + SpellGuardOr(std::vector<SpellGuard *> *a) : any(a) {} + SpellGuardOr(SpellGuard *left, SpellGuard *right) + : any(new std::vector<SpellGuard *>({left, right})) + {} + + virtual void declare() override; +}; +struct SpellGuardList : SpellGuard +{ + std::vector<SpellGuard *> *all; + + SpellGuardList(std::vector<SpellGuard *> *a) : all(a) {} + + virtual void declare() override; +}; +struct SpellGuardRequire : SpellGuard +{ + Expression *expr; + + SpellGuardRequire(Expression *x) : expr(x) {} + + virtual void declare() override; +}; +struct SpellGuardCatalysts : SpellGuard +{ + std::vector<Item *> *items; + + SpellGuardCatalysts(std::vector<Item *> *i) : items(i) {} + + virtual void declare() override; +}; +struct SpellGuardComponents : SpellGuard +{ + std::vector<Item *> *items; + + SpellGuardComponents(std::vector<Item *> *i) : items(i) {} + + virtual void declare() override; +}; +struct SpellGuardMana : SpellGuard +{ + Expression *sp; + + SpellGuardMana(Expression *x) : sp(x) {} + + virtual void declare() override; +}; +struct SpellGuardCasttime : SpellGuard +{ + Expression *time; + + SpellGuardCasttime(Expression *x) : time(x) {} + + virtual void declare() override; +}; + +struct Item +{ + RString count; + RString item; +}; + +struct Expression +{ + virtual void show() = 0; +}; + +struct SimpleExpr : Expression +{ + RString content; + + SimpleExpr(RString c) : content(c) {} + + virtual void show() override; +}; + +struct BinExpr : Expression +{ + Expression *left; + RString op; + Expression *right; + + BinExpr(Expression *l, RString o, Expression *r) + : left(l), op(o), right(r) + {} + + virtual void show() override; +}; + +struct CallExpr : Expression, Effect +{ + RString func; + std::vector<Expression *> *args; + + CallExpr(RString f, std::vector<Expression *> *a) + : func(f), args(a) + {} + + // expression + virtual void show() override; + // effect + virtual void print() override; +}; + +struct Location +{ + Expression *map; + Expression *x; + Expression *y; +}; + +struct AreaLoc : Expression +{ + Location *loc; + + AreaLoc(Location *l) + : loc(l) + {} + + virtual void show() override; +}; + +struct AreaRect : Expression +{ + Location *loc; + Expression *width; + Expression *height; + + AreaRect(Location *l, Expression *w, Expression *h) + : loc(l), width(w), height(h) + {} + + virtual void show() override; +}; + +struct AreaBar : Expression +{ + Location *loc; + Expression *dir; + Expression *width; + Expression *depth; + + AreaBar(Location *l, Expression *a, Expression *w, Expression *d) + : loc(l), dir(a), width(w), depth(d) + {} + + virtual void show() override; +}; + +#endif // AST_HPP diff --git a/src/spell-convert/lexer.lpp b/src/spell-convert/lexer.lpp new file mode 100644 index 0000000..92acf48 --- /dev/null +++ b/src/spell-convert/lexer.lpp @@ -0,0 +1,117 @@ +%{ +/* vim: set ft=lex: */ +//#include "lexer.hpp" + +#include "../strings/rstring.hpp" +#include "../strings/zstring.hpp" + +#include "../io/cxxstdio.hpp" + +#include "../sexpr/lexer.hpp" + +#include "parser.hpp" + +#define yylval spell_converterlval + +RString *str(const char *s) +{ + return new RString(ZString(strings::really_construct_from_a_pointer, s, nullptr)); +} +%} + +%option noyywrap +%option prefix="spell_converter" +%option nounput +%option noinput + +%% + +"S" { yylval.s = str(yytext); return DIR; } +"SW" { yylval.s = str(yytext); return DIR; } +"W" { yylval.s = str(yytext); return DIR; } +"NW" { yylval.s = str(yytext); return DIR; } +"N" { yylval.s = str(yytext); return DIR; } +"NE" { yylval.s = str(yytext); return DIR; } +"E" { yylval.s = str(yytext); return DIR; } +"SE" { yylval.s = str(yytext); return DIR; } +"=" { return '='; } +"==" { return EQ; } +"<>" { return NEQ; } +"!=" { return NEQ; } +">" { return '>'; } +"<" { return '<'; } +">=" { return GTE; } +"<=" { return LTE; } +"(" { return '('; } +")" { return ')'; } +"+" { return '+'; } +"-" { return '-'; } +"*" { return '*'; } +"/" { return '/'; } +"%" { return '%'; } +"&&" { return ANDAND; } +"||" { return OROR; } +";" { return ';'; } +":" { return ':'; } +"," { return ','; } +"@" { return '@'; } +"|" { return '|'; } +"[" { return '['; } +"]" { return ']'; } +"&" { return '&'; } +"^" { return '^'; } +"." { return '.'; } +"<<" { return SHL; } +">>" { return SHR; } +"PROCEDURE" { return PROCEDURE; } +"CALL" { return CALL; } +"OR" { return OR; } +"TO" { return TO; } +"TOWARDS" { return TOWARDS; } +"TELEPORT-ANCHOR" { return TELEPORT_ANCHOR; } +"SILENT" { return SILENT; } +"LOCAL" { return LOCAL; } +"NONMAGIC" { return NONMAGIC; } +"SPELL" { return SPELL; } +"LET" { return LET; } +"IN" { return IN; } +"END" { return END; } +"=>" { return DARROW; } +"STRING" { return STRING_TY; } +"REQUIRE" { return REQUIRE; } +"CATALYSTS" { return CATALYSTS; } +"COMPONENTS" { return COMPONENTS; } +"MANA" { return MANA; } +"CASTTIME" { return CASTTIME; } +"SKIP" { return SKIP; } +"ABORT" { return ABORT; } +"BREAK" { return BREAK; } +"EFFECT" { return EFFECT_; } +"ATEND" { return ATEND; } +"ATTRIGGER" { return ATTRIGGER; } +"CONST" { return CONST; } +"PC" { return PC_F; } +"NPC" { return NPC_F; } +"MOB" { return MOB_F; } +"ENTITY" { return ENTITY_F; } +"TARGET" { return TARGET_F; } +"IF" { return IF; } +"THEN" { return THEN; } +"ELSE" { return ELSE; } +"FOREACH" { return FOREACH; } +"FOR" { return FOR; } +"DO" { return DO; } +"WAIT" { return SLEEP; } + +\{([^\}]|\\.)*\} { yylval.s = str(yytext); return SCRIPT_DATA; } +\"([^\"]|\\.)*\" { yylval.s = str(yytext); return STRING; } +"-"?[0-9]+ { yylval.s = str(yytext); return INT; } +"0x"[0-9a-fA-F]+ { yylval.s = str(yytext); return INT; } +[a-zA-Z][-_a-zA-Z0-9]* { yylval.s = str(yytext); return ID; } +"#".*$ { PRINTF("%s\n", sexpr::escape(*str(yytext + 1))); } +"//".*$ { PRINTF("%s\n", sexpr::escape(*str(yytext + 2))); } +[ \n\t\r] /* ignore whitespace */ +. { abort(); } + +%% +// nothing to see here, move along diff --git a/src/spell-convert/main.cpp b/src/spell-convert/main.cpp new file mode 100644 index 0000000..a6f0d76 --- /dev/null +++ b/src/spell-convert/main.cpp @@ -0,0 +1,7 @@ +#include "src/spell-convert/lexer.hpp" +#include "src/spell-convert/parser.hpp" + +int main() +{ + spell_converterparse(); +} diff --git a/src/spell-convert/parser.ypp b/src/spell-convert/parser.ypp new file mode 100644 index 0000000..822727d --- /dev/null +++ b/src/spell-convert/parser.ypp @@ -0,0 +1,882 @@ +%code requires +{ +/* vim: set ft=yacc: */ +#include "../strings/rstring.hpp" + +#include "ast.hpp" + +#undef YYERROR_VERBOSE +#define YYERROR_VERBOSE 1 +} // %code requires + +%code +{ +//#include "parser.hpp" +#include "lexer.hpp" + +#include "../io/cxxstdio.hpp" + +#include "../sexpr/lexer.hpp" + +void yyerror(const char *msg) { FPRINTF(stderr, "Fatal: %s\n", msg); abort(); } +} // %code + +%name-prefix "spell_converter" + +%union +{ + RString *s; + std::vector<RString> *vs; + Effect *e; + std::deque<Effect *> *ve; + SpellDef *spelldef; + SpellArg *spellarg; + TopLevel *top; + Expression *expr; + std::vector<Expression *> *vx; + Location *loc; + Item *it; + std::vector<Item *> *vit; + Assignment *a; + std::vector<Assignment *> *va; + SpellBod *b; + std::vector<SpellBod *> *vb; + SpellGuard *g; + std::vector<SpellGuard *> *vg; +} // %union + +%expect 7 + +%token <s> INT +%token <s> STRING +%token <s> ID +%token <s> 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 <s> value +%type <loc> location +%type <expr> area +%type <vx> arg_list +%type <vx> arg_list_ne +%type <va> defs +%type <spelldef> spelldef +%type <spellarg> argopt +%type <a> def +%type <vb> spellbody_list +%type <b> spellbody +%type <g> spellguard +%type <vg> spellguard_list +%type <g> prereq +%type <it> item +%type <vit> items +%type <vit> item_list +%type <s> item_name +%type <s> selection; +%type <e> effect +%type <ve> effect_list +%type <ve> maybe_trigger +%type <ve> maybe_end +%type <vs> spell_flags; + +%type <expr> expr +%type <s> arg_ty +%type <vs> proc_formals_list +%type <vs> proc_formals_list_ne + +%type <top> spellconf_option + +%left OROR +%left ANDAND +%left '<' '>' GTE LTE NEQ EQ +%left '+' '-' +%left '*' '/' '%' +%left SHL SHR '&' '^' '|' +%right '=' +%left OR +%left DARROW +%left '.' + +%% + +spellconf + +: /* empty */ + +| spellconf semicolons spellconf_option +{ + $3->dump(); +} + +; + + +semicolons + +: /* empty */ + +| semicolons ';' + +; + + +proc_formals_list + +: /* empty */ +{ + $$ = new std::vector<RString>(); +} + +| proc_formals_list_ne +{ + $$ = $1; +} + +; + + +proc_formals_list_ne + +: ID +{ + $$ = new std::vector<RString>(); + $$->push_back(*$1); +} + +| proc_formals_list_ne ',' ID +{ + $$ = $1; + $$->push_back(*$3); +} + +; + + +spellconf_option + +: ID '=' expr +{ + $$ = new Assignment{*$1, $3}; +} + +| CONST ID '=' expr +{ + $$ = new Constant{*$2, $4}; +} + +| TELEPORT_ANCHOR ID ':' expr '=' expr +{ + $$ = new Teleport{*$2, $4, $6}; +} + +| PROCEDURE ID '(' proc_formals_list ')' '=' effect_list +{ + $$ = new Procedure{*$2, $4, $7}; +} + +| spell_flags SPELL ID argopt ':' expr '=' spelldef +{ + $$ = new Spell{$1, *$3, $4, $6, $8}; +} + +; + + +spell_flags + +: /* empty */ +{ + $$ = new std::vector<RString>(); +} + +| spell_flags LOCAL +{ + $$ = $1; + $$->push_back("LOCAL"); +} + +| spell_flags NONMAGIC +{ + $$ = $1; + $$->push_back("NONMAGIC"); +} + +| spell_flags SILENT +{ + $$ = $1; + $$->push_back("SILENT"); +} + +; + + +argopt + +: /* empty */ +{ + $$ = new SpellArg{}; +} + +| '(' ID ':' arg_ty ')' +{ + $$ = new SpellArg{*$2, *$4}; +} + +; + + +arg_ty + +: PC_F +{ + $$ = new RString("PC"); +} + +| STRING_TY +{ + $$ = new RString("STRING"); +} + +; + + +value + +: DIR +{ + $$ = $1; +} + +| INT +{ + $$ = $1; +} + +| STRING +{ + $$ = $1; +} + +; + + +expr + +: value +{ + $$ = new SimpleExpr{*$1}; +} + +| ID +{ + $$ = new SimpleExpr{*$1}; +} + +| area +{ + $$ = $1; +} + +| expr '+' expr +{ + $$ = new BinExpr{$1, "+", $3}; +} + +| expr '-' expr +{ + $$ = new BinExpr{$1, "-", $3}; +} + +| expr '*' expr +{ + $$ = new BinExpr{$1, "*", $3}; +} + +| expr '%' expr +{ + $$ = new BinExpr{$1, "%", $3}; +} + +| expr '/' expr +{ + $$ = new BinExpr{$1, "/", $3}; +} + +| expr '<' expr +{ + $$ = new BinExpr{$1, "<", $3}; +} + +| expr '>' expr +{ + $$ = new BinExpr{$1, ">", $3}; +} + +| expr '&' expr +{ + $$ = new BinExpr{$1, "&", $3}; +} + +| expr '^' expr +{ + $$ = new BinExpr{$1, "^", $3}; +} + +| expr '|' expr +{ + $$ = new BinExpr{$1, "|", $3}; +} + +| expr SHL expr +{ + $$ = new BinExpr{$1, "<<", $3}; +} + +| expr SHR expr +{ + $$ = new BinExpr{$1, ">>", $3}; +} + +| expr LTE expr +{ + $$ = new BinExpr{$1, "<=", $3}; +} + +| expr GTE expr +{ + $$ = new BinExpr{$1, ">=", $3}; +} + +| expr ANDAND expr +{ + $$ = new BinExpr{$1, "&&", $3}; +} + +| expr OROR expr +{ + $$ = new BinExpr{$1, "||", $3}; +} + +| expr EQ expr +{ + $$ = new BinExpr{$1, "==", $3}; +} + +| expr '=' expr +{ + // convert to == + $$ = new BinExpr{$1, "==", $3}; +} + +| expr NEQ expr +{ + $$ = new BinExpr{$1, "!=", $3}; +} + +| ID '(' arg_list ')' +{ + $$ = new CallExpr{*$1, $3}; +} + +| '(' expr ')' +{ + $$ = $2; +} + +| expr '.' ID +{ + $$ = new BinExpr{$1, ".", new SimpleExpr(*$3)}; +} + +; + + +arg_list + +: /* empty */ +{ + $$ = new std::vector<Expression *>(); +} + +| arg_list_ne +{ + $$ = $1; +} + +; + + +arg_list_ne + +: expr +{ + $$ = new std::vector<Expression *>(); + $$->push_back($1); +} + +| arg_list_ne ',' expr +{ + $$ = $1; + $$->push_back($3); +} + +; + + +location + +: '@' '(' expr ',' expr ',' expr ')' +{ + $$ = new Location{$3, $5, $7}; +} + +; + + +area + +: location +{ + $$ = new AreaLoc{$1}; +} + +| location '@' '+' '(' expr ',' expr ')' +{ + $$ = new AreaRect{$1, $5, $7}; +} + +| location TOWARDS expr ':' '(' expr ',' expr ')' +{ + $$ = new AreaBar{$1, $3, $6, $8}; +} + +; + + +spelldef + +: spellbody_list +{ + $$ = new SpellDef{new std::vector<Assignment *>{}, $1}; +} + +| LET defs IN spellbody_list +{ + $$ = new SpellDef{$2, $4}; +} + +; + + +defs + +: semicolons +{ + $$ = new std::vector<Assignment *>(); +} + +| defs def semicolons +{ + $$ = $1; + $$->push_back($2); +} + +; + + +def + +: ID '=' expr +{ + $$ = new Assignment{*$1, $3}; +} + +; + + +spellbody_list + +: spellbody +{ + $$ = new std::vector<SpellBod *>(); + $$->push_back($1); +} + +| spellbody_list '|' spellbody +{ + $$ = $1; + $$->push_back($3); +} + +; + + +spellbody + +: spellguard DARROW spellbody +{ + $$ = new SpellBodGuarded{$1, $3}; +} + +| '(' spellbody_list ')' +{ + $$ = new SpellBodList{$2}; +} + +| EFFECT_ effect_list maybe_trigger maybe_end +{ + $$ = new SpellBodEffect{$2, $3, $4}; +} + +; + + +maybe_trigger + +: /* empty */ +{ + $$ = nullptr; +} + +| ATTRIGGER effect_list +{ + $$ = $2; +} + +; + + +maybe_end + +: /* empty */ +{ + $$ = nullptr; +} + +| ATEND effect_list +{ + $$ = $2; +} + +; + + +spellguard + +: prereq +{ + $$ = $1; +} + +| spellguard OR spellguard +{ + $$ = new SpellGuardOr($1, $3); +} + +| '(' spellguard_list ')' +{ + $$ = new SpellGuardList{$2}; +} + +; + + +spellguard_list + +: spellguard +{ + $$ = new std::vector<SpellGuard *>(); + $$->push_back($1); +} + +| spellguard_list ',' spellguard +{ + $$ = $1; + $$->push_back($3); +} + +; + + +prereq + +: REQUIRE expr +{ + $$ = new SpellGuardRequire{$2}; +} + +| CATALYSTS items +{ + $$ = new SpellGuardCatalysts{$2}; +} + +| COMPONENTS items +{ + $$ = new SpellGuardComponents{$2}; +} + +| MANA expr +{ + $$ = new SpellGuardMana{$2}; +} + +| CASTTIME expr +{ + $$ = new SpellGuardCasttime{$2}; +} + +; + + +items + +: '[' item_list ']' +{ + $$ = $2; +} + +; + + +item_list + +: item +{ + $$ = new std::vector<Item *>(); + $$->push_back($1); +} + +| item_list ',' item +{ + $$ = $1; + $$->push_back($3); +} + +; + + +item + +: INT '*' item_name +{ + $$ = new Item{*$1, *$3}; +} + +| item_name +{ + $$ = new Item{RString(), *$1}; +} + +; + + +item_name + +: STRING +{ + $$ = $1; +} + +| INT +{ + $$ = $1; +} + +; + + +selection + +: PC_F +{ + $$ = new RString{"PC"}; +} + +| MOB_F +{ + $$ = new RString{"MOB"}; +} + +| ENTITY_F +{ + $$ = new RString{"ENTITY"}; +} + +| SPELL +{ + $$ = new RString{"SPELL"}; +} + +| TARGET_F +{ + $$ = new RString{"TARGET"}; +} + +| NPC_F +{ + $$ = new RString{"NPC"}; +} + +; + + +effect + +: '(' effect_list ')' +{ + $$ = new EffectList{$2}; +} + +| SKIP ';' +{ + $$ = new SimpleEffect{"SKIP"}; +} + +| ABORT ';' +{ + $$ = new SimpleEffect{"ABORT"}; +} + +| END ';' +{ + $$ = new SimpleEffect{"END"}; +} + +| BREAK ';' +{ + $$ = new SimpleEffect{"BREAK"}; +} + +| ID '=' expr ';' +{ + $$ = new Assignment(*$1, $3); +} + +| FOREACH selection ID IN expr DO effect +{ + $$ = new ForeachEffect{*$2, *$3, $5, $7}; +} + +| FOR ID '=' expr TO expr DO effect +{ + $$ = new ForEffect{*$2, $4, $6, $8}; +} + +| IF expr THEN effect ELSE effect +{ + $$ = new IfEffect{$2, $4, $6}; +} + +| IF expr THEN effect +{ + $$ = new IfEffect{$2, $4}; +} + +| SLEEP expr ';' +{ + $$ = new SleepEffect{$2}; +} + +| ID '(' arg_list ')' ';' +{ + $$ = new CallExpr{*$1, $3}; +} + +| SCRIPT_DATA +{ + AString tmp = sexpr::escape(*$1); + $$ = new ScriptEffect{RString(tmp)}; +} + +| CALL ID '(' arg_list ')' ';' +{ + $$ = new ExplicitCallEffect{*$2, $4}; +} + +; + + +effect_list + +: /* empty */ +{ + $$ = new std::deque<Effect *>(); +} + +| effect semicolons effect_list +{ + // because of grammar problems, doing this right generates reduce/reduce conflicts + $$ = $3; + $$->push_front($1); +} + +; + + +%% +// Nothing to see here, move along |