From 72cc0a39839a1b30d652590355198ed0877c0c2c Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Sun, 22 Aug 2010 09:17:05 +0200 Subject: [PATCH 01/15] fixed typo in documentation --- components/interpreter/docs/vmformat.txt | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/components/interpreter/docs/vmformat.txt b/components/interpreter/docs/vmformat.txt index 40ce3535b..291d1c490 100644 --- a/components/interpreter/docs/vmformat.txt +++ b/components/interpreter/docs/vmformat.txt @@ -31,8 +31,8 @@ B: argument 1 Segment 0: op 0: push arg0 -op 1: move pv ahead by arg0 -op 2: move pv back by arg0 +op 1: move pc ahead by arg0 +op 2: move pc back by arg0 opcodes 3-31 unused opcodes 32-63 reserved for extensions @@ -119,4 +119,3 @@ op 57: explicit reference = stack[0]; pop; replace stack[0] with distance between explicit reference and a reference of ID stack[0] opcodes 58-33554431 unused opcodes 33554432-67108863 reserved for extensions - From 276a9db6f7a4029215ba232ec5a1b7a1e05f07f8 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Sun, 22 Aug 2010 11:14:14 +0200 Subject: [PATCH 02/15] added missing button implementation for MessageBox --- apps/openmw/mwgui/console.cpp | 35 ++- components/compiler/generator.cpp | 339 ++++++++++++------------- components/compiler/lineparser.cpp | 185 ++++++++------ components/compiler/lineparser.hpp | 21 +- components/interpreter/miscopcodes.hpp | 134 +++++----- 5 files changed, 367 insertions(+), 347 deletions(-) diff --git a/apps/openmw/mwgui/console.cpp b/apps/openmw/mwgui/console.cpp index d9148028f..468cae456 100644 --- a/apps/openmw/mwgui/console.cpp +++ b/apps/openmw/mwgui/console.cpp @@ -10,16 +10,16 @@ namespace MWGui class ConsoleInterpreterContext : public MWScript::InterpreterContext { Console& mConsole; - + public: - - ConsoleInterpreterContext (Console& console, MWWorld::Environment& environment, + + ConsoleInterpreterContext (Console& console, MWWorld::Environment& environment, MWWorld::Ptr reference); virtual void messageBox (const std::string& message, - const std::vector& buttons); + const std::vector& buttons); }; - + ConsoleInterpreterContext::ConsoleInterpreterContext (Console& console, MWWorld::Environment& environment, MWWorld::Ptr reference) : MWScript::InterpreterContext (environment, @@ -39,18 +39,18 @@ namespace MWGui bool Console::compile (const std::string& cmd, Compiler::Output& output) { try - { + { ErrorHandler::reset(); - + std::istringstream input (cmd + '\n'); - + Compiler::Scanner scanner (*this, input, mCompilerContext.getExtensions()); - + Compiler::LineParser parser (*this, mCompilerContext, output.getLocals(), output.getLiterals(), output.getCode(), true); - + scanner.scan (parser); - + return isGood(); } catch (const Compiler::SourceException& error) @@ -61,7 +61,7 @@ namespace MWGui { printError (std::string ("An exception has been thrown: ") + error.what()); } - + return false; } @@ -69,7 +69,7 @@ namespace MWGui { std::ostringstream error; error << "column " << loc.mColumn << " (" << loc.mLiteral << "):"; - + printError (error.str()); printError ((type==ErrorMessage ? "error: " : "warning: ") + message); } @@ -78,7 +78,7 @@ namespace MWGui { printError ((type==ErrorMessage ? "error: " : "warning: ") + message); } - + Console::Console(int w, int h, MWWorld::Environment& environment, const Compiler::Extensions& extensions) : Layout("openmw_console_layout.xml"), @@ -100,7 +100,7 @@ namespace MWGui history->setOverflowToTheLeft(true); history->setEditStatic(true); history->setVisibleVScroll(true); - + // compiler mCompilerContext.setExtensions (&extensions); } @@ -196,7 +196,7 @@ namespace MWGui Compiler::Locals locals; Compiler::Output output (locals); - if (compile (cm, output)) + if (compile (cm + "\n", output)) { try { @@ -205,7 +205,7 @@ namespace MWGui MWScript::installOpcodes (interpreter); std::vector code; output.getCode (code); - interpreter.run (&code[0], code.size()); + interpreter.run (&code[0], code.size()); } catch (const std::exception& error) { @@ -216,4 +216,3 @@ namespace MWGui command->setCaption(""); } } - diff --git a/components/compiler/generator.cpp b/components/compiler/generator.cpp index 0be2c4151..c5262616b 100644 --- a/components/compiler/generator.cpp +++ b/components/compiler/generator.cpp @@ -9,46 +9,46 @@ #include "literals.hpp" namespace -{ +{ void opPushInt (Compiler::Generator::CodeContainer& code, int value) { code.push_back (Compiler::Generator::segment0 (0, value)); } - + void opFetchIntLiteral (Compiler::Generator::CodeContainer& code) { code.push_back (Compiler::Generator::segment5 (4)); } - + void opFetchFloatLiteral (Compiler::Generator::CodeContainer& code) { code.push_back (Compiler::Generator::segment5 (5)); } - + void opIntToFloat (Compiler::Generator::CodeContainer& code) { - code.push_back (Compiler::Generator::segment5 (3)); + code.push_back (Compiler::Generator::segment5 (3)); } - + void opFloatToInt (Compiler::Generator::CodeContainer& code) { code.push_back (Compiler::Generator::segment5 (6)); } - + void opStoreLocalShort (Compiler::Generator::CodeContainer& code) { - code.push_back (Compiler::Generator::segment5 (0)); + code.push_back (Compiler::Generator::segment5 (0)); } - + void opStoreLocalLong (Compiler::Generator::CodeContainer& code) { code.push_back (Compiler::Generator::segment5 (1)); } - + void opStoreLocalFloat (Compiler::Generator::CodeContainer& code) { code.push_back (Compiler::Generator::segment5 (2)); - } + } void opNegateInt (Compiler::Generator::CodeContainer& code) { @@ -99,46 +99,46 @@ namespace { code.push_back (Compiler::Generator::segment5 (16)); } - + void opIntToFloat1 (Compiler::Generator::CodeContainer& code) { - code.push_back (Compiler::Generator::segment5 (17)); + code.push_back (Compiler::Generator::segment5 (17)); } - + void opFloatToInt1 (Compiler::Generator::CodeContainer& code) { code.push_back (Compiler::Generator::segment5 (18)); - } + } void opSquareRoot (Compiler::Generator::CodeContainer& code) { code.push_back (Compiler::Generator::segment5 (19)); - } + } void opReturn (Compiler::Generator::CodeContainer& code) { code.push_back (Compiler::Generator::segment5 (20)); - } - + } + void opMessageBox (Compiler::Generator::CodeContainer& code, int buttons) { code.push_back (Compiler::Generator::segment3 (0, buttons)); } - + void opFetchLocalShort (Compiler::Generator::CodeContainer& code) { - code.push_back (Compiler::Generator::segment5 (21)); + code.push_back (Compiler::Generator::segment5 (21)); } - + void opFetchLocalLong (Compiler::Generator::CodeContainer& code) { code.push_back (Compiler::Generator::segment5 (22)); } - + void opFetchLocalFloat (Compiler::Generator::CodeContainer& code) { code.push_back (Compiler::Generator::segment5 (23)); - } + } void opJumpForward (Compiler::Generator::CodeContainer& code, int offset) { @@ -149,176 +149,176 @@ namespace { code.push_back (Compiler::Generator::segment0 (2, offset)); } - + void opSkipOnZero (Compiler::Generator::CodeContainer& code) { code.push_back (Compiler::Generator::segment5 (24)); - } - + } + void opSkipOnNonZero (Compiler::Generator::CodeContainer& code) { code.push_back (Compiler::Generator::segment5 (25)); - } - + } + void opEqualInt (Compiler::Generator::CodeContainer& code) { code.push_back (Compiler::Generator::segment5 (26)); } - + void opNonEqualInt (Compiler::Generator::CodeContainer& code) { - code.push_back (Compiler::Generator::segment5 (27)); + code.push_back (Compiler::Generator::segment5 (27)); } - + void opLessThanInt (Compiler::Generator::CodeContainer& code) { - code.push_back (Compiler::Generator::segment5 (28)); + code.push_back (Compiler::Generator::segment5 (28)); } - + void opLessOrEqualInt (Compiler::Generator::CodeContainer& code) { - code.push_back (Compiler::Generator::segment5 (29)); + code.push_back (Compiler::Generator::segment5 (29)); } - + void opGreaterThanInt (Compiler::Generator::CodeContainer& code) { - code.push_back (Compiler::Generator::segment5 (30)); + code.push_back (Compiler::Generator::segment5 (30)); } - + void opGreaterOrEqualInt (Compiler::Generator::CodeContainer& code) { - code.push_back (Compiler::Generator::segment5 (31)); + code.push_back (Compiler::Generator::segment5 (31)); } - + void opEqualFloat (Compiler::Generator::CodeContainer& code) { code.push_back (Compiler::Generator::segment5 (32)); } - + void opNonEqualFloat (Compiler::Generator::CodeContainer& code) { - code.push_back (Compiler::Generator::segment5 (33)); + code.push_back (Compiler::Generator::segment5 (33)); } - + void opLessThanFloat (Compiler::Generator::CodeContainer& code) { - code.push_back (Compiler::Generator::segment5 (34)); + code.push_back (Compiler::Generator::segment5 (34)); } - + void opLessOrEqualFloat (Compiler::Generator::CodeContainer& code) { - code.push_back (Compiler::Generator::segment5 (35)); + code.push_back (Compiler::Generator::segment5 (35)); } - + void opGreaterThanFloat (Compiler::Generator::CodeContainer& code) { - code.push_back (Compiler::Generator::segment5 (36)); + code.push_back (Compiler::Generator::segment5 (36)); } - + void opGreaterOrEqualFloat (Compiler::Generator::CodeContainer& code) { - code.push_back (Compiler::Generator::segment5 (37)); - } + code.push_back (Compiler::Generator::segment5 (37)); + } void opMenuMode (Compiler::Generator::CodeContainer& code) { - code.push_back (Compiler::Generator::segment5 (38)); - } - + code.push_back (Compiler::Generator::segment5 (38)); + } + void opStoreGlobalShort (Compiler::Generator::CodeContainer& code) { - code.push_back (Compiler::Generator::segment5 (39)); + code.push_back (Compiler::Generator::segment5 (39)); } - + void opStoreGlobalLong (Compiler::Generator::CodeContainer& code) { code.push_back (Compiler::Generator::segment5 (40)); } - + void opStoreGlobalFloat (Compiler::Generator::CodeContainer& code) { code.push_back (Compiler::Generator::segment5 (41)); - } + } void opFetchGlobalShort (Compiler::Generator::CodeContainer& code) { - code.push_back (Compiler::Generator::segment5 (42)); + code.push_back (Compiler::Generator::segment5 (42)); } - + void opFetchGlobalLong (Compiler::Generator::CodeContainer& code) { code.push_back (Compiler::Generator::segment5 (43)); } - + void opFetchGlobalFloat (Compiler::Generator::CodeContainer& code) { code.push_back (Compiler::Generator::segment5 (44)); - } - + } + void opRandom (Compiler::Generator::CodeContainer& code) { code.push_back (Compiler::Generator::segment5 (45)); - } - + } + void opScriptRunning (Compiler::Generator::CodeContainer& code) { code.push_back (Compiler::Generator::segment5 (46)); - } - + } + void opStartScript (Compiler::Generator::CodeContainer& code) { code.push_back (Compiler::Generator::segment5 (47)); - } - + } + void opStopScript (Compiler::Generator::CodeContainer& code) { code.push_back (Compiler::Generator::segment5 (48)); - } - + } + void opGetDistance (Compiler::Generator::CodeContainer& code) { code.push_back (Compiler::Generator::segment5 (49)); - } - + } + void opGetSecondsPassed (Compiler::Generator::CodeContainer& code) { code.push_back (Compiler::Generator::segment5 (50)); - } + } void opEnable (Compiler::Generator::CodeContainer& code) { code.push_back (Compiler::Generator::segment5 (51)); - } + } void opDisable (Compiler::Generator::CodeContainer& code) { code.push_back (Compiler::Generator::segment5 (52)); - } + } void opGetDisabled (Compiler::Generator::CodeContainer& code) { code.push_back (Compiler::Generator::segment5 (53)); - } + } void opEnableExplicit (Compiler::Generator::CodeContainer& code) { code.push_back (Compiler::Generator::segment5 (54)); - } + } void opDisableExplicit (Compiler::Generator::CodeContainer& code) { code.push_back (Compiler::Generator::segment5 (55)); - } + } void opGetDisabledExplicit (Compiler::Generator::CodeContainer& code) { code.push_back (Compiler::Generator::segment5 (56)); } - + void opGetDistanceExplicit (Compiler::Generator::CodeContainer& code) { code.push_back (Compiler::Generator::segment5 (57)); - } + } } namespace Compiler @@ -327,31 +327,31 @@ namespace Compiler { void pushInt (CodeContainer& code, Literals& literals, int value) { - int index = literals.addInteger (value); + int index = literals.addInteger (value); opPushInt (code, index); - opFetchIntLiteral (code); + opFetchIntLiteral (code); } - + void pushFloat (CodeContainer& code, Literals& literals, float value) { - int index = literals.addFloat (value); + int index = literals.addFloat (value); opPushInt (code, index); opFetchFloatLiteral (code); } - + void pushString (CodeContainer& code, Literals& literals, const std::string& value) { - int index = literals.addString (value); + int index = literals.addString (value); opPushInt (code, index); } - + void assignToLocal (CodeContainer& code, char localType, int localIndex, const CodeContainer& value, char valueType) - { + { opPushInt (code, localIndex); std::copy (value.begin(), value.end(), std::back_inserter (code)); - + if (localType!=valueType) { if (localType=='f' && valueType=='l') @@ -363,26 +363,26 @@ namespace Compiler opFloatToInt (code); } } - + switch (localType) { case 'f': - + opStoreLocalFloat (code); break; - + case 's': opStoreLocalShort (code); break; - + case 'l': opStoreLocalLong (code); break; - + default: - + assert (0); } } @@ -392,21 +392,21 @@ namespace Compiler switch (valueType) { case 'l': - + opNegateInt (code); break; - + case 'f': - + opNegateFloat (code); break; - + default: - + assert (0); } } - + void add (CodeContainer& code, char valueType1, char valueType2) { if (valueType1=='l' && valueType2=='l') @@ -420,7 +420,7 @@ namespace Compiler if (valueType2=='l') opIntToFloat (code); - + opAddFloat (code); } } @@ -438,11 +438,11 @@ namespace Compiler if (valueType2=='l') opIntToFloat (code); - + opSubFloat (code); } } - + void mul (CodeContainer& code, char valueType1, char valueType2) { if (valueType1=='l' && valueType2=='l') @@ -456,11 +456,11 @@ namespace Compiler if (valueType2=='l') opIntToFloat (code); - + opMulFloat (code); - } - } - + } + } + void div (CodeContainer& code, char valueType1, char valueType2) { if (valueType1=='l' && valueType2=='l') @@ -474,11 +474,11 @@ namespace Compiler if (valueType2=='l') opIntToFloat (code); - + opDivFloat (code); - } + } } - + void convert (CodeContainer& code, char fromType, char toType) { if (fromType!=toType) @@ -491,28 +491,26 @@ namespace Compiler throw std::logic_error ("illegal type conversion"); } } - + void squareRoot (CodeContainer& code) { opSquareRoot (code); } - + void exit (CodeContainer& code) { opReturn (code); - } - + } + void message (CodeContainer& code, Literals& literals, const std::string& message, int buttons) { - assert (buttons==0); - int index = literals.addString (message); - + opPushInt (code, index); opMessageBox (code, buttons); } - + void fetchLocal (CodeContainer& code, char localType, int localIndex) { opPushInt (code, localIndex); @@ -520,26 +518,26 @@ namespace Compiler switch (localType) { case 'f': - + opFetchLocalFloat (code); break; - + case 's': opFetchLocalShort (code); break; - + case 'l': opFetchLocalLong (code); break; - + default: - + assert (0); - } + } } - + void jump (CodeContainer& code, int offset) { if (offset>0) @@ -549,27 +547,27 @@ namespace Compiler else throw std::logic_error ("inifite loop"); } - + void jumpOnZero (CodeContainer& code, int offset) { opSkipOnNonZero (code); - + if (offset<0) --offset; // compensate for skip instruction - + jump (code, offset); } void jumpOnNonZero (CodeContainer& code, int offset) { opSkipOnZero (code); - + if (offset<0) --offset; // compensate for skip instruction - - jump (code, offset); + + jump (code, offset); } - + void compare (CodeContainer& code, char op, char valueType1, char valueType2) { if (valueType1=='l' && valueType2=='l') @@ -582,9 +580,9 @@ namespace Compiler case 'L': opLessOrEqualInt (code); break; case 'g': opGreaterThanInt (code); break; case 'G': opGreaterOrEqualInt (code); break; - + default: - + assert (0); } } @@ -595,7 +593,7 @@ namespace Compiler if (valueType2=='l') opIntToFloat (code); - + switch (op) { case 'e': opEqualFloat (code); break; @@ -604,28 +602,28 @@ namespace Compiler case 'L': opLessOrEqualFloat (code); break; case 'g': opGreaterThanFloat (code); break; case 'G': opGreaterOrEqualFloat (code); break; - + default: - + assert (0); } - } + } } - + void menuMode (CodeContainer& code) { opMenuMode (code); } - + void assignToGlobal (CodeContainer& code, Literals& literals, char localType, const std::string& name, const CodeContainer& value, char valueType) { int index = literals.addString (name); - + opPushInt (code, index); std::copy (value.begin(), value.end(), std::back_inserter (code)); - + if (localType!=valueType) { if (localType=='f' && valueType=='l') @@ -637,30 +635,30 @@ namespace Compiler opFloatToInt (code); } } - + switch (localType) { case 'f': - + opStoreGlobalFloat (code); break; - + case 's': opStoreGlobalShort (code); break; - + case 'l': opStoreGlobalLong (code); break; - + default: - + assert (0); - } + } } - + void fetchGlobal (CodeContainer& code, Literals& literals, char localType, const std::string& name) { @@ -671,36 +669,36 @@ namespace Compiler switch (localType) { case 'f': - + opFetchGlobalFloat (code); break; - + case 's': opFetchGlobalShort (code); break; - + case 'l': opFetchGlobalLong (code); break; - + default: - + assert (0); - } + } } - + void random (CodeContainer& code) { opRandom (code); } - + void scriptRunning (CodeContainer& code) { opScriptRunning (code); } - + void startScript (CodeContainer& code) { opStartScript (code); @@ -714,7 +712,7 @@ namespace Compiler void getDistance (CodeContainer& code, Literals& literals, const std::string id) { if (id.empty()) - { + { opGetDistance (code); } else @@ -722,14 +720,14 @@ namespace Compiler int index = literals.addString (id); opPushInt (code, index); opGetDistanceExplicit (code); - } - } - + } + } + void getSecondsPassed (CodeContainer& code) { opGetSecondsPassed (code); } - + void getDisabled (CodeContainer& code, Literals& literals, const std::string id) { if (id.empty()) @@ -743,11 +741,11 @@ namespace Compiler opGetDisabledExplicit (code); } } - + void enable (CodeContainer& code, Literals& literals, const std::string id) { if (id.empty()) - { + { opEnable (code); } else @@ -755,13 +753,13 @@ namespace Compiler int index = literals.addString (id); opPushInt (code, index); opEnableExplicit (code); - } + } } - + void disable (CodeContainer& code, Literals& literals, const std::string id) { if (id.empty()) - { + { opDisable (code); } else @@ -773,4 +771,3 @@ namespace Compiler } } } - diff --git a/components/compiler/lineparser.cpp b/components/compiler/lineparser.cpp index 927990a32..b4c79c972 100644 --- a/components/compiler/lineparser.cpp +++ b/components/compiler/lineparser.cpp @@ -14,32 +14,32 @@ namespace Compiler void LineParser::parseExpression (Scanner& scanner, const TokenLoc& loc) { mExprParser.reset(); - + if (!mExplicit.empty()) { mExprParser.parseName (mExplicit, loc, scanner); mExprParser.parseSpecial (Scanner::S_ref, loc, scanner); } - + scanner.scan (mExprParser); - + char type = mExprParser.append (mCode); - mState = EndState; - + mState = EndState; + switch (type) { case 'l': - - Generator::message (mCode, mLiterals, "%g", 0); + + Generator::message (mCode, mLiterals, "%g", 0); break; - + case 'f': - - Generator::message (mCode, mLiterals, "%f", 0); + + Generator::message (mCode, mLiterals, "%f", 0); break; - + default: - + throw std::runtime_error ("unknown expression result type"); } } @@ -52,14 +52,14 @@ namespace Compiler {} bool LineParser::parseInt (int value, const TokenLoc& loc, Scanner& scanner) - { + { if (mAllowExpression && mState==BeginState) { scanner.putbackInt (value, loc); parseExpression (scanner, loc); return true; } - + return Parser::parseInt (value, loc, scanner); } @@ -71,7 +71,7 @@ namespace Compiler parseExpression (scanner, loc); return true; } - + return Parser::parseFloat (value, loc, scanner); } @@ -87,11 +87,11 @@ namespace Compiler scanner.scan (skip); return false; } - + std::string name2 = toLower (name); - + char type = mLocals.getType (name2); - + if (type!=' ') { getErrorHandler().error ("can't re-declare local variable", loc); @@ -99,14 +99,14 @@ namespace Compiler scanner.scan (skip); return false; } - + mLocals.declare (mState==ShortState ? 's' : (mState==LongState ? 'l' : 'f'), name2); - + mState = EndState; return true; } - + if (mState==SetState) { std::string name2 = toLower (name); @@ -119,7 +119,7 @@ namespace Compiler mState = SetLocalVarState; return true; } - + type = getContext().getGlobalType (name2); if (type!=' ') { @@ -127,18 +127,18 @@ namespace Compiler mType = type; mState = SetGlobalVarState; return true; - } - + } + getErrorHandler().error ("unknown variable", loc); SkipParser skip (getErrorHandler(), getContext()); scanner.scan (skip); - return false; + return false; } - + if (mState==MessageState || mState==MessageCommaState) { std::string arguments; - + for (std::size_t i=0; iisInstruction (keyword, argumentType, mState==ExplicitState)) { mExprParser.parseArguments (argumentType, scanner, mCode, true); - + extensions->generateInstructionCode (keyword, mCode, mLiterals, mExplicit); mState = EndState; return true; } - } - + } + if (mAllowExpression) { if (keyword==Scanner::K_getdisabled || keyword==Scanner::K_getdistance) { scanner.putbackKeyword (keyword, loc); parseExpression (scanner, loc); - return true; + return true; } if (const Extensions *extensions = getContext().getExtensions()) { char returnType; std::string argumentType; - + if (extensions->isFunction (keyword, returnType, argumentType, !mExplicit.empty())) { scanner.putbackKeyword (keyword, loc); parseExpression (scanner, loc); - return true; + return true; } - } + } } } - + if (mState==BeginState) { switch (keyword) @@ -278,39 +284,39 @@ namespace Compiler case Scanner::K_float: mState = FloatState; return true; case Scanner::K_set: mState = SetState; return true; case Scanner::K_messagebox: mState = MessageState; return true; - + case Scanner::K_return: - + Generator::exit (mCode); mState = EndState; return true; - + case Scanner::K_startscript: - mExprParser.parseArguments ("c", scanner, mCode, true); + mExprParser.parseArguments ("c", scanner, mCode, true); Generator::startScript (mCode); mState = EndState; - return true; - + return true; + case Scanner::K_stopscript: - mExprParser.parseArguments ("c", scanner, mCode, true); + mExprParser.parseArguments ("c", scanner, mCode, true); Generator::stopScript (mCode); mState = EndState; - return true; + return true; } } else if (mState==SetLocalVarState && keyword==Scanner::K_to) { mExprParser.reset(); scanner.scan (mExprParser); - + std::vector code; char type = mExprParser.append (code); - + Generator::assignToLocal (mCode, mLocals.getType (mName), mLocals.getIndex (mName), code, type); - + mState = EndState; return true; } @@ -318,16 +324,16 @@ namespace Compiler { mExprParser.reset(); scanner.scan (mExprParser); - + std::vector code; char type = mExprParser.append (code); - + Generator::assignToGlobal (mCode, mLiterals, mType, mName, code, type); - + mState = EndState; return true; } - + if (mAllowExpression) { if (keyword==Scanner::K_getsquareroot || keyword==Scanner::K_menumode || @@ -336,10 +342,10 @@ namespace Compiler { scanner.putbackKeyword (keyword, loc); parseExpression (scanner, loc); - return true; - } + return true; + } } - + return Parser::parseKeyword (keyword, loc, scanner); } @@ -347,30 +353,42 @@ namespace Compiler { if (code==Scanner::S_newline && (mState==EndState || mState==BeginState)) return false; - + if (code==Scanner::S_comma && mState==MessageState) { mState = MessageCommaState; return true; } - + if (code==Scanner::S_ref && mState==PotentialExplicitState) { mState = ExplicitState; return true; } - + + if (code==Scanner::S_newline && mState==MessageButtonState) + { + Generator::message (mCode, mLiterals, mName, mButtons); + return false; + } + + if (code==Scanner::S_comma && mState==MessageButtonState) + { + mState = MessageButtonCommaState; + return true; + } + if (mAllowExpression && mState==BeginState && (code==Scanner::S_open || code==Scanner::S_minus)) { scanner.putbackSpecial (code, loc); parseExpression (scanner, loc); - return true; + return true; } - + return Parser::parseSpecial (code, loc, scanner); } - + void LineParser::reset() { mState = BeginState; @@ -378,4 +396,3 @@ namespace Compiler mExplicit.clear(); } } - diff --git a/components/compiler/lineparser.hpp b/components/compiler/lineparser.hpp index c407d3b6b..531b7762f 100644 --- a/components/compiler/lineparser.hpp +++ b/components/compiler/lineparser.hpp @@ -12,9 +12,9 @@ namespace Compiler { class Locals; class Literals; - + /// \brief Line parser, to be used in console scripts and as part of ScriptParser - + class LineParser : public Parser { enum State @@ -22,31 +22,32 @@ namespace Compiler BeginState, ShortState, LongState, FloatState, SetState, SetLocalVarState, SetGlobalVarState, - MessageState, MessageCommaState, + MessageState, MessageCommaState, MessageButtonState, MessageButtonCommaState, EndState, PotentialExplicitState, ExplicitState }; - Locals& mLocals; + Locals& mLocals; Literals& mLiterals; std::vector& mCode; State mState; std::string mName; + int mButtons; std::string mExplicit; char mType; ExprParser mExprParser; bool mAllowExpression; - + void parseExpression (Scanner& scanner, const TokenLoc& loc); - + public: - + LineParser (ErrorHandler& errorHandler, Context& context, Locals& locals, Literals& literals, std::vector& code, bool allowExpression = false); ///< \param allowExpression Allow lines consisting of a naked expression /// (result is send to the messagebox interface) - + virtual bool parseInt (int value, const TokenLoc& loc, Scanner& scanner); ///< Handle an int token. /// \return fetch another token? @@ -67,9 +68,9 @@ namespace Compiler virtual bool parseSpecial (int code, const TokenLoc& loc, Scanner& scanner); ///< Handle a special character token. /// \return fetch another token? - + void reset(); - ///< Reset parser to clean state. + ///< Reset parser to clean state. }; } diff --git a/components/interpreter/miscopcodes.hpp b/components/interpreter/miscopcodes.hpp index 8d05c58da..7e7dcd18a 100644 --- a/components/interpreter/miscopcodes.hpp +++ b/components/interpreter/miscopcodes.hpp @@ -6,6 +6,7 @@ #include #include #include +#include #include "opcodes.hpp" #include "runtime.hpp" @@ -15,24 +16,33 @@ namespace Interpreter class OpMessageBox : public Opcode1 { public: - + virtual void execute (Runtime& runtime, unsigned int arg0) { - if (arg0!=0) - throw std::logic_error ("message box buttons not implemented yet"); - - // message + // buttons + std::vector buttons; + + for (std::size_t i=0; i buttons; - + runtime.getContext().messageBox (formattedMessage, buttons); - } - }; - + } + }; + class OpMenuMode : public Opcode0 { public: - + virtual void execute (Runtime& runtime) { runtime.push (runtime.getContext().menuMode()); - } + } }; - + class OpRandom : public Opcode0 { public: - + virtual void execute (Runtime& runtime) { double r = static_cast (std::rand()) / RAND_MAX; // [0, 1) - + Type_Integer limit = runtime[0].mInteger; - + if (limit<0) throw std::runtime_error ( "random: argument out of range (Don't be so negative!)"); - + Type_Integer value = static_cast (r*limit); // [o, limit) - + runtime[0].mInteger = value; - } - }; - + } + }; + class OpGetSecondsPassed : public Opcode0 { public: - + virtual void execute (Runtime& runtime) { Type_Float duration = runtime.getContext().getSecondsPassed(); - + runtime.push (duration); - } + } }; - + class OpEnable : public Opcode0 { public: - + virtual void execute (Runtime& runtime) { runtime.getContext().enable(); - } - }; - + } + }; + class OpDisable : public Opcode0 { public: - + virtual void execute (Runtime& runtime) { runtime.getContext().disable(); - } - }; - + } + }; + class OpGetDisabled : public Opcode0 { public: - + virtual void execute (Runtime& runtime) { runtime.push (runtime.getContext().isDisabled()); - } - }; - + } + }; + class OpEnableExplicit : public Opcode0 { public: - + virtual void execute (Runtime& runtime) { int index = runtime[0].mInteger; runtime.pop(); std::string id = runtime.getStringLiteral (index); - + runtime.getContext().enable (id); - } - }; - + } + }; + class OpDisableExplicit : public Opcode0 { public: - + virtual void execute (Runtime& runtime) { int index = runtime[0].mInteger; runtime.pop(); std::string id = runtime.getStringLiteral (index); - + runtime.getContext().disable (id); - } - }; - + } + }; + class OpGetDisabledExplicit : public Opcode0 { public: - + virtual void execute (Runtime& runtime) { int index = runtime[0].mInteger; runtime.pop(); std::string id = runtime.getStringLiteral (index); - + runtime.push (runtime.getContext().isDisabled (id)); - } - }; - + } + }; + } #endif - From 09a258253ca84d767dafee1d39f86d5763dca93a Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Sun, 22 Aug 2010 11:17:19 +0200 Subject: [PATCH 03/15] removed custom messageBox implementation for console --- apps/openmw/mwgui/console.cpp | 12 ------------ 1 file changed, 12 deletions(-) diff --git a/apps/openmw/mwgui/console.cpp b/apps/openmw/mwgui/console.cpp index 468cae456..471b2810b 100644 --- a/apps/openmw/mwgui/console.cpp +++ b/apps/openmw/mwgui/console.cpp @@ -15,9 +15,6 @@ namespace MWGui ConsoleInterpreterContext (Console& console, MWWorld::Environment& environment, MWWorld::Ptr reference); - - virtual void messageBox (const std::string& message, - const std::vector& buttons); }; ConsoleInterpreterContext::ConsoleInterpreterContext (Console& console, @@ -27,15 +24,6 @@ namespace MWGui mConsole (console) {} - void ConsoleInterpreterContext::messageBox (const std::string& message, - const std::vector& buttons) - { - if (!buttons.empty()) - mConsole.printError ("MessageBox doesn't support buttons while in console mode"); - else - mConsole.printOK (message); - } - bool Console::compile (const std::string& cmd, Compiler::Output& output) { try From 17135a64035d1f26b8bdd6f7125254935b9067e8 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Sun, 22 Aug 2010 11:22:10 +0200 Subject: [PATCH 04/15] routed message box output through window manager --- apps/openmw/mwgui/window_manager.cpp | 9 +++++++++ apps/openmw/mwgui/window_manager.hpp | 3 +++ apps/openmw/mwscript/interpretercontext.cpp | 5 +---- 3 files changed, 13 insertions(+), 4 deletions(-) diff --git a/apps/openmw/mwgui/window_manager.cpp b/apps/openmw/mwgui/window_manager.cpp index 726cd5bd8..ed4085ea8 100644 --- a/apps/openmw/mwgui/window_manager.cpp +++ b/apps/openmw/mwgui/window_manager.cpp @@ -4,6 +4,7 @@ #include "console.hpp" #include +#include using namespace MWGui; @@ -95,3 +96,11 @@ void WindowManager::setValue (const std::string& id, const MWMechanics::DynamicS stats->setValue (id, value); hud->setValue (id, value); } + +void WindowManager::messageBox (const std::string& message, const std::vector& buttons) +{ + std::cout << "message box: " << message << std::endl; + + if (!buttons.empty()) + std::cerr << "error: message box buttons not supported" << std::endl; +} diff --git a/apps/openmw/mwgui/window_manager.hpp b/apps/openmw/mwgui/window_manager.hpp index a2e664d26..ea2d87bc9 100644 --- a/apps/openmw/mwgui/window_manager.hpp +++ b/apps/openmw/mwgui/window_manager.hpp @@ -11,6 +11,7 @@ */ #include +#include #include "../mwmechanics/stat.hpp" @@ -144,6 +145,8 @@ namespace MWGui void setValue (const std::string& id, const MWMechanics::DynamicStat& value); ///< Set value for the given ID. + + void messageBox (const std::string& message, const std::vector& buttons); }; } #endif diff --git a/apps/openmw/mwscript/interpretercontext.cpp b/apps/openmw/mwscript/interpretercontext.cpp index 404aa69a6..22a5aaa70 100644 --- a/apps/openmw/mwscript/interpretercontext.cpp +++ b/apps/openmw/mwscript/interpretercontext.cpp @@ -105,10 +105,7 @@ namespace MWScript void InterpreterContext::messageBox (const std::string& message, const std::vector& buttons) { - std::cout << "message box: " << message << std::endl; - - if (!buttons.empty()) - std::cerr << "error: message box buttons not supported" << std::endl; + mEnvironment.mWindowManager->messageBox (message, buttons); } bool InterpreterContext::menuMode() From f4e79a48f05197734c1ae7860875a600e8fe4039 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Sun, 22 Aug 2010 12:47:56 +0200 Subject: [PATCH 05/15] implemented optional arguments --- components/compiler/controlparser.cpp | 114 +++++----- components/compiler/exprparser.cpp | 309 +++++++++++++++----------- components/compiler/exprparser.hpp | 46 ++-- components/compiler/fileparser.cpp | 30 +-- components/compiler/parser.cpp | 48 +++- components/compiler/parser.hpp | 17 +- components/compiler/stringparser.cpp | 19 +- 7 files changed, 344 insertions(+), 239 deletions(-) diff --git a/components/compiler/controlparser.cpp b/components/compiler/controlparser.cpp index 4715d3214..2f5d5c4b6 100644 --- a/components/compiler/controlparser.cpp +++ b/components/compiler/controlparser.cpp @@ -17,21 +17,21 @@ namespace Compiler { std::pair entry; - if (mState!=IfElseBodyState) + if (mState!=IfElseBodyState) mExprParser.append (entry.first); std::copy (mCodeBlock.begin(), mCodeBlock.end(), std::back_inserter (entry.second)); - + mIfCode.push_back (entry); mCodeBlock.clear(); - + if (keyword==Scanner::K_endif) { // store code for if-cascade Codes codes; - + for (IfCodes::reverse_iterator iter (mIfCode.rbegin()); iter!=mIfCode.rend(); ++iter) { @@ -47,17 +47,17 @@ namespace Compiler std::back_inserter (block)); Generator::jumpOnZero (block, iter->second.size()+1); } - + std::copy (iter->second.begin(), iter->second.end(), std::back_inserter (block)); - + std::swap (codes, block); - + std::copy (block.begin(), block.end(), std::back_inserter (codes)); } - + std::copy (codes.begin(), codes.end(), std::back_inserter (mCode)); - + mIfCode.clear(); mState = IfEndifState; } @@ -66,36 +66,36 @@ namespace Compiler mExprParser.reset(); scanner.scan (mExprParser); - mState = IfElseifEndState; + mState = IfElseifEndState; } else if (keyword==Scanner::K_else) { - mState = IfElseEndState; - } - + mState = IfElseEndState; + } + return true; } else if (keyword==Scanner::K_if || keyword==Scanner::K_while) { // nested ControlParser parser (getErrorHandler(), getContext(), mLocals, mLiterals); - + if (parser.parseKeyword (keyword, loc, scanner)) - scanner.scan (parser); - - parser.appendCode (mCodeBlock); - + scanner.scan (parser); + + parser.appendCode (mCodeBlock); + return true; } else { mLineParser.reset(); if (mLineParser.parseKeyword (keyword, loc, scanner)) - scanner.scan (mLineParser); - - return true; - } - + scanner.scan (mLineParser); + + return true; + } + return false; } @@ -104,24 +104,24 @@ namespace Compiler if (keyword==Scanner::K_endwhile) { Codes loop; - + Codes expr; mExprParser.append (expr); - + Generator::jump (loop, -mCodeBlock.size()-expr.size()); - + std::copy (expr.begin(), expr.end(), std::back_inserter (mCode)); Codes skip; - + Generator::jumpOnZero (skip, mCodeBlock.size()+loop.size()+1); - + std::copy (skip.begin(), skip.end(), std::back_inserter (mCode)); - + std::copy (mCodeBlock.begin(), mCodeBlock.end(), std::back_inserter (mCode)); - + Codes loop2; - + Generator::jump (loop2, -mCodeBlock.size()-expr.size()-skip.size()); if (loop.size()!=loop2.size()) @@ -129,31 +129,31 @@ namespace Compiler "internal compiler error: failed to generate a while loop"); std::copy (loop2.begin(), loop2.end(), std::back_inserter (mCode)); - + mState = WhileEndwhileState; - return true; + return true; } else if (keyword==Scanner::K_if || keyword==Scanner::K_while) { // nested ControlParser parser (getErrorHandler(), getContext(), mLocals, mLiterals); - + if (parser.parseKeyword (keyword, loc, scanner)) - scanner.scan (parser); - - parser.appendCode (mCodeBlock); - + scanner.scan (parser); + + parser.appendCode (mCodeBlock); + return true; } else { mLineParser.reset(); if (mLineParser.parseKeyword (keyword, loc, scanner)) - scanner.scan (mLineParser); - - return true; - } - + scanner.scan (mLineParser); + + return true; + } + return false; } @@ -164,14 +164,14 @@ namespace Compiler mExprParser (errorHandler, context, locals, literals), mState (StartState) { - + } - + void ControlParser::appendCode (std::vector& code) const { std::copy (mCode.begin(), mCode.end(), std::back_inserter (code)); } - + bool ControlParser::parseKeyword (int keyword, const TokenLoc& loc, Scanner& scanner) { if (mState==StartState) @@ -190,20 +190,20 @@ namespace Compiler scanner.scan (mExprParser); mState = WhileEndState; - return true; + return true; } } else if (mState==IfBodyState || mState==IfElseifBodyState || mState==IfElseBodyState) { if (parseIfBody (keyword, loc, scanner)) - return true; + return true; } else if (mState==WhileBodyState) { if ( parseWhileBody (keyword, loc, scanner)) return true; } - + return Parser::parseKeyword (keyword, loc, scanner); } @@ -218,24 +218,24 @@ namespace Compiler case IfElseEndState: mState = IfElseBodyState; return true; case WhileEndState: mState = WhileBodyState; return true; - + case IfBodyState: case IfElseifBodyState: case IfElseBodyState: case WhileBodyState: - + return true; // empty line - + case IfEndifState: case WhileEndwhileState: - + return false; - + default: ; } - + } - + return Parser::parseSpecial (code, loc, scanner); } @@ -245,6 +245,6 @@ namespace Compiler mCodeBlock.clear(); mIfCode.clear(); mState = StartState; + Parser::reset(); } } - diff --git a/components/compiler/exprparser.cpp b/components/compiler/exprparser.cpp index d0138078e..484aea878 100644 --- a/components/compiler/exprparser.cpp +++ b/components/compiler/exprparser.cpp @@ -22,33 +22,33 @@ namespace Compiler switch (op) { case '(': - + return 0; - + case 'e': // == case 'n': // != case 'l': // < case 'L': // <= case 'g': // < case 'G': // >= - + return 1; - + case '+': case '-': - + return 2; - + case '*': case '/': - + return 3; - + case 'm': - + return 4; } - + return 0; } @@ -59,7 +59,7 @@ namespace Compiler assert (Index (mOperands.size())); return mOperands[mOperands.size()-1-Index]; } - + char ExprParser::getOperator() const { assert (!mOperators.empty()); @@ -70,27 +70,27 @@ namespace Compiler { return std::find (mOperators.begin(), mOperators.end(), '(')!=mOperators.end(); } - + void ExprParser::popOperator() { assert (!mOperators.empty()); - mOperators.resize (mOperators.size()-1); + mOperators.resize (mOperators.size()-1); } - + void ExprParser::popOperand() { assert (!mOperands.empty()); - mOperands.resize (mOperands.size()-1); + mOperands.resize (mOperands.size()-1); } void ExprParser::replaceBinaryOperands() { char t1 = getOperandType (1); char t2 = getOperandType(); - + popOperand(); popOperand(); - + if (t1==t2) mOperands.push_back (t1); else if (t1=='f' || t2=='f') @@ -102,59 +102,59 @@ namespace Compiler void ExprParser::pop() { char op = getOperator(); - + switch (op) { case 'm': - + Generator::negate (mCode, getOperandType()); popOperator(); break; case '+': - + Generator::add (mCode, getOperandType (1), getOperandType()); popOperator(); replaceBinaryOperands(); break; case '-': - + Generator::sub (mCode, getOperandType (1), getOperandType()); popOperator(); replaceBinaryOperands(); break; - + case '*': - + Generator::mul (mCode, getOperandType (1), getOperandType()); popOperator(); replaceBinaryOperands(); - break; - + break; + case '/': - + Generator::div (mCode, getOperandType (1), getOperandType()); popOperator(); replaceBinaryOperands(); break; - + case 'e': case 'n': case 'l': case 'L': case 'g': case 'G': - + Generator::compare (mCode, op, getOperandType (1), getOperandType()); popOperator(); popOperand(); popOperand(); mOperands.push_back ('l'); break; - + default: - + throw std::logic_error ("unknown operator"); } } @@ -165,36 +165,36 @@ namespace Compiler mOperands.push_back ('l'); Generator::pushInt (mCode, mLiterals, value); } - + void ExprParser::pushFloatLiteral (float value) { mNextOperand = false; mOperands.push_back ('f'); - Generator::pushFloat (mCode, mLiterals, value); + Generator::pushFloat (mCode, mLiterals, value); } - + void ExprParser::pushBinaryOperator (char c) { while (!mOperators.empty() && getPriority (getOperator())>=getPriority (c)) pop(); - + mOperators.push_back (c); mNextOperand = true; } - + void ExprParser::close() { while (getOperator()!='(') pop(); - + popOperator(); } - - void ExprParser::parseArguments (const std::string& arguments, Scanner& scanner) + + int ExprParser::parseArguments (const std::string& arguments, Scanner& scanner) { - parseArguments (arguments, scanner, mCode); + return parseArguments (arguments, scanner, mCode); } - + ExprParser::ExprParser (ErrorHandler& errorHandler, Context& context, Locals& locals, Literals& literals, bool argument) : Parser (errorHandler, context), mLocals (locals), mLiterals (literals), @@ -205,11 +205,13 @@ namespace Compiler { if (!mExplicit.empty()) return Parser::parseInt (value, loc, scanner); - + mFirst = false; - + if (mNextOperand) - { + { + start(); + pushIntegerLiteral (value); mTokenLoc = loc; return true; @@ -228,13 +230,15 @@ namespace Compiler return Parser::parseFloat (value, loc, scanner); mFirst = false; - + if (mNextOperand) - { + { + start(); + pushFloatLiteral (value); mTokenLoc = loc; return true; - } + } else { // no comma was used between arguments @@ -252,29 +256,31 @@ namespace Compiler mFirst = false; if (mNextOperand) - { + { + start(); + std::string name2 = toLower (name); - + char type = mLocals.getType (name2); - + if (type!=' ') { Generator::fetchLocal (mCode, type, mLocals.getIndex (name2)); mNextOperand = false; - mOperands.push_back (type=='f' ? 'f' : 'l'); - return true; + mOperands.push_back (type=='f' ? 'f' : 'l'); + return true; } - + type = getContext().getGlobalType (name2); - + if (type!=' ') { Generator::fetchGlobal (mCode, mLiterals, type, name2); mNextOperand = false; - mOperands.push_back (type=='f' ? 'f' : 'l'); - return true; + mOperands.push_back (type=='f' ? 'f' : 'l'); + return true; } - + if (mExplicit.empty() && getContext().isId (name)) { mExplicit = name; @@ -287,161 +293,183 @@ namespace Compiler scanner.putbackName (name, loc); return false; } - + return Parser::parseName (name, loc, scanner); } bool ExprParser::parseKeyword (int keyword, const TokenLoc& loc, Scanner& scanner) { mFirst = false; - + if (!mExplicit.empty()) { if (mRefOp && mNextOperand) { if (keyword==Scanner::K_getdisabled) { - mTokenLoc = loc; + start(); + + mTokenLoc = loc; Generator::getDisabled (mCode, mLiterals, mExplicit); mOperands.push_back ('l'); mExplicit.clear(); mRefOp = false; - + mNextOperand = false; - return true; - } + return true; + } else if (keyword==Scanner::K_getdistance) { + start(); + mTokenLoc = loc; parseArguments ("c", scanner); - + Generator::getDistance (mCode, mLiterals, mExplicit); mOperands.push_back ('f'); mExplicit.clear(); mRefOp = false; - + mNextOperand = false; return true; - } + } // check for custom extensions if (const Extensions *extensions = getContext().getExtensions()) { char returnType; std::string argumentType; - + if (extensions->isFunction (keyword, returnType, argumentType, true)) { + start(); + mTokenLoc = loc; parseArguments (argumentType, scanner); - + extensions->generateFunctionCode (keyword, mCode, mLiterals, mExplicit); mOperands.push_back (returnType); mExplicit.clear(); mRefOp = false; - + mNextOperand = false; return true; } } } - + return Parser::parseKeyword (keyword, loc, scanner); } - + if (mNextOperand) - { + { if (keyword==Scanner::K_getsquareroot) { - mTokenLoc = loc; + start(); + + mTokenLoc = loc; parseArguments ("f", scanner); Generator::squareRoot (mCode); mOperands.push_back ('f'); - + mNextOperand = false; return true; } else if (keyword==Scanner::K_menumode) { + start(); + mTokenLoc = loc; - + Generator::menuMode (mCode); mOperands.push_back ('l'); - + mNextOperand = false; return true; } else if (keyword==Scanner::K_random) { - mTokenLoc = loc; + start(); + + mTokenLoc = loc; parseArguments ("l", scanner); Generator::random (mCode); mOperands.push_back ('l'); - + mNextOperand = false; - return true; + return true; } else if (keyword==Scanner::K_scriptrunning) { + start(); + mTokenLoc = loc; parseArguments ("c", scanner); - + Generator::scriptRunning (mCode); mOperands.push_back ('l'); - + mNextOperand = false; return true; - } + } else if (keyword==Scanner::K_getdistance) { + start(); + mTokenLoc = loc; parseArguments ("c", scanner); - + Generator::getDistance (mCode, mLiterals, ""); mOperands.push_back ('f'); - + mNextOperand = false; return true; - } + } else if (keyword==Scanner::K_getsecondspassed) { - mTokenLoc = loc; + start(); + + mTokenLoc = loc; Generator::getSecondsPassed (mCode); mOperands.push_back ('f'); - + mNextOperand = false; - return true; + return true; } else if (keyword==Scanner::K_getdisabled) { - mTokenLoc = loc; + start(); + + mTokenLoc = loc; Generator::getDisabled (mCode, mLiterals, ""); mOperands.push_back ('l'); - + mNextOperand = false; - return true; + return true; } else { // check for custom extensions if (const Extensions *extensions = getContext().getExtensions()) { + start(); + char returnType; std::string argumentType; - + if (extensions->isFunction (keyword, returnType, argumentType, false)) { mTokenLoc = loc; parseArguments (argumentType, scanner); - + extensions->generateFunctionCode (keyword, mCode, mLiterals, ""); mOperands.push_back (returnType); - + mNextOperand = false; return true; } @@ -454,7 +482,7 @@ namespace Compiler scanner.putbackKeyword (keyword, loc); return false; } - + return Parser::parseKeyword (keyword, loc, scanner); } @@ -467,10 +495,10 @@ namespace Compiler mRefOp = true; return true; } - + return Parser::parseSpecial (code, loc, scanner); } - + if (code==Scanner::S_comma) { mTokenLoc = loc; @@ -481,14 +509,14 @@ namespace Compiler mFirst = false; return true; } - + // end marker scanner.putbackSpecial (code, loc); return false; } mFirst = false; - + if (code==Scanner::S_newline) { // end marker @@ -496,7 +524,7 @@ namespace Compiler scanner.putbackSpecial (code, loc); return false; } - + if (code==Scanner::S_minus && mNextOperand) { // unary @@ -504,7 +532,7 @@ namespace Compiler mTokenLoc = loc; return true; } - + if (code==Scanner::S_open) { if (mNextOperand) @@ -520,7 +548,7 @@ namespace Compiler return false; } } - + if (code==Scanner::S_close && !mNextOperand) { if (isOpen()) @@ -528,17 +556,17 @@ namespace Compiler close(); return true; } - + mTokenLoc = loc; scanner.putbackSpecial (code, loc); return false; } - + if (!mNextOperand) { mTokenLoc = loc; char c = 0; // comparison - + switch (code) { case Scanner::S_plus: pushBinaryOperator ('+'); return true; @@ -552,7 +580,7 @@ namespace Compiler case Scanner::S_cmpGT: c = 'g'; break; case Scanner::S_cmpGE: c = 'G'; break; } - + if (c) { if (mArgument && !isOpen()) @@ -562,15 +590,15 @@ namespace Compiler scanner.putbackSpecial (code, loc); return false; } - + pushBinaryOperator (c); return true; } } - + return Parser::parseSpecial (code, loc, scanner); } - + void ExprParser::reset() { mOperands.clear(); @@ -580,8 +608,9 @@ namespace Compiler mFirst = true; mExplicit.clear(); mRefOp = false; + Parser::reset(); } - + char ExprParser::append (std::vector& code) { if (mOperands.empty() && mOperators.empty()) @@ -589,7 +618,7 @@ namespace Compiler getErrorHandler().error ("missing expression", mTokenLoc); return 'l'; } - + if (mNextOperand || mOperands.empty()) { getErrorHandler().error ("syntax error in expression", mTokenLoc); @@ -603,62 +632,90 @@ namespace Compiler assert (mOperands.size()==1); return mOperands[0]; - } - - void ExprParser::parseArguments (const std::string& arguments, Scanner& scanner, + } + + int ExprParser::parseArguments (const std::string& arguments, Scanner& scanner, std::vector& code, bool invert) { + bool optional = false; + bool optionalCount = 0; + ExprParser parser (getErrorHandler(), getContext(), mLocals, mLiterals, true); StringParser stringParser (getErrorHandler(), getContext(), mLiterals); - + std::stack > stack; - + for (std::string::const_iterator iter (arguments.begin()); iter!=arguments.end(); ++iter) { - if (*iter=='S' || *iter=='c') + if (*iter=='/') + { + optional = true; + } + else if (*iter=='S' || *iter=='c') { stringParser.reset(); + + if (optional) + stringParser.setOptional (true); + if (*iter=='c') stringParser.smashCase(); - scanner.scan (stringParser); - + scanner.scan (stringParser); + + if (optional && stringParser.isEmpty()) + break; + if (invert) { std::vector tmp; stringParser.append (tmp); - + stack.push (tmp); } else stringParser.append (code); + + if (optional) + ++optionalCount; } else { - parser.reset(); + parser.reset(); + + if (optional) + parser.setOptional (true); + scanner.scan (parser); + if (optional && parser.isEmpty()) + break; + std::vector tmp; char type = parser.append (tmp); if (type!=*iter) Generator::convert (tmp, type, *iter); - + if (invert) stack.push (tmp); else std::copy (tmp.begin(), tmp.end(), std::back_inserter (code)); + + if (optional) + ++optionalCount; } } - + while (!stack.empty()) { std::vector& tmp = stack.top(); - + std::copy (tmp.begin(), tmp.end(), std::back_inserter (code)); - + stack.pop(); } - } -} + return optionalCount; + } +} diff --git a/components/compiler/exprparser.hpp b/components/compiler/exprparser.hpp index 0dd8c871a..87945c628 100644 --- a/components/compiler/exprparser.hpp +++ b/components/compiler/exprparser.hpp @@ -15,7 +15,7 @@ namespace Compiler class ExprParser : public Parser { - Locals& mLocals; + Locals& mLocals; Literals& mLiterals; std::vector mOperands; std::vector mOperators; @@ -26,35 +26,35 @@ namespace Compiler bool mArgument; std::string mExplicit; bool mRefOp; - + int getPriority (char op) const; - - char getOperandType (int Index = 0) const; + + char getOperandType (int Index = 0) const; char getOperator() const; - + bool isOpen() const; - + void popOperator(); - + void popOperand(); - + void replaceBinaryOperands(); - + void pop(); - + void pushIntegerLiteral (int value); - + void pushFloatLiteral (float value); - + void pushBinaryOperator (char c); - + void close(); - - void parseArguments (const std::string& arguments, Scanner& scanner); - + + int parseArguments (const std::string& arguments, Scanner& scanner); + public: - + ExprParser (ErrorHandler& errorHandler, Context& context, Locals& locals, Literals& literals, bool argument = false); ///< constructor @@ -84,20 +84,22 @@ namespace Compiler virtual bool parseSpecial (int code, const TokenLoc& loc, Scanner& scanner); ///< Handle a special character token. /// \return fetch another token? - + void reset(); ///< Reset parser to clean state. - + char append (std::vector& code); ///< Generate code for parsed expression. /// \return Type ('l': integer, 'f': float) - - void parseArguments (const std::string& arguments, Scanner& scanner, + + int parseArguments (const std::string& arguments, Scanner& scanner, std::vector& code, bool invert = false); ///< Parse sequence of arguments specified by \a arguments. /// \param arguments Each character represents one arguments ('l': integer, - /// 'f': float, 'S': string, 'c': string (case smashed)) + /// 'f': float, 'S': string, 'c': string (case smashed), '/': following arguments are + /// optional) /// \param invert Store arguments in reverted order. + /// \return number of optional arguments }; } diff --git a/components/compiler/fileparser.cpp b/components/compiler/fileparser.cpp index 6e26f48d6..9b184f1ff 100644 --- a/components/compiler/fileparser.cpp +++ b/components/compiler/fileparser.cpp @@ -8,7 +8,7 @@ namespace Compiler { FileParser::FileParser (ErrorHandler& errorHandler, Context& context) - : Parser (errorHandler, context), + : Parser (errorHandler, context), mScriptParser (errorHandler, context, mLocals, true), mState (BeginState) {} @@ -17,12 +17,12 @@ namespace Compiler { return mName; } - + void FileParser::getCode (std::vector& code) const { mScriptParser.getCode (code); } - + const Locals& FileParser::getLocals() const { return mLocals; @@ -37,17 +37,17 @@ namespace Compiler mState = BeginCompleteState; return true; } - + if (mState==EndNameState) { // optional repeated name after end statement if (mName!=name) reportWarning ("Names for script " + mName + " do not match", loc); - + mState = EndCompleteState; return true; } - + return Parser::parseName (name, loc, scanner); } @@ -58,7 +58,7 @@ namespace Compiler mState = NameState; return true; } - + if (mState==NameState) { // keywords can be used as script names too. Thank you Morrowind for another @@ -67,7 +67,7 @@ namespace Compiler mState = BeginCompleteState; return true; } - + return Parser::parseKeyword (keyword, loc, scanner); } @@ -80,25 +80,25 @@ namespace Compiler // ignore empty lines return true; } - + if (mState==BeginCompleteState) { // parse the script body mScriptParser.reset(); - + scanner.scan (mScriptParser); - + mState = EndNameState; return true; } - + if (mState==EndCompleteState || mState==EndNameState) { // we are done here -> ignore the rest of the script return false; } } - + return Parser::parseSpecial (code, loc, scanner); } @@ -107,12 +107,12 @@ namespace Compiler if (mState!=EndNameState && mState!=EndCompleteState) Parser::parseEOF (scanner); } - + void FileParser::reset() { mState = BeginState; mName.clear(); mScriptParser.reset(); + Parser::reset(); } } - diff --git a/components/compiler/parser.cpp b/components/compiler/parser.cpp index ff5bf33ee..73cadfeba 100644 --- a/components/compiler/parser.cpp +++ b/components/compiler/parser.cpp @@ -57,15 +57,15 @@ namespace Compiler std::string Parser::toLower (const std::string& name) { std::string lowerCase; - + std::transform (name.begin(), name.end(), std::back_inserter (lowerCase), (int(*)(int)) std::tolower); - + return lowerCase; } Parser::Parser (ErrorHandler& errorHandler, Context& context) - : mErrorHandler (errorHandler), mContext (context) + : mErrorHandler (errorHandler), mContext (context), mOptional (false), mEmpty (true) {} // destructor @@ -79,7 +79,9 @@ namespace Compiler bool Parser::parseInt (int value, const TokenLoc& loc, Scanner& scanner) { - reportSeriousError ("Unexpected numeric value", loc); + if (!(mOptional && mEmpty)) + reportSeriousError ("Unexpected numeric value", loc); + return false; } @@ -90,7 +92,9 @@ namespace Compiler bool Parser::parseFloat (float value, const TokenLoc& loc, Scanner& scanner) { - reportSeriousError ("Unexpected floating point value", loc); + if (!(mOptional && mEmpty)) + reportSeriousError ("Unexpected floating point value", loc); + return false; } @@ -102,7 +106,9 @@ namespace Compiler bool Parser::parseName (const std::string& name, const TokenLoc& loc, Scanner& scanner) { - reportSeriousError ("Unexpected name", loc); + if (!(mOptional && mEmpty)) + reportSeriousError ("Unexpected name", loc); + return false; } @@ -113,7 +119,9 @@ namespace Compiler bool Parser::parseKeyword (int keyword, const TokenLoc& loc, Scanner& scanner) { - reportSeriousError ("Unexpected keyword", loc); + if (!(mOptional && mEmpty)) + reportSeriousError ("Unexpected keyword", loc); + return false; } @@ -124,7 +132,9 @@ namespace Compiler bool Parser::parseSpecial (int code, const TokenLoc& loc, Scanner& scanner) { - reportSeriousError ("Unexpected special token", loc); + if (!(mOptional && mEmpty)) + reportSeriousError ("Unexpected special token", loc); + return false; } @@ -136,5 +146,25 @@ namespace Compiler { reportEOF(); } -} + void Parser::reset() + { + mOptional = false; + mEmpty = true; + } + + void Parser::setOptional (bool optional) + { + mOptional = optional; + } + + void Parser::start() + { + mEmpty = false; + } + + bool Parser::isEmpty() const + { + return mEmpty; + } +} diff --git a/components/compiler/parser.hpp b/components/compiler/parser.hpp index a55f5a024..221e7c2c9 100644 --- a/components/compiler/parser.hpp +++ b/components/compiler/parser.hpp @@ -18,6 +18,8 @@ namespace Compiler { ErrorHandler& mErrorHandler; Context& mContext; + bool mOptional; + bool mEmpty; protected: @@ -47,7 +49,7 @@ namespace Compiler ///< constructor virtual ~Parser(); - ///< destructor + ///< destructor virtual bool parseInt (int value, const TokenLoc& loc, Scanner& scanner); ///< Handle an int token. @@ -84,6 +86,19 @@ namespace Compiler ///< Handle EOF token. /// /// - Default-implementation: Report an error. + + virtual void reset(); + ///< Reset parser to clean state. + + void setOptional (bool optional); + ///< Optional mode: If nothign has been parsed yet and an unexpected token is delivered, stop + /// parsing without raising an exception (after a reset the parser is in non-optional mode). + + void start(); + ///< Mark parser as non-empty (at least one token has been parser). + + bool isEmpty() const; + ///< Has anything been parsed? }; } diff --git a/components/compiler/stringparser.cpp b/components/compiler/stringparser.cpp index 633b7eab4..396a88c78 100644 --- a/components/compiler/stringparser.cpp +++ b/components/compiler/stringparser.cpp @@ -12,7 +12,7 @@ namespace Compiler StringParser::StringParser (ErrorHandler& errorHandler, Context& context, Literals& literals) : Parser (errorHandler, context), mLiterals (literals), mState (StartState), mSmashCase (false) { - + } bool StringParser::parseName (const std::string& name, const TokenLoc& loc, @@ -20,14 +20,15 @@ namespace Compiler { if (mState==StartState || mState==CommaState) { + start(); if (mSmashCase) - Generator::pushString (mCode, mLiterals, toLower (name)); - else + Generator::pushString (mCode, mLiterals, toLower (name)); + else Generator::pushString (mCode, mLiterals, name); - + return false; } - + return Parser::parseName (name, loc, scanner); } @@ -38,10 +39,10 @@ namespace Compiler mState = CommaState; return true; } - + return Parser::parseSpecial (code, loc, scanner); } - + void StringParser::append (std::vector& code) { std::copy (mCode.begin(), mCode.end(), std::back_inserter (code)); @@ -52,11 +53,11 @@ namespace Compiler mState = StartState; mCode.clear(); mSmashCase = false; + Parser::reset(); } - + void StringParser::smashCase() { mSmashCase = true; } } - From 08d2b804344e3c41e2daf08588ab7dd76010adfb Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Sun, 22 Aug 2010 12:56:35 +0200 Subject: [PATCH 06/15] message box fix --- apps/openmw/mwgui/window_manager.cpp | 7 ++++++- components/interpreter/miscopcodes.hpp | 10 +++++----- 2 files changed, 11 insertions(+), 6 deletions(-) diff --git a/apps/openmw/mwgui/window_manager.cpp b/apps/openmw/mwgui/window_manager.cpp index ed4085ea8..1752743f7 100644 --- a/apps/openmw/mwgui/window_manager.cpp +++ b/apps/openmw/mwgui/window_manager.cpp @@ -5,6 +5,7 @@ #include #include +#include using namespace MWGui; @@ -102,5 +103,9 @@ void WindowManager::messageBox (const std::string& message, const std::vector (std::cout, ", ")); + std::cout << std::endl; + } } diff --git a/components/interpreter/miscopcodes.hpp b/components/interpreter/miscopcodes.hpp index 7e7dcd18a..fbee0aa26 100644 --- a/components/interpreter/miscopcodes.hpp +++ b/components/interpreter/miscopcodes.hpp @@ -19,6 +19,11 @@ namespace Interpreter virtual void execute (Runtime& runtime, unsigned int arg0) { + // message + int index = runtime[0].mInteger; + runtime.pop(); + std::string message = runtime.getStringLiteral (index); + // buttons std::vector buttons; @@ -31,11 +36,6 @@ namespace Interpreter std::reverse (buttons.begin(), buttons.end()); - // message - int index = runtime[0].mInteger; - runtime.pop(); - std::string message = runtime.getStringLiteral (index); - // additional parameters std::string formattedMessage; From b3cc3073a35ca4850a225abc41cce6a2d89ad533 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Sun, 22 Aug 2010 13:15:56 +0200 Subject: [PATCH 07/15] changed encoding of segment 3 opcodes (increasing the number of opcodes, while reducing the width of the argument) --- apps/openmw/mwscript/docs/vmformat.txt | 2 +- components/compiler/generator.cpp | 5 ++ components/compiler/generator.hpp | 61 +++++++------ components/interpreter/docs/vmformat.txt | 6 +- components/interpreter/interpreter.cpp | 108 +++++++++++------------ 5 files changed, 93 insertions(+), 89 deletions(-) diff --git a/apps/openmw/mwscript/docs/vmformat.txt b/apps/openmw/mwscript/docs/vmformat.txt index 70e5fe8c2..9813e2e2f 100644 --- a/apps/openmw/mwscript/docs/vmformat.txt +++ b/apps/openmw/mwscript/docs/vmformat.txt @@ -14,7 +14,7 @@ opcodes 0x200-0x3ff unused Segment 3: (not implemented yet) -opcodes 0x200-0x3ff unused +opcodes 0x20000-0x3ffff unused Segment 4: (not implemented yet) diff --git a/components/compiler/generator.cpp b/components/compiler/generator.cpp index c5262616b..3d3b21d65 100644 --- a/components/compiler/generator.cpp +++ b/components/compiler/generator.cpp @@ -505,6 +505,11 @@ namespace Compiler void message (CodeContainer& code, Literals& literals, const std::string& message, int buttons) { + assert (buttons>=0); + + if (buttons>=256) + throw std::runtime_error ("A message box can't have more than 255 buttons"); + int index = literals.addString (message); opPushInt (code, index); diff --git a/components/compiler/generator.hpp b/components/compiler/generator.hpp index a7559f7e9..5671949f2 100644 --- a/components/compiler/generator.hpp +++ b/components/compiler/generator.hpp @@ -36,8 +36,8 @@ namespace Compiler inline Interpreter::Type_Code segment3 (unsigned int c, unsigned int arg0) { - assert (c<1024); - return 0xc0000000 | (c<<20) | (arg0 & 0xffff); + assert (c<262144); + return 0xc0000000 | (c<<8) | (arg0 & 0xff); } inline Interpreter::Type_Code segment4 (unsigned int c, unsigned int arg0, @@ -52,72 +52,71 @@ namespace Compiler assert (c<67108864); return 0xc8000000 | c; } - + void pushInt (CodeContainer& code, Literals& literals, int value); void pushFloat (CodeContainer& code, Literals& literals, float value); - + void pushString (CodeContainer& code, Literals& literals, const std::string& value); void assignToLocal (CodeContainer& code, char localType, int localIndex, const CodeContainer& value, char valueType); - + void negate (CodeContainer& code, char valueType); - + void add (CodeContainer& code, char valueType1, char valueType2); - void sub (CodeContainer& code, char valueType1, char valueType2); - - void mul (CodeContainer& code, char valueType1, char valueType2); - - void div (CodeContainer& code, char valueType1, char valueType2); - + void sub (CodeContainer& code, char valueType1, char valueType2); + + void mul (CodeContainer& code, char valueType1, char valueType2); + + void div (CodeContainer& code, char valueType1, char valueType2); + void convert (CodeContainer& code, char fromType, char toType); - + void squareRoot (CodeContainer& code); - void exit (CodeContainer& code); - + void exit (CodeContainer& code); + void message (CodeContainer& code, Literals& literals, const std::string& message, int buttons); - + void fetchLocal (CodeContainer& code, char localType, int localIndex); void jump (CodeContainer& code, int offset); - + void jumpOnZero (CodeContainer& code, int offset); - + void jumpOnNonZero (CodeContainer& code, int offset); void compare (CodeContainer& code, char op, char valueType1, char valueType2); - + void menuMode (CodeContainer& code); - + void assignToGlobal (CodeContainer& code, Literals& literals, char localType, - const std::string& name, const CodeContainer& value, char valueType); - + const std::string& name, const CodeContainer& value, char valueType); + void fetchGlobal (CodeContainer& code, Literals& literals, char localType, - const std::string& name); - + const std::string& name); + void random (CodeContainer& code); - + void scriptRunning (CodeContainer& code); - + void startScript (CodeContainer& code); void stopScript (CodeContainer& code); - + void getDistance (CodeContainer& code, Literals& literals, const std::string id); void getSecondsPassed (CodeContainer& code); - + void getDisabled (CodeContainer& code, Literals& literals, const std::string id); - + void enable (CodeContainer& code, Literals& literals, const std::string id); - + void disable (CodeContainer& code, Literals& literals, const std::string id); } } #endif - diff --git a/components/interpreter/docs/vmformat.txt b/components/interpreter/docs/vmformat.txt index 291d1c490..6619fc30a 100644 --- a/components/interpreter/docs/vmformat.txt +++ b/components/interpreter/docs/vmformat.txt @@ -19,7 +19,7 @@ Code bit-patterns: 00ccccccAAAAAAAAAAAAAAAAAAAAAAAA segment 0: 64 opcodes, 1 24-bit argument 01ccccccAAAAAAAAAAAABBBBBBBBBBBB segment 1: 64 opcodes, 2 12-bit arguments 10ccccccccccAAAAAAAAAAAAAAAAAAAA segment 2: 1024 opcodes, 1 20-bit argument -110000ccccccccccAAAAAAAAAAAAAAAA segment 3: 1024 opcodes, 1 16-bit argument +110000ccccccccccccccccccAAAAAAAA segment 3: 262144 opcodes, 1 8-bit argument 110001ccccccccccAAAAAAAABBBBBBBB segment 4: 1024 opcodes, 2 8-bit arguments 110010cccccccccccccccccccccccccc segment 5: 67108864 opcodes, no arguments other bit-patterns reserved @@ -50,8 +50,8 @@ op 0: show message box with message string literal index in stack[0]; additional arguments (if any) in stack[arg0+n]..stack[arg0+1]; n is determined according to the message string all arguments are removed from stack -opcodes 1-511 unused -opcodes 512-1023 reserved for extensions +opcodes 1-131071 unused +opcodes 131072-262143 reserved for extensions Segment 4: opcodes 0-511 unused diff --git a/components/interpreter/interpreter.cpp b/components/interpreter/interpreter.cpp index f3ebd97a7..44f626aad 100644 --- a/components/interpreter/interpreter.cpp +++ b/components/interpreter/interpreter.cpp @@ -13,131 +13,131 @@ namespace Interpreter void Interpreter::execute (Type_Code code) { unsigned int segSpec = code>>30; - + switch (segSpec) { case 0: { int opcode = code>>24; unsigned int arg0 = code & 0xffffff; - + std::map::iterator iter = mSegment0.find (opcode); - + if (iter==mSegment0.end()) abortUnknownCode (0, opcode); - + iter->second->execute (mRuntime, arg0); - + return; } - + case 1: { int opcode = (code>>24) & 0x3f; unsigned int arg0 = (code>>16) & 0xfff; unsigned int arg1 = code & 0xfff; - + std::map::iterator iter = mSegment1.find (opcode); - + if (iter==mSegment1.end()) abortUnknownCode (1, opcode); - + iter->second->execute (mRuntime, arg0, arg1); - + return; } - + case 2: { int opcode = (code>>20) & 0x3ff; unsigned int arg0 = code & 0xfffff; - + std::map::iterator iter = mSegment2.find (opcode); - + if (iter==mSegment2.end()) abortUnknownCode (2, opcode); - + iter->second->execute (mRuntime, arg0); - + return; - } + } } - + segSpec = code>>26; - + switch (segSpec) - { + { case 0x30: { - int opcode = (code>>16) & 0x3ff; - unsigned int arg0 = code & 0xffff; - + int opcode = (code>>8) & 0x3ffff; + unsigned int arg0 = code & 0xff; + std::map::iterator iter = mSegment3.find (opcode); - + if (iter==mSegment3.end()) abortUnknownCode (3, opcode); - + iter->second->execute (mRuntime, arg0); - + return; - } - + } + case 0x31: { int opcode = (code>>16) & 0x3ff; unsigned int arg0 = (code>>8) & 0xff; unsigned int arg1 = code & 0xff; - + std::map::iterator iter = mSegment4.find (opcode); - + if (iter==mSegment4.end()) abortUnknownCode (4, opcode); - + iter->second->execute (mRuntime, arg0, arg1); - + return; - } - + } + case 0x32: { int opcode = code & 0x3ffffff; - + std::map::iterator iter = mSegment5.find (opcode); - + if (iter==mSegment5.end()) abortUnknownCode (5, opcode); - + iter->second->execute (mRuntime); - + return; } } - + abortUnknownSegment (code); } void Interpreter::abortUnknownCode (int segment, int opcode) { std::ostringstream error; - + error << "unknown opcode " << opcode << " in segment " << segment; - + throw std::runtime_error (error.str()); } - + void Interpreter::abortUnknownSegment (Type_Code code) { std::ostringstream error; - + error << "opcode outside of the allocated segment range: " << code; - + throw std::runtime_error (error.str()); } - + Interpreter::Interpreter (Context& context) : mRuntime (context) {} - + Interpreter::~Interpreter() { for (std::map::iterator iter (mSegment0.begin()); @@ -159,12 +159,12 @@ namespace Interpreter for (std::map::iterator iter (mSegment4.begin()); iter!=mSegment4.end(); ++iter) delete iter->second; - + for (std::map::iterator iter (mSegment5.begin()); iter!=mSegment5.end(); ++iter) - delete iter->second; + delete iter->second; } - + void Interpreter::installSegment0 (int code, Opcode1 *opcode) { mSegment0.insert (std::make_pair (code, opcode)); @@ -194,24 +194,24 @@ namespace Interpreter { mSegment5.insert (std::make_pair (code, opcode)); } - + void Interpreter::run (const Type_Code *code, int codeSize) { assert (codeSize>=4); - + mRuntime.configure (code, codeSize); - + int opcodes = static_cast (code[0]); - + const Type_Code *codeBlock = code + 4; - + while (mRuntime.getPC()>=0 && mRuntime.getPC() Date: Sun, 22 Aug 2010 14:00:30 +0200 Subject: [PATCH 08/15] extended scripting extensions to code segment 3 (instructions and functions with optional arguments) --- components/compiler/exprparser.cpp | 9 +- components/compiler/extensions.cpp | 184 ++++++++++++++++++++--------- components/compiler/extensions.hpp | 43 +++---- components/compiler/lineparser.cpp | 4 +- 4 files changed, 160 insertions(+), 80 deletions(-) diff --git a/components/compiler/exprparser.cpp b/components/compiler/exprparser.cpp index 484aea878..06c3207e2 100644 --- a/components/compiler/exprparser.cpp +++ b/components/compiler/exprparser.cpp @@ -346,9 +346,10 @@ namespace Compiler start(); mTokenLoc = loc; - parseArguments (argumentType, scanner); + int optionals = parseArguments (argumentType, scanner); - extensions->generateFunctionCode (keyword, mCode, mLiterals, mExplicit); + extensions->generateFunctionCode (keyword, mCode, mLiterals, mExplicit, + optionals); mOperands.push_back (returnType); mExplicit.clear(); mRefOp = false; @@ -465,9 +466,9 @@ namespace Compiler if (extensions->isFunction (keyword, returnType, argumentType, false)) { mTokenLoc = loc; - parseArguments (argumentType, scanner); + int optionals = parseArguments (argumentType, scanner); - extensions->generateFunctionCode (keyword, mCode, mLiterals, ""); + extensions->generateFunctionCode (keyword, mCode, mLiterals, "", optionals); mOperands.push_back (returnType); mNextOperand = false; diff --git a/components/compiler/extensions.cpp b/components/compiler/extensions.cpp index 78ae0fdfd..3b1d180b1 100644 --- a/components/compiler/extensions.cpp +++ b/components/compiler/extensions.cpp @@ -14,119 +14,197 @@ namespace Compiler int Extensions::searchKeyword (const std::string& keyword) const { std::map::const_iterator iter = mKeywords.find (keyword); - + if (iter==mKeywords.end()) return 0; - + return iter->second; } - + bool Extensions::isFunction (int keyword, char& returnType, std::string& argumentType, bool explicitReference) const { std::map::const_iterator iter = mFunctions.find (keyword); - + if (iter==mFunctions.end()) return false; - + if (explicitReference && iter->second.mCodeExplicit==-1) return false; - + returnType = iter->second.mReturn; argumentType = iter->second.mArguments; return true; } - + bool Extensions::isInstruction (int keyword, std::string& argumentType, bool explicitReference) const { std::map::const_iterator iter = mInstructions.find (keyword); - + if (iter==mInstructions.end()) return false; if (explicitReference && iter->second.mCodeExplicit==-1) return false; - + argumentType = iter->second.mArguments; return true; } - + void Extensions::registerFunction (const std::string& keyword, char returnType, - const std::string& argumentType, int segment5code, int segment5codeExplicit) + const std::string& argumentType, int code, int codeExplicit) { - assert (segment5code>=33554432 && segment5code<=67108863); - - int code = mNextKeywordIndex--; - - mKeywords.insert (std::make_pair (keyword, code)); - Function function; + + if (argumentType.find ('/')==std::string::npos) + { + function.mSegment = 5; + assert (code>=33554432 && code<=67108863); + assert (codeExplicit==-1 || (codeExplicit>=33554432 && codeExplicit<=67108863)); + } + else + { + function.mSegment = 3; + assert (code>=0x20000 && code<=0x2ffff); + assert (codeExplicit==-1 || (codeExplicit>=0x20000 && codeExplicit<=0x2ffff)); + } + + int keywordIndex = mNextKeywordIndex--; + + mKeywords.insert (std::make_pair (keyword, keywordIndex)); + function.mReturn = returnType; function.mArguments = argumentType; - function.mCode = segment5code; - function.mCodeExplicit = segment5codeExplicit; - - mFunctions.insert (std::make_pair (code, function)); + function.mCode = code; + function.mCodeExplicit = codeExplicit; + + mFunctions.insert (std::make_pair (keywordIndex, function)); } - + void Extensions::registerInstruction (const std::string& keyword, - const std::string& argumentType, int segment5code, int segment5codeExplicit) + const std::string& argumentType, int code, int codeExplicit) { - assert (segment5code>=33554432 && segment5code<=67108863); - - int code = mNextKeywordIndex--; - - mKeywords.insert (std::make_pair (keyword, code)); - Instruction instruction; + + if (argumentType.find ('/')==std::string::npos) + { + instruction.mSegment = 5; + assert (code>=33554432 && code<=67108863); + assert (codeExplicit==-1 || (codeExplicit>=33554432 && codeExplicit<=67108863)); + } + else + { + instruction.mSegment = 3; + assert (code>=0x20000 && code<=0x2ffff); + assert (codeExplicit==-1 || (codeExplicit>=0x20000 && codeExplicit<=0x2ffff)); + } + + int keywordIndex = mNextKeywordIndex--; + + mKeywords.insert (std::make_pair (keyword, keywordIndex)); + instruction.mArguments = argumentType; - instruction.mCode = segment5code; - instruction.mCodeExplicit = segment5codeExplicit; - - mInstructions.insert (std::make_pair (code, instruction)); + instruction.mCode = code; + instruction.mCodeExplicit = codeExplicit; + + mInstructions.insert (std::make_pair (keywordIndex, instruction)); } - + void Extensions::generateFunctionCode (int keyword, std::vector& code, - Literals& literals, const std::string& id) const + Literals& literals, const std::string& id, int optionalArguments) const { + assert (optionalArguments>=0); + std::map::const_iterator iter = mFunctions.find (keyword); - + if (iter==mFunctions.end()) throw std::logic_error ("unknown custom function keyword"); - + + if (optionalArguments && iter->second.mSegment!=3) + throw std::logic_error ("functions with optional arguments must be placed into segment 3"); + if (!id.empty()) { if (iter->second.mCodeExplicit==-1) throw std::logic_error ("explicit references not supported"); - + int index = literals.addString (id); - Generator::pushInt (code, literals, index); + Generator::pushInt (code, literals, index); + } + + switch (iter->second.mSegment) + { + case 3: + + if (optionalArguments>=256) + throw std::logic_error ("number of optional arguments is too large for segment 3"); + + code.push_back (Generator::segment3 ( + id.empty() ? iter->second.mCode : iter->second.mCodeExplicit, + optionalArguments)); + + break; + + case 5: + + code.push_back (Generator::segment5 ( + id.empty() ? iter->second.mCode : iter->second.mCodeExplicit)); + + break; + + default: + + throw std::logic_error ("unsupported code segment"); } - - code.push_back (Generator::segment5 ( - id.empty() ? iter->second.mCode : iter->second.mCodeExplicit)); } - + void Extensions::generateInstructionCode (int keyword, - std::vector& code, Literals& literals, const std::string& id) - const + std::vector& code, Literals& literals, const std::string& id, + int optionalArguments) const { + assert (optionalArguments>=0); + std::map::const_iterator iter = mInstructions.find (keyword); - + if (iter==mInstructions.end()) throw std::logic_error ("unknown custom instruction keyword"); - + + if (optionalArguments && iter->second.mSegment!=3) + throw std::logic_error ("instructions with optional arguments must be placed into segment 3"); + if (!id.empty()) { if (iter->second.mCodeExplicit==-1) throw std::logic_error ("explicit references not supported"); - + int index = literals.addString (id); - Generator::pushInt (code, literals, index); + Generator::pushInt (code, literals, index); } - - code.push_back (Generator::segment5 ( - id.empty() ? iter->second.mCode : iter->second.mCodeExplicit)); - } + + switch (iter->second.mSegment) + { + case 3: + + if (optionalArguments>=256) + throw std::logic_error ("number of optional arguments is too large for segment 3"); + + code.push_back (Generator::segment3 ( + id.empty() ? iter->second.mCode : iter->second.mCodeExplicit, + optionalArguments)); + + break; + + case 5: + + code.push_back (Generator::segment5 ( + id.empty() ? iter->second.mCode : iter->second.mCodeExplicit)); + + break; + + default: + + throw std::logic_error ("unsupported code segment"); + } + } } diff --git a/components/compiler/extensions.hpp b/components/compiler/extensions.hpp index 85a761951..960cac157 100644 --- a/components/compiler/extensions.hpp +++ b/components/compiler/extensions.hpp @@ -10,9 +10,9 @@ namespace Compiler { class Literals; - + /// \brief Collection of compiler extensions - + class Extensions { struct Function @@ -21,29 +21,31 @@ namespace Compiler std::string mArguments; int mCode; int mCodeExplicit; + int mSegment; }; - + struct Instruction { std::string mArguments; - int mCode; + int mCode; int mCodeExplicit; + int mSegment; }; - + int mNextKeywordIndex; std::map mKeywords; std::map mFunctions; std::map mInstructions; - + public: - + Extensions(); - + int searchKeyword (const std::string& keyword) const; ///< Return extension keyword code, that is assigned to the string \a keyword. /// - if no match is found 0 is returned. /// - keyword must be all lower case. - + bool isFunction (int keyword, char& returnType, std::string& argumentType, bool explicitReference) const; ///< Is this keyword registered with a function? If yes, return return and argument @@ -52,32 +54,31 @@ namespace Compiler bool isInstruction (int keyword, std::string& argumentType, bool explicitReference) const; ///< Is this keyword registered with a function? If yes, return argument types. - + void registerFunction (const std::string& keyword, char returnType, - const std::string& argumentType, int segment5code, int segment5codeExplicit = -1); + const std::string& argumentType, int code, int codeExplicit = -1); ///< Register a custom function /// - keyword must be all lower case. /// - keyword must be unique /// - if explicit references are not supported, segment5codeExplicit must be set to -1 - /// \note Currently only segment 5 opcodes are supported. - + /// \note Currently only segment 3 and segment 5 opcodes are supported. + void registerInstruction (const std::string& keyword, - const std::string& argumentType, int segment5code, int segment5codeExplicit = -1); + const std::string& argumentType, int code, int codeExplicit = -1); ///< Register a custom instruction /// - keyword must be all lower case. /// - keyword must be unique /// - if explicit references are not supported, segment5codeExplicit must be set to -1 - /// \note Currently only segment 5 opcodes are supported. - + /// \note Currently only segment 3 and segment 5 opcodes are supported. + void generateFunctionCode (int keyword, std::vector& code, - Literals& literals, const std::string& id) const; + Literals& literals, const std::string& id, int optionalArguments) const; ///< Append code for function to \a code. - + void generateInstructionCode (int keyword, std::vector& code, - Literals& literals, const std::string& id) const; - ///< Append code for function to \a code. + Literals& literals, const std::string& id, int optionalArguments) const; + ///< Append code for function to \a code. }; } #endif - diff --git a/components/compiler/lineparser.cpp b/components/compiler/lineparser.cpp index b4c79c972..3f80d671e 100644 --- a/components/compiler/lineparser.cpp +++ b/components/compiler/lineparser.cpp @@ -242,9 +242,9 @@ namespace Compiler if (extensions->isInstruction (keyword, argumentType, mState==ExplicitState)) { - mExprParser.parseArguments (argumentType, scanner, mCode, true); + int optionals = mExprParser.parseArguments (argumentType, scanner, mCode, true); - extensions->generateInstructionCode (keyword, mCode, mLiterals, mExplicit); + extensions->generateInstructionCode (keyword, mCode, mLiterals, mExplicit, optionals); mState = EndState; return true; } From 14cf007a3f8a494f10a6f0edf9b5d5b13fb96656 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Sun, 22 Aug 2010 14:49:25 +0200 Subject: [PATCH 09/15] added first batch of AI-related instructions and functions (they don't do anything at this point) --- apps/openmw/CMakeLists.txt | 2 + apps/openmw/mwscript/aiextensions.cpp | 214 +++++++++++++++++++++++++ apps/openmw/mwscript/aiextensions.hpp | 25 +++ apps/openmw/mwscript/docs/vmformat.txt | 11 +- apps/openmw/mwscript/extensions.cpp | 3 + 5 files changed, 252 insertions(+), 3 deletions(-) create mode 100644 apps/openmw/mwscript/aiextensions.cpp create mode 100644 apps/openmw/mwscript/aiextensions.hpp diff --git a/apps/openmw/CMakeLists.txt b/apps/openmw/CMakeLists.txt index b5948aaea..f0aafbbbc 100644 --- a/apps/openmw/CMakeLists.txt +++ b/apps/openmw/CMakeLists.txt @@ -60,6 +60,7 @@ set(GAMESCRIPT mwscript/skyextensions.cpp mwscript/statsextensions.cpp mwscript/containerextensions.cpp + mwscript/aiextensions.cpp mwscript/extensions.cpp mwscript/globalscripts.cpp ) @@ -75,6 +76,7 @@ set(GAMESCRIPT_HEADER mwscript/skyextensions.hpp mwscript/statsextensions.hpp mwscript/containerextensions.hpp + mwscript/aiextensions.hpp mwscript/extensions.hpp mwscript/globalscripts.hpp ) diff --git a/apps/openmw/mwscript/aiextensions.cpp b/apps/openmw/mwscript/aiextensions.cpp new file mode 100644 index 000000000..e1fdc1976 --- /dev/null +++ b/apps/openmw/mwscript/aiextensions.cpp @@ -0,0 +1,214 @@ + +#include "aiextensions.hpp" + +#include + +#include +#include +#include + +#include "interpretercontext.hpp" + +#include +namespace MWScript +{ + namespace Ai + { + class OpAiTravel : public Interpreter::Opcode1 + { + public: + + virtual void execute (Interpreter::Runtime& runtime, unsigned int arg0) + { + MWScript::InterpreterContext& context + = static_cast (runtime.getContext()); + + MWWorld::Ptr ptr = context.getReference(); + + Interpreter::Type_Float x = runtime[0].mInteger; + runtime.pop(); + + Interpreter::Type_Float y = runtime[0].mInteger; + runtime.pop(); + + Interpreter::Type_Float z = runtime[0].mInteger; + runtime.pop(); + + // discard additional arguments (reset), because we have no idea what they mean. + for (unsigned int i=0; i (runtime.getContext()); + + std::string id = runtime.getStringLiteral (runtime[0].mInteger); + runtime.pop(); + + MWWorld::Ptr ptr = context.getWorld().getPtr (id, false); + + Interpreter::Type_Float x = runtime[0].mInteger; + runtime.pop(); + + Interpreter::Type_Float y = runtime[0].mInteger; + runtime.pop(); + + Interpreter::Type_Float z = runtime[0].mInteger; + runtime.pop(); + + // discard additional arguments (reset), because we have no idea what they mean. + for (unsigned int i=0; i (runtime.getContext()); + + std::string id = runtime.getStringLiteral (runtime[0].mInteger); + runtime.pop(); + + MWWorld::Ptr ptr = context.getReference(); + + std::string actor = runtime.getStringLiteral (runtime[0].mInteger); + runtime.pop(); + + Interpreter::Type_Float duration = runtime[0].mInteger; + runtime.pop(); + + Interpreter::Type_Float x = runtime[0].mInteger; + runtime.pop(); + + Interpreter::Type_Float y = runtime[0].mInteger; + runtime.pop(); + + Interpreter::Type_Float z = runtime[0].mInteger; + runtime.pop(); + + // discard additional arguments (reset), because we have no idea what they mean. + for (unsigned int i=0; i (runtime.getContext()); + + std::string id = runtime.getStringLiteral (runtime[0].mInteger); + runtime.pop(); + + MWWorld::Ptr ptr = context.getWorld().getPtr (id, false); + + std::string actor = runtime.getStringLiteral (runtime[0].mInteger); + runtime.pop(); + + Interpreter::Type_Float duration = runtime[0].mInteger; + runtime.pop(); + + Interpreter::Type_Float x = runtime[0].mInteger; + runtime.pop(); + + Interpreter::Type_Float y = runtime[0].mInteger; + runtime.pop(); + + Interpreter::Type_Float z = runtime[0].mInteger; + runtime.pop(); + + // discard additional arguments (reset), because we have no idea what they mean. + for (unsigned int i=0; i (runtime.getContext()); + + MWWorld::Ptr ptr = context.getReference(); + + Interpreter::Type_Integer value = 1; + + runtime.push (value); + } + }; + + class OpGetAiPackageDoneExplicit : public Interpreter::Opcode0 + { + public: + + virtual void execute (Interpreter::Runtime& runtime) + { + MWScript::InterpreterContext& context + = static_cast (runtime.getContext()); + + std::string id = runtime.getStringLiteral (runtime[0].mInteger); + runtime.pop(); + + MWWorld::Ptr ptr = context.getWorld().getPtr (id, false); + + Interpreter::Type_Integer value = 1; + + runtime.push (value); + } + }; + + + const int opcodeAiTravel = 0x20000; + const int opcodeAiTravelExplicit = 0x20001; + const int opcodeAiEscort = 0x20002; + const int opcodeAiEscortExplicit = 0x20003; + const int opcodeGetAiPackageDone = 0x200007c; + const int opcodeGetAiPackageDoneExplicit = 0x200007d; + + void registerExtensions (Compiler::Extensions& extensions) + { + extensions.registerInstruction ("aitravel", "cllll/l", opcodeAiTravel, + opcodeAiTravelExplicit); + extensions.registerInstruction ("aiescort", "cllll/l", opcodeAiEscort, + opcodeAiEscortExplicit); + + extensions.registerFunction ("getaipackagedone", 'l', "", opcodeGetAiPackageDone, + opcodeGetAiPackageDoneExplicit); + } + + void installOpcodes (Interpreter::Interpreter& interpreter) + { + interpreter.installSegment3 (opcodeAiTravel, new OpAiTravel); + interpreter.installSegment3 (opcodeAiTravelExplicit, new OpAiTravelExplicit); + interpreter.installSegment3 (opcodeAiEscort, new OpAiEscort); + interpreter.installSegment3 (opcodeAiEscortExplicit, new OpAiEscortExplicit); + interpreter.installSegment5 (opcodeGetAiPackageDone, new OpGetAiPackageDone); + interpreter.installSegment5 (opcodeGetAiPackageDoneExplicit, new OpGetAiPackageDoneExplicit); + } + } +} diff --git a/apps/openmw/mwscript/aiextensions.hpp b/apps/openmw/mwscript/aiextensions.hpp new file mode 100644 index 000000000..547341476 --- /dev/null +++ b/apps/openmw/mwscript/aiextensions.hpp @@ -0,0 +1,25 @@ +#ifndef GAME_SCRIPT_AIEXTENSIONS_H +#define GAME_SCRIPT_AIEXTENSIONS_H + +namespace Compiler +{ + class Extensions; +} + +namespace Interpreter +{ + class Interpreter; +} + +namespace MWScript +{ + /// \brief AI-related script functionality + namespace Ai + { + void registerExtensions (Compiler::Extensions& extensions); + + void installOpcodes (Interpreter::Interpreter& interpreter); + } +} + +#endif diff --git a/apps/openmw/mwscript/docs/vmformat.txt b/apps/openmw/mwscript/docs/vmformat.txt index 9813e2e2f..88d3f59ac 100644 --- a/apps/openmw/mwscript/docs/vmformat.txt +++ b/apps/openmw/mwscript/docs/vmformat.txt @@ -13,8 +13,11 @@ Segment 2: opcodes 0x200-0x3ff unused Segment 3: -(not implemented yet) -opcodes 0x20000-0x3ffff unused +op 0x20000: AiTravel +op 0x20001: AiTravel, explicit reference +op 0x20002: AiEscort +op 0x20003: AiEscort, explicit reference +opcodes 0x20004-0x3ffff unused Segment 4: (not implemented yet) @@ -83,4 +86,6 @@ op 0x2000078: GetItemCount op 0x2000079: GetItemCount, explicit reference op 0x200007a: RemoveItem op 0x200007b: RemoveItem, explicit reference -opcodes 0x200007c-0x3ffffff unused +op 0x200007c: GetAiPackageDone +op 0x200007d: GetAiPackageDone, explicit reference +opcodes 0x200007e-0x3ffffff unused diff --git a/apps/openmw/mwscript/extensions.cpp b/apps/openmw/mwscript/extensions.cpp index 1b3d3df14..9b1e2dd45 100644 --- a/apps/openmw/mwscript/extensions.cpp +++ b/apps/openmw/mwscript/extensions.cpp @@ -11,6 +11,7 @@ #include "skyextensions.hpp" #include "statsextensions.hpp" #include "containerextensions.hpp" +#include "aiextensions.hpp" namespace MWScript { @@ -23,6 +24,7 @@ namespace MWScript Sky::registerExtensions (extensions); Stats::registerExtensions (extensions); Container::registerExtensions (extensions); + Ai::registerExtensions (extensions); } void installOpcodes (Interpreter::Interpreter& interpreter) @@ -35,5 +37,6 @@ namespace MWScript Sky::installOpcodes (interpreter); Stats::installOpcodes (interpreter); Container::installOpcodes (interpreter); + Ai::installOpcodes (interpreter); } } From 68a788b2c87abe5af73023a7e48ed0fbe1f035f6 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Sun, 22 Aug 2010 15:11:40 +0200 Subject: [PATCH 10/15] added instructions for enabling/disabling player controls (they don't do anything yet) --- apps/openmw/CMakeLists.txt | 2 + apps/openmw/mwscript/controlextensions.cpp | 70 ++++++++++++++++++++++ apps/openmw/mwscript/controlextensions.hpp | 25 ++++++++ apps/openmw/mwscript/docs/vmformat.txt | 4 +- apps/openmw/mwscript/extensions.cpp | 3 + 5 files changed, 103 insertions(+), 1 deletion(-) create mode 100644 apps/openmw/mwscript/controlextensions.cpp create mode 100644 apps/openmw/mwscript/controlextensions.hpp diff --git a/apps/openmw/CMakeLists.txt b/apps/openmw/CMakeLists.txt index f0aafbbbc..6863b2e13 100644 --- a/apps/openmw/CMakeLists.txt +++ b/apps/openmw/CMakeLists.txt @@ -61,6 +61,7 @@ set(GAMESCRIPT mwscript/statsextensions.cpp mwscript/containerextensions.cpp mwscript/aiextensions.cpp + mwscript/controlextensions.cpp mwscript/extensions.cpp mwscript/globalscripts.cpp ) @@ -77,6 +78,7 @@ set(GAMESCRIPT_HEADER mwscript/statsextensions.hpp mwscript/containerextensions.hpp mwscript/aiextensions.hpp + mwscript/controlextensions.hpp mwscript/extensions.hpp mwscript/globalscripts.hpp ) diff --git a/apps/openmw/mwscript/controlextensions.cpp b/apps/openmw/mwscript/controlextensions.cpp new file mode 100644 index 000000000..e38ee7c2d --- /dev/null +++ b/apps/openmw/mwscript/controlextensions.cpp @@ -0,0 +1,70 @@ + +#include "statsextensions.hpp" + +#include + +#include +#include +#include + +#include "interpretercontext.hpp" + +#include + +namespace MWScript +{ + namespace Control + { + class OpSetControl : public Interpreter::Opcode0 + { + std::string mControl; + bool mEnable; + + public: + + OpSetControl (const std::string& control, bool enable) + : mControl (control), mEnable (enable) + {} + + virtual void execute (Interpreter::Runtime& runtime) + { + if (mEnable) + std::cout << "enable: " << mControl << std::endl; + else + std::cout << "disable: " << mControl << std::endl; + } + }; + + const int numberOfControls = 7; + + const int opcodeEnable = 0x200007e; + const int opcodeDisable = 0x2000085; + + const char *controls[numberOfControls] = + { + "playercontrols", "playerfighting", "playerjumping", "playerlooking", "playermagic", + "playerviewswitch", "vanitymode" + }; + + void registerExtensions (Compiler::Extensions& extensions) + { + std::string enable ("enable"); + std::string disable ("disable"); + + for (int i=0; i Date: Sun, 22 Aug 2010 15:16:11 +0200 Subject: [PATCH 11/15] fixed AiTravel and changed GetAiPackageDone to return 0 (returning one would interfere with character creation testing at this point) --- apps/openmw/mwscript/aiextensions.cpp | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/apps/openmw/mwscript/aiextensions.cpp b/apps/openmw/mwscript/aiextensions.cpp index e1fdc1976..cd36eac9e 100644 --- a/apps/openmw/mwscript/aiextensions.cpp +++ b/apps/openmw/mwscript/aiextensions.cpp @@ -10,6 +10,7 @@ #include "interpretercontext.hpp" #include + namespace MWScript { namespace Ai @@ -156,7 +157,7 @@ namespace MWScript MWWorld::Ptr ptr = context.getReference(); - Interpreter::Type_Integer value = 1; + Interpreter::Type_Integer value = 0; runtime.push (value); } @@ -176,7 +177,7 @@ namespace MWScript MWWorld::Ptr ptr = context.getWorld().getPtr (id, false); - Interpreter::Type_Integer value = 1; + Interpreter::Type_Integer value = 0; runtime.push (value); } @@ -192,7 +193,7 @@ namespace MWScript void registerExtensions (Compiler::Extensions& extensions) { - extensions.registerInstruction ("aitravel", "cllll/l", opcodeAiTravel, + extensions.registerInstruction ("aitravel", "lll/l", opcodeAiTravel, opcodeAiTravelExplicit); extensions.registerInstruction ("aiescort", "cllll/l", opcodeAiEscort, opcodeAiEscortExplicit); From 459dd82896db01c81ffda318f49e8c00c21c2f56 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Mon, 30 Aug 2010 11:56:55 +0200 Subject: [PATCH 12/15] implemented locking/unlocking for doors (can not be invoked by user interaction yet) --- apps/openmw/mwclass/door.cpp | 16 ++++++++++++++++ apps/openmw/mwclass/door.hpp | 6 ++++++ apps/openmw/mwworld/class.cpp | 10 ++++++++++ apps/openmw/mwworld/class.hpp | 6 ++++++ 4 files changed, 38 insertions(+) diff --git a/apps/openmw/mwclass/door.cpp b/apps/openmw/mwclass/door.cpp index 12aeb9a5b..d15a01e9f 100644 --- a/apps/openmw/mwclass/door.cpp +++ b/apps/openmw/mwclass/door.cpp @@ -50,6 +50,9 @@ namespace MWClass ESMS::LiveCellRef *ref = ptr.get(); + // TODO check lock + // TODO check trap + if (ref->ref.teleport) { // teleport door @@ -74,6 +77,19 @@ namespace MWClass } } + void Door::lock (const MWWorld::Ptr& ptr, int lockLevel) const + { + if (lockLevel<0) + lockLevel = 0; + + ptr.getCellRef().lockLevel = lockLevel; + } + + void Door::unlock (const MWWorld::Ptr& ptr) const + { + ptr.getCellRef().lockLevel = 0; + } + std::string Door::getScript (const MWWorld::Ptr& ptr) const { ESMS::LiveCellRef *ref = diff --git a/apps/openmw/mwclass/door.hpp b/apps/openmw/mwclass/door.hpp index b6bf8808e..aecb117d3 100644 --- a/apps/openmw/mwclass/door.hpp +++ b/apps/openmw/mwclass/door.hpp @@ -21,6 +21,12 @@ namespace MWClass const MWWorld::Ptr& actor, const MWWorld::Environment& environment) const; ///< Generate action for activation + virtual void lock (const MWWorld::Ptr& ptr, int lockLevel) const; + ///< Lock object + + virtual void unlock (const MWWorld::Ptr& ptr) const; + ///< Unlock object + virtual std::string getScript (const MWWorld::Ptr& ptr) const; ///< Return name of the script attached to ptr diff --git a/apps/openmw/mwworld/class.cpp b/apps/openmw/mwworld/class.cpp index e21e4908c..1e9f25bbd 100644 --- a/apps/openmw/mwworld/class.cpp +++ b/apps/openmw/mwworld/class.cpp @@ -77,6 +77,16 @@ namespace MWWorld throw std::runtime_error ("class does not support inserting into a container"); } + void Class::lock (const Ptr& ptr, int lockLevel) const + { + throw std::runtime_error ("class does not support locking"); + } + + void Class::unlock (const Ptr& ptr) const + { + throw std::runtime_error ("class does not support unlocking"); + } + std::string Class::getScript (const Ptr& ptr) const { return ""; diff --git a/apps/openmw/mwworld/class.hpp b/apps/openmw/mwworld/class.hpp index c3f4bff14..5153d7468 100644 --- a/apps/openmw/mwworld/class.hpp +++ b/apps/openmw/mwworld/class.hpp @@ -98,6 +98,12 @@ namespace MWWorld ///< Insert into a container or throw an exception, if class does not support inserting into /// a container. + virtual void lock (const Ptr& ptr, int lockLevel) const; + ///< Lock object (default implementation: throw an exception) + + virtual void unlock (const Ptr& ptr) const; + ///< Unlock object (default implementation: throw an exception) + virtual std::string getScript (const Ptr& ptr) const; ///< Return name of the script attached to ptr (default implementation: return an empty /// string). From 61c4fa0630225201c4f1649f96e6086cb0afe4b1 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Mon, 30 Aug 2010 12:02:47 +0200 Subject: [PATCH 13/15] blocked using of locked doors (keys are not considered yet) --- apps/openmw/mwclass/door.cpp | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/apps/openmw/mwclass/door.cpp b/apps/openmw/mwclass/door.cpp index d15a01e9f..c22b8005e 100644 --- a/apps/openmw/mwclass/door.cpp +++ b/apps/openmw/mwclass/door.cpp @@ -15,6 +15,8 @@ #include "../mwrender/cellimp.hpp" +#include + namespace MWClass { void Door::insertObj (const MWWorld::Ptr& ptr, MWRender::CellRenderImp& cellRender, @@ -50,7 +52,14 @@ namespace MWClass ESMS::LiveCellRef *ref = ptr.get(); - // TODO check lock + if (ptr.getCellRef().lockLevel>0) + { + // TODO check for key + // TODO report failure to player (message, sound?). Look up behaviour of original MW. + std::cout << "Locked!" << std::endl; + return boost::shared_ptr (new MWWorld::NullAction); + } + // TODO check trap if (ref->ref.teleport) From 147dd57162bc3aafb05b7cd431a6835322960663 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Mon, 30 Aug 2010 12:30:34 +0200 Subject: [PATCH 14/15] added Lock and Unlock instructions --- apps/openmw/mwscript/docs/vmformat.txt | 8 ++- apps/openmw/mwscript/miscextensions.cpp | 95 +++++++++++++++++++++++++ 2 files changed, 101 insertions(+), 2 deletions(-) diff --git a/apps/openmw/mwscript/docs/vmformat.txt b/apps/openmw/mwscript/docs/vmformat.txt index 47f883c8a..0556450e6 100644 --- a/apps/openmw/mwscript/docs/vmformat.txt +++ b/apps/openmw/mwscript/docs/vmformat.txt @@ -17,7 +17,9 @@ op 0x20000: AiTravel op 0x20001: AiTravel, explicit reference op 0x20002: AiEscort op 0x20003: AiEscort, explicit reference -opcodes 0x20004-0x3ffff unused +op 0x20004: Lock +op 0x20005: Lock, explicit reference +opcodes 0x20006-0x3ffff unused Segment 4: (not implemented yet) @@ -90,4 +92,6 @@ op 0x200007c: GetAiPackageDone op 0x200007d: GetAiPackageDone, explicit reference op 0x200007e-0x2000084: Enable Controls op 0x2000085-0x200008b: Disable Controls -opcodes 0x200008c-0x3ffffff unused +op 0x200008c: Unlock +op 0x200008d: Unlock, explicit reference +opcodes 0x200008e-0x3ffffff unused diff --git a/apps/openmw/mwscript/miscextensions.cpp b/apps/openmw/mwscript/miscextensions.cpp index 1ecfd0c57..9cb65dcd7 100644 --- a/apps/openmw/mwscript/miscextensions.cpp +++ b/apps/openmw/mwscript/miscextensions.cpp @@ -9,6 +9,8 @@ #include "interpretercontext.hpp" +#include "../mwworld/class.hpp" + namespace MWScript { namespace Misc @@ -53,15 +55,104 @@ namespace MWScript } }; + class OpLock : public Interpreter::Opcode1 + { + public: + + virtual void execute (Interpreter::Runtime& runtime, unsigned int arg0) + { + InterpreterContext& context = + static_cast (runtime.getContext()); + + MWWorld::Ptr ptr = context.getReference(); + + Interpreter::Type_Integer lockLevel = 100; + + if (arg0==1) + { + lockLevel = runtime[0].mInteger; + runtime.pop(); + } + + MWWorld::Class::get (ptr).lock (ptr, lockLevel); + } + }; + + class OpLockExplicit : public Interpreter::Opcode1 + { + public: + + virtual void execute (Interpreter::Runtime& runtime, unsigned int arg0) + { + InterpreterContext& context = + static_cast (runtime.getContext()); + + std::string id = runtime.getStringLiteral (runtime[0].mInteger); + runtime.pop(); + + MWWorld::Ptr ptr = context.getWorld().getPtr (id, false); + + Interpreter::Type_Integer lockLevel = 100; + + if (arg0==1) + { + lockLevel = runtime[0].mInteger; + runtime.pop(); + } + + MWWorld::Class::get (ptr).lock (ptr, lockLevel); + } + }; + + class OpUnlock : public Interpreter::Opcode0 + { + public: + + virtual void execute (Interpreter::Runtime& runtime) + { + InterpreterContext& context = + static_cast (runtime.getContext()); + + MWWorld::Ptr ptr = context.getReference(); + + MWWorld::Class::get (ptr).unlock (ptr); + } + }; + + class OpUnlockExplicit : public Interpreter::Opcode0 + { + public: + + virtual void execute (Interpreter::Runtime& runtime) + { + InterpreterContext& context = + static_cast (runtime.getContext()); + + std::string id = runtime.getStringLiteral (runtime[0].mInteger); + runtime.pop(); + + MWWorld::Ptr ptr = context.getWorld().getPtr (id, false); + + MWWorld::Class::get (ptr).unlock (ptr); + } + }; + + const int opcodeXBox = 0x200000c; const int opcodeOnActivate = 0x200000d; const int opcodeActivate = 0x2000075; + const int opcodeLock = 0x20004; + const int opcodeLockExplicit = 0x20005; + const int opcodeUnlock = 0x200008c; + const int opcodeUnlockExplicit = 0x200008d; void registerExtensions (Compiler::Extensions& extensions) { extensions.registerFunction ("xbox", 'l', "", opcodeXBox); extensions.registerFunction ("onactivate", 'l', "", opcodeOnActivate); extensions.registerInstruction ("activate", "", opcodeActivate); + extensions.registerInstruction ("lock", "/l", opcodeLock, opcodeLockExplicit); + extensions.registerInstruction ("unlock", "", opcodeUnlock, opcodeUnlockExplicit); } void installOpcodes (Interpreter::Interpreter& interpreter) @@ -69,6 +160,10 @@ namespace MWScript interpreter.installSegment5 (opcodeXBox, new OpXBox); interpreter.installSegment5 (opcodeOnActivate, new OpOnActivate); interpreter.installSegment5 (opcodeActivate, new OpActivate); + interpreter.installSegment3 (opcodeLock, new OpLock); + interpreter.installSegment3 (opcodeLockExplicit, new OpLockExplicit); + interpreter.installSegment5 (opcodeUnlock, new OpUnlock); + interpreter.installSegment5 (opcodeUnlockExplicit, new OpUnlockExplicit); } } } From 044bf0ab4871b9631eb3ecf0284eb50518fcf20a Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Mon, 30 Aug 2010 14:44:23 +0200 Subject: [PATCH 15/15] fixed parsing explicit references in the body of control structures --- components/compiler/controlparser.cpp | 14 ++++++++++++++ components/compiler/controlparser.hpp | 24 ++++++++++++++---------- components/compiler/lineparser.cpp | 14 +++++++------- 3 files changed, 35 insertions(+), 17 deletions(-) diff --git a/components/compiler/controlparser.cpp b/components/compiler/controlparser.cpp index 2f5d5c4b6..c255154b5 100644 --- a/components/compiler/controlparser.cpp +++ b/components/compiler/controlparser.cpp @@ -172,6 +172,20 @@ namespace Compiler std::copy (mCode.begin(), mCode.end(), std::back_inserter (code)); } + bool ControlParser::parseName (const std::string& name, const TokenLoc& loc, Scanner& scanner) + { + if (mState==IfBodyState || mState==IfElseifBodyState || mState==IfElseBodyState || + mState==WhileBodyState) + { + scanner.putbackName (name, loc); + mLineParser.reset(); + scanner.scan (mLineParser); + return true; + } + + return Parser::parseName (name, loc, scanner); + } + bool ControlParser::parseKeyword (int keyword, const TokenLoc& loc, Scanner& scanner) { if (mState==StartState) diff --git a/components/compiler/controlparser.hpp b/components/compiler/controlparser.hpp index 17b3137c7..50fd2d1f9 100644 --- a/components/compiler/controlparser.hpp +++ b/components/compiler/controlparser.hpp @@ -13,9 +13,9 @@ namespace Compiler { class Locals; class Literals; - + // Control structure parser - + class ControlParser : public Parser { enum State @@ -28,31 +28,36 @@ namespace Compiler WhileEndState, WhileBodyState, WhileEndwhileState }; - + typedef std::vector Codes; typedef std::vector > IfCodes; - - Locals& mLocals; - Literals& mLiterals; + + Locals& mLocals; + Literals& mLiterals; Codes mCode; Codes mCodeBlock; IfCodes mIfCode; // condition, body LineParser mLineParser; ExprParser mExprParser; State mState; - + bool parseIfBody (int keyword, const TokenLoc& loc, Scanner& scanner); bool parseWhileBody (int keyword, const TokenLoc& loc, Scanner& scanner); - + public: - + ControlParser (ErrorHandler& errorHandler, Context& context, Locals& locals, Literals& literals); void appendCode (std::vector& code) const; ///< store generated code in \æ code. + virtual bool parseName (const std::string& name, const TokenLoc& loc, + Scanner& scanner); + ///< Handle a name token. + /// \return fetch another token? + virtual bool parseKeyword (int keyword, const TokenLoc& loc, Scanner& scanner); ///< Handle a keyword token. /// \return fetch another token? @@ -67,4 +72,3 @@ namespace Compiler } #endif - diff --git a/components/compiler/lineparser.cpp b/components/compiler/lineparser.cpp index 3f80d671e..5462f7788 100644 --- a/components/compiler/lineparser.cpp +++ b/components/compiler/lineparser.cpp @@ -183,6 +183,13 @@ namespace Compiler return true; } + if (mState==BeginState && getContext().isId (name)) + { + mState = PotentialExplicitState; + mExplicit = toLower (name); + return true; + } + if (mState==BeginState && mAllowExpression) { std::string name2 = toLower (name); @@ -206,13 +213,6 @@ namespace Compiler } } - if (mState==BeginState && getContext().isId (name)) - { - mState = PotentialExplicitState; - mExplicit = toLower (name); - return true; - } - return Parser::parseName (name, loc, scanner); }