From 6912dfda093b3b67263065461a5f84e3f006f4f0 Mon Sep 17 00:00:00 2001 From: twanvl Date: Tue, 3 Jun 2008 14:08:11 +0000 Subject: [PATCH] Simplified script VM: - removed I_RET instruction, return is now implicit at end of script - I_POP is not a binary instruction. git-svn-id: svn://svn.code.sf.net/p/magicseteditor/code/trunk@963 0fc631ac-6414-0410-93d0-97cfa31319b6 --- src/data/field/choice.cpp | 2 -- src/data/game.cpp | 1 - src/data/statistics.cpp | 2 -- src/script/context.cpp | 43 ++++++++++-------------- src/script/dependency.cpp | 31 +++++++++-------- src/script/image.cpp | 1 - src/script/parser.cpp | 71 +++++++++++++++++++++------------------ src/script/script.cpp | 7 ++-- src/script/script.hpp | 48 +++++++++++++------------- 9 files changed, 99 insertions(+), 107 deletions(-) diff --git a/src/data/field/choice.cpp b/src/data/field/choice.cpp index b3e6dc3c..29ca7100 100644 --- a/src/data/field/choice.cpp +++ b/src/data/field/choice.cpp @@ -198,7 +198,6 @@ void ChoiceStyle::initImage() { // CALL 0 // PUSH_CONST nil // OR_ELSE - // RET intrusive_ptr lookup(new ScriptCustomCollection()); FOR_EACH(ci, choice_images) { lookup->key_value[ci.first] = ci.second.getScriptP(); @@ -210,7 +209,6 @@ void ChoiceStyle::initImage() { script.addInstruction(I_CALL, 0); script.addInstruction(I_PUSH_CONST, script_nil); script.addInstruction(I_BINARY, I_OR_ELSE); - script.addInstruction(I_RET); } int ChoiceStyle::update(Context& ctx) { diff --git a/src/data/game.cpp b/src/data/game.cpp index b74d0883..0cf1d805 100644 --- a/src/data/game.cpp +++ b/src/data/game.cpp @@ -99,7 +99,6 @@ void Game::initCardListColorScript() { s.addInstruction(I_BINARY, I_MEMBER); s.addInstruction(I_PUSH_CONST, to_script(Color(0,0,0))); s.addInstruction(I_BINARY, I_OR_ELSE); - s.addInstruction(I_RET); return; } } diff --git a/src/data/statistics.cpp b/src/data/statistics.cpp index 58e55aa9..a3fc3b37 100644 --- a/src/data/statistics.cpp +++ b/src/data/statistics.cpp @@ -56,13 +56,11 @@ StatsDimension::StatsDimension(const Field& field) s.addInstruction(I_MEMBER_C, field.name); s.addInstruction(I_CALL, 1); s.addInstruction(I_NOP, SCRIPT_VAR_input); - s.addInstruction(I_RET); } else { // initialize script, card.{field_name} Script& s = script.getScript(); s.addInstruction(I_GET_VAR, SCRIPT_VAR_card); s.addInstruction(I_MEMBER_C, field.name); - s.addInstruction(I_RET); } } diff --git a/src/script/context.cpp b/src/script/context.cpp index c8499dce..3e1431f7 100644 --- a/src/script/context.cpp +++ b/src/script/context.cpp @@ -39,12 +39,10 @@ ScriptValueP Context::eval(const Script& script, bool useScope) { try { // Instruction pointer const Instruction* instr = &script.instructions[0]; + const Instruction* end = &*script.instructions.end(); // Loop until we are done - while (true) { - assert(instr < &*script.instructions.end()); - // debug -// cout << script.dumpInstr(instr - &script.instructions[0], *instr) << endl; + while (instr < end) { // Evaluate the current instruction Instruction i = *instr++; switch (i.instr) { @@ -54,11 +52,6 @@ ScriptValueP Context::eval(const Script& script, bool useScope) { stack.push_back(script.constants[i.data]); break; } - // Pop top value - case I_POP: { - stack.pop_back(); - break; - } // Jump case I_JUMP: { instr = &script.instructions[i.data]; @@ -144,21 +137,10 @@ ScriptValueP Context::eval(const Script& script, bool useScope) { closeScope(scope); break; } - // Function return - case I_RET: { - // restore shadowed variables - if (useScope) closeScope(scope); - // return top of stack - ScriptValueP result = stack.back(); - stack.pop_back(); - assert(stack.size() == stack_size); // we end up with the same stack - return result; - } // Simple instruction: unary case I_UNARY: { instrUnary(i.instr1, stack.back()); -// cout << "\t\t-> " << (String)*stack.back() << endl; break; } // Simple instruction: binary @@ -166,7 +148,6 @@ ScriptValueP Context::eval(const Script& script, bool useScope) { ScriptValueP b = stack.back(); stack.pop_back(); ScriptValueP& a = stack.back(); instrBinary(i.instr2, a, b); -// cout << "\t\t-> " << (String)*stack.back() << endl; break; } // Simple instruction: ternary @@ -175,7 +156,6 @@ ScriptValueP Context::eval(const Script& script, bool useScope) { ScriptValueP b = stack.back(); stack.pop_back(); ScriptValueP& a = stack.back(); instrTernary(i.instr3, a, b, c); -// cout << "\t\t-> " << (String)*stack.back() << endl; break; } // Simple instruction: quaternary @@ -185,12 +165,20 @@ ScriptValueP Context::eval(const Script& script, bool useScope) { ScriptValueP b = stack.back(); stack.pop_back(); ScriptValueP& a = stack.back(); instrQuaternary(i.instr4, a, b, c, d); -// cout << "\t\t-> " << (String)*stack.back() << endl; break; } } } + // Function return + // restore shadowed variables + if (useScope) closeScope(scope); + // return top of stack + ScriptValueP result = stack.back(); + stack.pop_back(); + assert(stack.size() == stack_size); // we end up with the same stack + return result; + } catch (...) { // cleanup after an exception if (useScope) closeScope(scope); // restore scope @@ -322,14 +310,19 @@ class ScriptCompose : public ScriptValue { }; void instrBinary (BinaryInstructionType i, ScriptValueP& a, const ScriptValueP& b) { - ScriptType at = a->type(), bt = b->type(); switch (i) { + case I_POP: + // a = a; + break; case I_MEMBER: a = a->getMember(*b); break; case I_ITERATOR_R: a = rangeIterator(*a, *b); break; + default: + ScriptType at = a->type(), bt = b->type(); + switch(i) { case I_ADD: // add is quite overloaded if (at == SCRIPT_NIL) { a = b; @@ -370,7 +363,7 @@ void instrBinary (BinaryInstructionType i, ScriptValueP& a, const ScriptValueP& case I_OR_ELSE: if (at == SCRIPT_ERROR) a = b; break; - } + }} } // ----------------------------------------------------------------------------- : Simple instructions : ternary diff --git a/src/script/dependency.cpp b/src/script/dependency.cpp index 7427df84..75007231 100644 --- a/src/script/dependency.cpp +++ b/src/script/dependency.cpp @@ -140,7 +140,6 @@ ScriptValueP Context::dependencies(const Dependency& dep, const Script& script) // Loop until we are done while (true) { - assert(instr < &*script.instructions.end()); // Is there a jump going here? // If so, unify with current execution path while (!jumps.empty() && jumps.top()->target == instr) { @@ -158,6 +157,8 @@ ScriptValueP Context::dependencies(const Dependency& dep, const Script& script) delete j; } + if (instr >= &*script.instructions.end()) break; // end of script + // Analyze the current instruction Instruction i = *instr++; switch (i.instr) { @@ -167,11 +168,6 @@ ScriptValueP Context::dependencies(const Dependency& dep, const Script& script) stack.push_back(script.constants[i.data]); break; } - // Pop top value (as normal) - case I_POP: { - stack.pop_back(); - break; - } // Jump case I_JUMP: { if (&script.instructions[i.data] >= instr) { @@ -253,16 +249,6 @@ ScriptValueP Context::dependencies(const Dependency& dep, const Script& script) closeScope(scope); break; } - // Function return (as normal) - case I_RET: { - closeScope(scope); - // return top of stack - ScriptValueP result = stack.back(); - stack.pop_back(); - assert(stack.size() == stack_size); // we end up with the same stack - assert(jumps.empty()); // no open jump records - return result; - } // Get a variable (almost as normal) case I_GET_VAR: { @@ -293,6 +279,10 @@ ScriptValueP Context::dependencies(const Dependency& dep, const Script& script) } // Simple instruction: binary case I_BINARY: { + if (i.instr2 == I_POP) { + stack.pop_back(); + continue; + } ScriptValueP b = stack.back(); stack.pop_back(); ScriptValueP& a = stack.back(); switch (i.instr2) { @@ -330,6 +320,15 @@ ScriptValueP Context::dependencies(const Dependency& dep, const Script& script) } } } + + // Function return (as normal) + closeScope(scope); + ScriptValueP result = stack.back(); + stack.pop_back(); + assert(stack.size() == stack_size); // we end up with the same stack + assert(jumps.empty()); // no open jump records + return result; + } catch (...) { // cleanup after an exception // the only place where exceptions should be possible is in someValue->getMember diff --git a/src/script/image.cpp b/src/script/image.cpp index 9e331fb1..e10d2afe 100644 --- a/src/script/image.cpp +++ b/src/script/image.cpp @@ -82,7 +82,6 @@ ScriptP ScriptableImage::getScriptP() { // return value or a blank image ScriptP s(new Script); s->addInstruction(I_PUSH_CONST, value ? static_pointer_cast(value) : script_nil); - s->addInstruction(I_RET); return s; } diff --git a/src/script/parser.cpp b/src/script/parser.cpp index 4fb98a3a..71591152 100644 --- a/src/script/parser.cpp +++ b/src/script/parser.cpp @@ -346,19 +346,22 @@ void parseExpr(TokenIterator& input, Script& script, Precedence min_prec); /** @param input Read tokens from the input * @param script Add resulting instructions to the script * @param min_prec Minimum precedence level for operators - * @param close_with Add this instruction at the end + * @param close_with Add this instruction at the end, or I_NOP for no instruction * @param close_with_data Data for the instruction at the end * NOTE: The net stack effect of an expression should be +1 */ void parseOper(TokenIterator& input, Script& script, Precedence min_prec, InstructionType close_with = I_NOP, int close_with_data = 0); +/// Parse call arguments, "(...)" +void parseCallArguments(TokenIterator& input, Script& script, vector& arguments); + ScriptP parse(const String& s, Packaged* package, bool string_mode, vector& errors_out) { errors_out.clear(); // parse TokenIterator input(s, package, string_mode, errors_out); ScriptP script(new Script); - parseOper(input, *script, PREC_ALL, I_RET); + parseOper(input, *script, PREC_ALL); Token eof = input.read(); if (eof != TOK_EOF) { input.expected(_("end of input")); @@ -403,7 +406,7 @@ void parseExpr(TokenIterator& input, Script& script, Precedence minPrec) { } else if (token == _("{")) { // {} = function block. Parse a new Script intrusive_ptr