From 8bcdf54570bc01659d06f8691d089ad5864bc1dd Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Sun, 2 Feb 2014 13:55:03 +0100 Subject: [PATCH 01/47] added warning mode to script compiler error handler --- components/compiler/errorhandler.cpp | 16 +++++++++++++--- components/compiler/errorhandler.hpp | 6 +++++- 2 files changed, 18 insertions(+), 4 deletions(-) diff --git a/components/compiler/errorhandler.cpp b/components/compiler/errorhandler.cpp index ee13c837d1..fe58836cca 100644 --- a/components/compiler/errorhandler.cpp +++ b/components/compiler/errorhandler.cpp @@ -5,7 +5,7 @@ namespace Compiler { // constructor - ErrorHandler::ErrorHandler() : mWarnings (0), mErrors (0) {} + ErrorHandler::ErrorHandler() : mWarnings (0), mErrors (0), mWarningsMode (1) {} // destructor @@ -36,8 +36,13 @@ namespace Compiler void ErrorHandler::warning (const std::string& message, const TokenLoc& loc) { - ++mWarnings; - report (message, loc, WarningMessage); + if (mWarningsMode==1) + { + ++mWarnings; + report (message, loc, WarningMessage); + } + else if (mWarningsMode==2) + error (message, loc); } // Generate an error message. @@ -62,4 +67,9 @@ namespace Compiler { mErrors = mWarnings = 0; } + + void ErrorHandler::setWarningsMode (int mode) + { + mWarningsMode = mode; + } } diff --git a/components/compiler/errorhandler.hpp b/components/compiler/errorhandler.hpp index 256065854a..e5922a6be5 100644 --- a/components/compiler/errorhandler.hpp +++ b/components/compiler/errorhandler.hpp @@ -16,6 +16,7 @@ namespace Compiler { int mWarnings; int mErrors; + int mWarningsMode; protected: @@ -60,8 +61,11 @@ namespace Compiler void endOfFile(); ///< Generate an error message for an unexpected EOF. - virtual void reset(); + virtual void reset(); ///< Remove all previous error/warning events + + void setWarningsMode (int mode); + ///< // 0 ignore, 1 rate as warning, 2 rate as error }; } From 4ee43612f66915ea1dc768b63a012c3cb06e9d89 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Sun, 2 Feb 2014 14:09:59 +0100 Subject: [PATCH 02/47] added new switch: --script-warn --- apps/openmw/engine.cpp | 9 +++-- apps/openmw/engine.hpp | 3 ++ apps/openmw/main.cpp | 8 +++++ apps/openmw/mwscript/scriptmanagerimp.cpp | 6 ++-- apps/openmw/mwscript/scriptmanagerimp.hpp | 2 +- readme.txt | 42 +++++++++++++---------- 6 files changed, 47 insertions(+), 23 deletions(-) diff --git a/apps/openmw/engine.cpp b/apps/openmw/engine.cpp index bf1cca5e0f..e80bd954e3 100644 --- a/apps/openmw/engine.cpp +++ b/apps/openmw/engine.cpp @@ -155,6 +155,7 @@ OMW::Engine::Engine(Files::ConfigurationManager& configurationManager) , mSkipMenu (false) , mUseSound (true) , mCompileAll (false) + , mWarningsMode (1) , mScriptContext (0) , mFSStrict (false) , mScriptConsoleMode (false) @@ -424,7 +425,7 @@ void OMW::Engine::prepareEngine (Settings::Manager & settings) mScriptContext->setExtensions (&mExtensions); mEnvironment.setScriptManager (new MWScript::ScriptManager (MWBase::Environment::get().getWorld()->getStore(), - mVerboseScripts, *mScriptContext)); + mVerboseScripts, *mScriptContext, mWarningsMode)); // Create game mechanics system MWMechanics::MechanicsManager* mechanics = new MWMechanics::MechanicsManager; @@ -612,8 +613,12 @@ void OMW::Engine::setStartupScript (const std::string& path) mStartupScript = path; } - void OMW::Engine::setActivationDistanceOverride (int distance) { mActivationDistanceOverride = distance; } + +void OMW::Engine::setWarningsMode (int mode) +{ + mWarningsMode = mode; +} \ No newline at end of file diff --git a/apps/openmw/engine.hpp b/apps/openmw/engine.hpp index 8b2a65b7ed..5c15ddf6fc 100644 --- a/apps/openmw/engine.hpp +++ b/apps/openmw/engine.hpp @@ -74,6 +74,7 @@ namespace OMW bool mSkipMenu; bool mUseSound; bool mCompileAll; + int mWarningsMode; std::string mFocusName; std::map mFallbackMap; bool mScriptConsoleMode; @@ -181,6 +182,8 @@ namespace OMW /// Override the game setting specified activation distance. void setActivationDistanceOverride (int distance); + void setWarningsMode (int mode); + private: Files::ConfigurationManager& mCfgMgr; }; diff --git a/apps/openmw/main.cpp b/apps/openmw/main.cpp index 570c2b1983..764c4f39b8 100644 --- a/apps/openmw/main.cpp +++ b/apps/openmw/main.cpp @@ -137,6 +137,13 @@ bool parseOptions (int argc, char** argv, OMW::Engine& engine, Files::Configurat ("script-run", bpo::value()->default_value(""), "select a file containing a list of console commands that is executed on startup") + ("script-warn", bpo::value()->implicit_value (1) + ->default_value (1), + "handling of warnings when compiling scripts\n" + "\t0 - ignore warning\n" + "\t1 - show warning but consider script as correctly compiled anyway\n" + "\t2 - treat warnings as errors") + ("skip-menu", bpo::value()->implicit_value(true) ->default_value(false), "skip main menu on game startup") @@ -242,6 +249,7 @@ bool parseOptions (int argc, char** argv, OMW::Engine& engine, Files::Configurat engine.setScriptConsoleMode (variables["script-console"].as()); engine.setStartupScript (variables["script-run"].as()); engine.setActivationDistanceOverride (variables["activate-dist"].as()); + engine.setWarningsMode (variables["script-warn"].as()); return true; } diff --git a/apps/openmw/mwscript/scriptmanagerimp.cpp b/apps/openmw/mwscript/scriptmanagerimp.cpp index a3e0615467..6862b9f830 100644 --- a/apps/openmw/mwscript/scriptmanagerimp.cpp +++ b/apps/openmw/mwscript/scriptmanagerimp.cpp @@ -18,11 +18,13 @@ namespace MWScript { ScriptManager::ScriptManager (const MWWorld::ESMStore& store, bool verbose, - Compiler::Context& compilerContext) + Compiler::Context& compilerContext, int warningsMode) : mErrorHandler (std::cerr), mStore (store), mVerbose (verbose), mCompilerContext (compilerContext), mParser (mErrorHandler, mCompilerContext), mOpcodesInstalled (false), mGlobalScripts (store) - {} + { + mErrorHandler.setWarningsMode (warningsMode); + } bool ScriptManager::compile (const std::string& name) { diff --git a/apps/openmw/mwscript/scriptmanagerimp.hpp b/apps/openmw/mwscript/scriptmanagerimp.hpp index 1a856e0c58..da3abc60b5 100644 --- a/apps/openmw/mwscript/scriptmanagerimp.hpp +++ b/apps/openmw/mwscript/scriptmanagerimp.hpp @@ -52,7 +52,7 @@ namespace MWScript public: ScriptManager (const MWWorld::ESMStore& store, bool verbose, - Compiler::Context& compilerContext); + Compiler::Context& compilerContext, int warningsMode); virtual void run (const std::string& name, Interpreter::Context& interpreterContext); ///< Run the script with the given name (compile first, if not compiled yet) diff --git a/readme.txt b/readme.txt index 6b388dc724..f4d0c0b8f7 100644 --- a/readme.txt +++ b/readme.txt @@ -48,42 +48,48 @@ Allowed options: --version print version information and quit --data arg (=data) set data directories (later directories have higher priority) - --data-local arg set local data directory (highest + --data-local arg set local data directory (highest priority) --fallback-archive arg (=fallback-archive) - set fallback BSA archives (later + set fallback BSA archives (later archives have higher priority) --resources arg (=resources) set resources directory --start arg (=Beshara) set initial cell - --content arg content file(s): esm/esp, or + --content arg content file(s): esm/esp, or omwgame/omwaddon --anim-verbose [=arg(=1)] (=0) output animation indices files --no-sound [=arg(=1)] (=0) disable all sounds --script-verbose [=arg(=1)] (=0) verbose script output --script-all [=arg(=1)] (=0) compile all scripts (excluding dialogue scripts) at startup - --script-console [=arg(=1)] (=0) enable console-only script + --script-console [=arg(=1)] (=0) enable console-only script functionality - --script-run arg select a file containing a list of - console commands that is executed on + --script-run arg select a file containing a list of + console commands that is executed on startup + --script-warn [=arg(=1)] (=1) handling of warnings when compiling + scripts + 0 - ignore warning + 1 - show warning but consider script as + correctly compiled anyway + 2 - treat warnings as errors --new-game [=arg(=1)] (=0) activate char gen/new game mechanics - --fs-strict [=arg(=1)] (=0) strict file system handling (no case + --fs-strict [=arg(=1)] (=0) strict file system handling (no case folding) - --encoding arg (=win1252) Character encoding used in OpenMW game + --encoding arg (=win1252) Character encoding used in OpenMW game messages: - - win1250 - Central and Eastern European - such as Polish, Czech, Slovak, - Hungarian, Slovene, Bosnian, Croatian, - Serbian (Latin script), Romanian and + + win1250 - Central and Eastern European + such as Polish, Czech, Slovak, + Hungarian, Slovene, Bosnian, Croatian, + Serbian (Latin script), Romanian and Albanian languages - - win1251 - Cyrillic alphabet such as - Russian, Bulgarian, Serbian Cyrillic + + win1251 - Cyrillic alphabet such as + Russian, Bulgarian, Serbian Cyrillic and other languages - - win1252 - Western European (Latin) + + win1252 - Western European (Latin) alphabet, used by default --fallback arg fallback values --no-grab Don't grab mouse cursor From 858dc80292a31c7359fc728f6d2c964a64f0f838 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Sun, 2 Feb 2014 14:10:57 +0100 Subject: [PATCH 03/47] corrected command line switch documentation in readme file --- readme.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/readme.txt b/readme.txt index f4d0c0b8f7..b1fef2d097 100644 --- a/readme.txt +++ b/readme.txt @@ -73,7 +73,7 @@ Allowed options: 1 - show warning but consider script as correctly compiled anyway 2 - treat warnings as errors - --new-game [=arg(=1)] (=0) activate char gen/new game mechanics + --skip-menu [=arg(=1)] (=0) skip main menu on game startup --fs-strict [=arg(=1)] (=0) strict file system handling (no case folding) --encoding arg (=win1252) Character encoding used in OpenMW game From cd9b13712921be4c61968e7959cff2b287f6fc17 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Sun, 2 Feb 2014 14:24:58 +0100 Subject: [PATCH 04/47] allow elseif without matching if (grrrrr) --- components/compiler/controlparser.cpp | 6 +++++- components/compiler/scriptparser.cpp | 2 +- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/components/compiler/controlparser.cpp b/components/compiler/controlparser.cpp index 5d74ee9d42..3be470c273 100644 --- a/components/compiler/controlparser.cpp +++ b/components/compiler/controlparser.cpp @@ -7,6 +7,7 @@ #include "scanner.hpp" #include "generator.hpp" +#include "errorhandler.hpp" namespace Compiler { @@ -186,8 +187,11 @@ namespace Compiler { if (mState==StartState) { - if (keyword==Scanner::K_if) + if (keyword==Scanner::K_if || keyword==Scanner::K_elseif) { + if (keyword==Scanner::K_elseif) + getErrorHandler().warning ("elseif without matching if", loc); + mExprParser.reset(); scanner.scan (mExprParser); diff --git a/components/compiler/scriptparser.cpp b/components/compiler/scriptparser.cpp index 5b3d244b0d..1b613595a6 100644 --- a/components/compiler/scriptparser.cpp +++ b/components/compiler/scriptparser.cpp @@ -32,7 +32,7 @@ namespace Compiler bool ScriptParser::parseKeyword (int keyword, const TokenLoc& loc, Scanner& scanner) { - if (keyword==Scanner::K_while || keyword==Scanner::K_if) + if (keyword==Scanner::K_while || keyword==Scanner::K_if || keyword==Scanner::K_elseif) { mControlParser.reset(); if (mControlParser.parseKeyword (keyword, loc, scanner)) From 914ab1b8ab689f1462d2f396d936ab0377bb2b2f Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Sun, 2 Feb 2014 15:08:27 +0100 Subject: [PATCH 05/47] allow 'x' instead of 'getjournalindex x' --- apps/opencs/model/world/scriptcontext.cpp | 6 ++++++ apps/opencs/model/world/scriptcontext.hpp | 3 +++ apps/openmw/mwscript/compilercontext.cpp | 12 ++++++++++++ apps/openmw/mwscript/compilercontext.hpp | 3 +++ components/compiler/context.hpp | 3 +++ components/compiler/exprparser.cpp | 19 ++++++++++++++++++- 6 files changed, 45 insertions(+), 1 deletion(-) diff --git a/apps/opencs/model/world/scriptcontext.cpp b/apps/opencs/model/world/scriptcontext.cpp index 86689d823b..8190c68eb7 100644 --- a/apps/opencs/model/world/scriptcontext.cpp +++ b/apps/opencs/model/world/scriptcontext.cpp @@ -38,6 +38,12 @@ bool CSMWorld::ScriptContext::isId (const std::string& name) const return std::binary_search (mIds.begin(), mIds.end(), Misc::StringUtils::lowerCase (name)); } +bool CSMWorld::ScriptContext::isJournalId (const std::string& name) const +{ + /// \todo fix this after isId is fixed + return isId (name); +} + void CSMWorld::ScriptContext::invalidateIds() { mIdsUpdated = false; diff --git a/apps/opencs/model/world/scriptcontext.hpp b/apps/opencs/model/world/scriptcontext.hpp index b839b5a432..961da9143b 100644 --- a/apps/opencs/model/world/scriptcontext.hpp +++ b/apps/opencs/model/world/scriptcontext.hpp @@ -32,6 +32,9 @@ namespace CSMWorld virtual bool isId (const std::string& name) const; ///< Does \a name match an ID, that can be referenced? + virtual bool isJournalId (const std::string& name) const; + ///< Does \a name match a journal ID? + void invalidateIds(); }; } diff --git a/apps/openmw/mwscript/compilercontext.cpp b/apps/openmw/mwscript/compilercontext.cpp index 7e63a33b25..b094e54147 100644 --- a/apps/openmw/mwscript/compilercontext.cpp +++ b/apps/openmw/mwscript/compilercontext.cpp @@ -3,6 +3,8 @@ #include "../mwworld/esmstore.hpp" +#include + #include #include "../mwbase/environment.hpp" @@ -67,4 +69,14 @@ namespace MWScript store.get().search (name) || store.get().search (name); } + + bool CompilerContext::isJournalId (const std::string& name) const + { + const MWWorld::ESMStore &store = + MWBase::Environment::get().getWorld()->getStore(); + + const ESM::Dialogue *topic = store.get().search (name); + + return topic && topic->mType==ESM::Dialogue::Journal; + } } diff --git a/apps/openmw/mwscript/compilercontext.hpp b/apps/openmw/mwscript/compilercontext.hpp index 5ec98e09a7..50256f9422 100644 --- a/apps/openmw/mwscript/compilercontext.hpp +++ b/apps/openmw/mwscript/compilercontext.hpp @@ -35,6 +35,9 @@ namespace MWScript virtual bool isId (const std::string& name) const; ///< Does \a name match an ID, that can be referenced? + + virtual bool isJournalId (const std::string& name) const; + ///< Does \a name match a journal ID? }; } diff --git a/components/compiler/context.hpp b/components/compiler/context.hpp index 1b02613c59..69146e285f 100644 --- a/components/compiler/context.hpp +++ b/components/compiler/context.hpp @@ -38,6 +38,9 @@ namespace Compiler virtual bool isId (const std::string& name) const = 0; ///< Does \a name match an ID, that can be referenced? + + virtual bool isJournalId (const std::string& name) const = 0; + ///< Does \a name match a journal ID? }; } diff --git a/components/compiler/exprparser.cpp b/components/compiler/exprparser.cpp index 94240c5eb9..42c88b75ab 100644 --- a/components/compiler/exprparser.cpp +++ b/components/compiler/exprparser.cpp @@ -7,6 +7,8 @@ #include #include +#include + #include "generator.hpp" #include "scanner.hpp" #include "errorhandler.hpp" @@ -14,7 +16,6 @@ #include "stringparser.hpp" #include "extensions.hpp" #include "context.hpp" -#include namespace Compiler { @@ -308,6 +309,22 @@ namespace Compiler return true; } + // die in a fire, Morrowind script compiler! + if (const Extensions *extensions = getContext().getExtensions()) + { + if (getContext().isJournalId (name2)) + { + // JournalID used as an argument. Use the index of that JournalID + Generator::pushString (mCode, mLiterals, name2); + int keyword = extensions->searchKeyword ("getjournalindex"); + extensions->generateFunctionCode (keyword, mCode, mLiterals, mExplicit, 0); + mNextOperand = false; + mOperands.push_back ('l'); + + return 2; + } + } + if (mExplicit.empty() && getContext().isId (name2)) { mExplicit = name2; From 32860a05e38f7b67afc8725beed30254d4c69dc1 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Sun, 2 Feb 2014 15:35:18 +0100 Subject: [PATCH 06/47] added dummy implementations for getPcInJail and getPcTraveling --- apps/openmw/mwscript/docs/vmformat.txt | 4 +++- apps/openmw/mwscript/miscextensions.cpp | 24 ++++++++++++++++++++++++ components/compiler/extensions0.cpp | 4 +++- components/compiler/opcodes.hpp | 2 ++ 4 files changed, 32 insertions(+), 2 deletions(-) diff --git a/apps/openmw/mwscript/docs/vmformat.txt b/apps/openmw/mwscript/docs/vmformat.txt index 25f3c38aa7..2fe4c768ba 100644 --- a/apps/openmw/mwscript/docs/vmformat.txt +++ b/apps/openmw/mwscript/docs/vmformat.txt @@ -381,5 +381,7 @@ op 0x200023a: StartCombat op 0x200023b: StartCombatExplicit op 0x200023c: StopCombat op 0x200023d: StopCombatExplicit +op 0x200023e: GetPcInJail +op 0x200023f: GetPcTraveling -opcodes 0x200023e-0x3ffffff unused +opcodes 0x2000240-0x3ffffff unused diff --git a/apps/openmw/mwscript/miscextensions.cpp b/apps/openmw/mwscript/miscextensions.cpp index d117c8dede..aa0e775af2 100644 --- a/apps/openmw/mwscript/miscextensions.cpp +++ b/apps/openmw/mwscript/miscextensions.cpp @@ -818,6 +818,28 @@ namespace MWScript } }; + class OpGetPcInJail : public Interpreter::Opcode0 + { + public: + + virtual void execute (Interpreter::Runtime &runtime) + { + /// \todo implement jail check + runtime.push (0); + } + }; + + class OpGetPcTraveling : public Interpreter::Opcode0 + { + public: + + virtual void execute (Interpreter::Runtime &runtime) + { + /// \todo implement traveling check + runtime.push (0); + } + }; + void installOpcodes (Interpreter::Interpreter& interpreter) { interpreter.installSegment5 (Compiler::Misc::opcodeXBox, new OpXBox); @@ -888,6 +910,8 @@ namespace MWScript interpreter.installSegment5 (Compiler::Misc::opcodeCastExplicit, new OpCast); interpreter.installSegment5 (Compiler::Misc::opcodeExplodeSpell, new OpExplodeSpell); interpreter.installSegment5 (Compiler::Misc::opcodeExplodeSpellExplicit, new OpExplodeSpell); + interpreter.installSegment5 (Compiler::Misc::opcodeGetPcInJail, new OpGetPcInJail); + interpreter.installSegment5 (Compiler::Misc::opcodeGetPcTraveling, new OpGetPcTraveling); } } } diff --git a/components/compiler/extensions0.cpp b/components/compiler/extensions0.cpp index baec9987fa..ebe46d2826 100644 --- a/components/compiler/extensions0.cpp +++ b/components/compiler/extensions0.cpp @@ -190,7 +190,7 @@ namespace Compiler extensions.registerInstruction ("enableclassmenu", "", opcodeEnableClassMenu); extensions.registerInstruction ("enablenamemenu", "", opcodeEnableNameMenu); extensions.registerInstruction ("enableracemenu", "", opcodeEnableRaceMenu); - extensions.registerInstruction ("enablestatreviewmenu", "", + extensions.registerInstruction ("enablestatreviewmenu", "", opcodeEnableStatsReviewMenu); extensions.registerInstruction ("enableinventorymenu", "", opcodeEnableInventoryMenu); @@ -276,6 +276,8 @@ namespace Compiler extensions.registerInstruction("togglegodmode", "", opcodeToggleGodMode); extensions.registerInstruction ("disablelevitation", "", opcodeDisableLevitation); extensions.registerInstruction ("enablelevitation", "", opcodeEnableLevitation); + extensions.registerFunction ("getpcinjail", 'l', "", opcodeGetPcInJail); + extensions.registerFunction ("getpctraveling", 'l', "", opcodeGetPcTraveling); } } diff --git a/components/compiler/opcodes.hpp b/components/compiler/opcodes.hpp index 57d86e62bf..583cf4eea3 100644 --- a/components/compiler/opcodes.hpp +++ b/components/compiler/opcodes.hpp @@ -245,6 +245,8 @@ namespace Compiler const int opcodeCastExplicit = 0x2000228; const int opcodeExplodeSpell = 0x2000229; const int opcodeExplodeSpellExplicit = 0x200022a; + const int opcodeGetPcInJail = 0x200023e; + const int opcodeGetPcTraveling = 0x200023f; } namespace Sky From 2b2ac6f62b7db5972fbf461056d06576e9e4557f Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Sun, 2 Feb 2014 15:43:48 +0100 Subject: [PATCH 07/47] allow declaration of local variables with keywords as names --- components/compiler/lineparser.cpp | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/components/compiler/lineparser.cpp b/components/compiler/lineparser.cpp index 3d9ac0a93a..2904df6e1b 100644 --- a/components/compiler/lineparser.cpp +++ b/components/compiler/lineparser.cpp @@ -370,6 +370,12 @@ namespace Compiler mState = EndState; return true; } + else if (mState==ShortState || mState==LongState || mState==FloatState) + { + // allow keywords to be used as local variable names. MW script compiler, you suck! + /// \todo option to disable this atrocity. + return parseName (loc.mLiteral, loc, scanner); + } if (mAllowExpression) { From 3147aebf7501cc1fc7c64d3b93832261c2eed47c Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Mon, 10 Feb 2014 13:01:52 +0100 Subject: [PATCH 08/47] factored out declaration parser --- components/CMakeLists.txt | 2 +- components/compiler/declarationparser.cpp | 79 +++++++++++++++++++++++ components/compiler/declarationparser.hpp | 41 ++++++++++++ components/compiler/lineparser.cpp | 64 +++++++----------- components/compiler/lineparser.hpp | 1 - 5 files changed, 144 insertions(+), 43 deletions(-) create mode 100644 components/compiler/declarationparser.cpp create mode 100644 components/compiler/declarationparser.hpp diff --git a/components/CMakeLists.txt b/components/CMakeLists.txt index f2b16d4d53..4f6639e9bc 100644 --- a/components/CMakeLists.txt +++ b/components/CMakeLists.txt @@ -55,7 +55,7 @@ add_component_dir (files add_component_dir (compiler context controlparser errorhandler exception exprparser extensions fileparser generator lineparser literals locals output parser scanner scriptparser skipparser streamerrorhandler - stringparser tokenloc nullerrorhandler opcodes extensions0 + stringparser tokenloc nullerrorhandler opcodes extensions0 declarationparser ) add_component_dir (interpreter diff --git a/components/compiler/declarationparser.cpp b/components/compiler/declarationparser.cpp new file mode 100644 index 0000000000..586b28bc29 --- /dev/null +++ b/components/compiler/declarationparser.cpp @@ -0,0 +1,79 @@ + +#include "declarationparser.hpp" + +#include + +#include "scanner.hpp" +#include "errorhandler.hpp" +#include "skipparser.hpp" +#include "locals.hpp" + +Compiler::DeclarationParser::DeclarationParser (ErrorHandler& errorHandler, Context& context, + Locals& locals) +: Parser (errorHandler, context), mLocals (locals), mState (State_Begin), mType (0) +{} + +bool Compiler::DeclarationParser::parseName (const std::string& name, const TokenLoc& loc, + Scanner& scanner) +{ + if (mState==State_Name) + { + std::string name2 = Misc::StringUtils::lowerCase (name); + + char type = mLocals.getType (name2); + + if (type!=' ') + { + /// \todo add option to make re-declared local variables an error + getErrorHandler().warning ("can't re-declare local variable (ignoring declaration)", + loc); + SkipParser skip (getErrorHandler(), getContext()); + scanner.scan (skip); + mState = State_End; + return true; + } + + mLocals.declare (mType, name2); + + mState = State_End; + return true; + } + + return Parser::parseName (name, loc, scanner); +} + +bool Compiler::DeclarationParser::parseKeyword (int keyword, const TokenLoc& loc, Scanner& scanner) +{ + if (mState==State_Begin) + { + switch (keyword) + { + case Scanner::K_short: mType = 's'; break; + case Scanner::K_long: mType = 'l'; break; + case Scanner::K_float: mType = 'f'; break; + default: mType = 0; + } + + if (mType) + { + mState = State_Name; + return true; + } + } + else if (mState==State_Name) + { + // allow keywords to be used as local variable names. MW script compiler, you suck! + /// \todo option to disable this atrocity. + return parseName (loc.mLiteral, loc, scanner); + } + + return Parser::parseKeyword (keyword, loc, scanner); +} + +bool Compiler::DeclarationParser::parseSpecial (int code, const TokenLoc& loc, Scanner& scanner) +{ + if (code==Scanner::S_newline && mState==State_End) + return false; + + return Parser::parseSpecial (code, loc, scanner); +} \ No newline at end of file diff --git a/components/compiler/declarationparser.hpp b/components/compiler/declarationparser.hpp new file mode 100644 index 0000000000..3e0ac57c34 --- /dev/null +++ b/components/compiler/declarationparser.hpp @@ -0,0 +1,41 @@ +#ifndef COMPILER_DECLARATIONPARSER_H_INCLUDED +#define COMPILER_DECLARATIONPARSER_H_INCLUDED + +#include "parser.hpp" + +namespace Compiler +{ + class Locals; + + class DeclarationParser : public Parser + { + enum State + { + State_Begin, State_Name, State_End + }; + + Locals& mLocals; + State mState; + char mType; + + public: + + DeclarationParser (ErrorHandler& errorHandler, Context& context, Locals& locals); + + 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? + + virtual bool parseSpecial (int code, const TokenLoc& loc, Scanner& scanner); + ///< Handle a special character token. + /// \return fetch another token? + + }; +} + +#endif diff --git a/components/compiler/lineparser.cpp b/components/compiler/lineparser.cpp index 2904df6e1b..368152fd93 100644 --- a/components/compiler/lineparser.cpp +++ b/components/compiler/lineparser.cpp @@ -1,6 +1,8 @@ #include "lineparser.hpp" +#include + #include "scanner.hpp" #include "context.hpp" #include "errorhandler.hpp" @@ -8,7 +10,7 @@ #include "locals.hpp" #include "generator.hpp" #include "extensions.hpp" -#include +#include "declarationparser.hpp" namespace Compiler { @@ -82,37 +84,6 @@ namespace Compiler bool LineParser::parseName (const std::string& name, const TokenLoc& loc, Scanner& scanner) { - if (mState==ShortState || mState==LongState || mState==FloatState) - { - if (!getContext().canDeclareLocals()) - { - getErrorHandler().error ("local variables can't be declared in this context", loc); - SkipParser skip (getErrorHandler(), getContext()); - scanner.scan (skip); - return false; - } - - std::string name2 = Misc::StringUtils::lowerCase (name); - - char type = mLocals.getType (name2); - - if (type!=' ') - { - /// \todo add option to make re-declared local variables an error - getErrorHandler().warning ("can't re-declare local variable", loc); - SkipParser skip (getErrorHandler(), getContext()); - scanner.scan (skip); - mState = EndState; - return true; - } - - mLocals.declare (mState==ShortState ? 's' : (mState==LongState ? 'l' : 'f'), - name2); - - mState = EndState; - return true; - } - if (mState==SetState) { std::string name2 = Misc::StringUtils::lowerCase (name); @@ -303,9 +274,26 @@ namespace Compiler { switch (keyword) { - case Scanner::K_short: mState = ShortState; return true; - case Scanner::K_long: mState = LongState; return true; - case Scanner::K_float: mState = FloatState; return true; + case Scanner::K_short: + case Scanner::K_long: + case Scanner::K_float: + { + if (!getContext().canDeclareLocals()) + { + getErrorHandler().error ( + "local variables can't be declared in this context", loc); + SkipParser skip (getErrorHandler(), getContext()); + scanner.scan (skip); + return true; + } + + DeclarationParser declaration (getErrorHandler(), getContext(), mLocals); + if (declaration.parseKeyword (keyword, loc, scanner)) + scanner.scan (declaration); + + return true; + } + case Scanner::K_set: mState = SetState; return true; case Scanner::K_messagebox: mState = MessageState; return true; @@ -370,12 +358,6 @@ namespace Compiler mState = EndState; return true; } - else if (mState==ShortState || mState==LongState || mState==FloatState) - { - // allow keywords to be used as local variable names. MW script compiler, you suck! - /// \todo option to disable this atrocity. - return parseName (loc.mLiteral, loc, scanner); - } if (mAllowExpression) { diff --git a/components/compiler/lineparser.hpp b/components/compiler/lineparser.hpp index aa74cd232f..cf72f26a83 100644 --- a/components/compiler/lineparser.hpp +++ b/components/compiler/lineparser.hpp @@ -20,7 +20,6 @@ namespace Compiler enum State { BeginState, - ShortState, LongState, FloatState, SetState, SetLocalVarState, SetGlobalVarState, SetPotentialMemberVarState, SetMemberVarState, SetMemberVarState2, MessageState, MessageCommaState, MessageButtonState, MessageButtonCommaState, From 3b990795c4da85fcbf7373b47ff4914aa17b5635 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Mon, 10 Feb 2014 14:45:55 +0100 Subject: [PATCH 09/47] added access to remote access of local variables of global scripts --- apps/opencs/model/world/scriptcontext.cpp | 5 +- apps/opencs/model/world/scriptcontext.hpp | 8 +- apps/openmw/mwscript/compilercontext.cpp | 27 ++++- apps/openmw/mwscript/compilercontext.hpp | 8 +- apps/openmw/mwscript/globalscripts.cpp | 21 ++++ apps/openmw/mwscript/globalscripts.hpp | 4 + apps/openmw/mwscript/interpretercontext.cpp | 123 +++++++++++++------- apps/openmw/mwscript/interpretercontext.hpp | 44 ++++--- components/compiler/context.hpp | 8 +- components/compiler/exprparser.cpp | 9 +- components/compiler/generator.cpp | 41 +++---- components/compiler/generator.hpp | 6 +- components/compiler/lineparser.cpp | 10 +- components/compiler/lineparser.hpp | 1 + components/interpreter/context.hpp | 36 +++--- components/interpreter/docs/vmformat.txt | 8 +- components/interpreter/installopcodes.cpp | 18 ++- components/interpreter/localopcodes.hpp | 36 +++++- 18 files changed, 277 insertions(+), 136 deletions(-) diff --git a/apps/opencs/model/world/scriptcontext.cpp b/apps/opencs/model/world/scriptcontext.cpp index 8190c68eb7..1b30281595 100644 --- a/apps/opencs/model/world/scriptcontext.cpp +++ b/apps/opencs/model/world/scriptcontext.cpp @@ -19,9 +19,10 @@ char CSMWorld::ScriptContext::getGlobalType (const std::string& name) const return ' '; } -char CSMWorld::ScriptContext::getMemberType (const std::string& name, const std::string& id) const +std::pair CSMWorld::ScriptContext::getMemberType (const std::string& name, + const std::string& id) const { - return ' '; + return std::make_pair (' ', false); } bool CSMWorld::ScriptContext::isId (const std::string& name) const diff --git a/apps/opencs/model/world/scriptcontext.hpp b/apps/opencs/model/world/scriptcontext.hpp index 961da9143b..3baca99b24 100644 --- a/apps/opencs/model/world/scriptcontext.hpp +++ b/apps/opencs/model/world/scriptcontext.hpp @@ -26,8 +26,12 @@ namespace CSMWorld virtual char getGlobalType (const std::string& name) const; ///< 'l: long, 's': short, 'f': float, ' ': does not exist. - virtual char getMemberType (const std::string& name, const std::string& id) const; - ///< 'l: long, 's': short, 'f': float, ' ': does not exist. + virtual std::pair getMemberType (const std::string& name, + const std::string& id) const; + ///< Return type of member variable \a name in script \a id or in script of reference of + /// \a id + /// \return first: 'l: long, 's': short, 'f': float, ' ': does not exist. + /// second: true: script of reference virtual bool isId (const std::string& name) const; ///< Does \a name match an ID, that can be referenced? diff --git a/apps/openmw/mwscript/compilercontext.cpp b/apps/openmw/mwscript/compilercontext.cpp index b094e54147..8018b86e02 100644 --- a/apps/openmw/mwscript/compilercontext.cpp +++ b/apps/openmw/mwscript/compilercontext.cpp @@ -30,16 +30,31 @@ namespace MWScript return MWBase::Environment::get().getWorld()->getGlobalVariableType (name); } - char CompilerContext::getMemberType (const std::string& name, const std::string& id) const + std::pair CompilerContext::getMemberType (const std::string& name, + const std::string& id) const { - MWWorld::Ptr ptr = MWBase::Environment::get().getWorld()->getPtr (id, false); + std::string script; + bool reference = false; - std::string script = MWWorld::Class::get (ptr).getScript (ptr); + if (const ESM::Script *scriptRecord = + MWBase::Environment::get().getWorld()->getStore().get().search (id)) + { + script = scriptRecord->mId; + } + else + { + MWWorld::Ptr ptr = MWBase::Environment::get().getWorld()->getPtr (id, false); - if (script.empty()) - return ' '; + script = MWWorld::Class::get (ptr).getScript (ptr); + reference = true; + } - return MWBase::Environment::get().getScriptManager()->getLocals (script).getType (name); + char type = ' '; + + if (!script.empty()) + type = MWBase::Environment::get().getScriptManager()->getLocals (script).getType (name); + + return std::make_pair (type, reference); } bool CompilerContext::isId (const std::string& name) const diff --git a/apps/openmw/mwscript/compilercontext.hpp b/apps/openmw/mwscript/compilercontext.hpp index 50256f9422..95719ab692 100644 --- a/apps/openmw/mwscript/compilercontext.hpp +++ b/apps/openmw/mwscript/compilercontext.hpp @@ -30,8 +30,12 @@ namespace MWScript /// 'l: long, 's': short, 'f': float, ' ': does not exist. virtual char getGlobalType (const std::string& name) const; - virtual char getMemberType (const std::string& name, const std::string& id) const; - ///< 'l: long, 's': short, 'f': float, ' ': does not exist. + virtual std::pair getMemberType (const std::string& name, + const std::string& id) const; + ///< Return type of member variable \a name in script \a id or in script of reference of + /// \a id + /// \return first: 'l: long, 's': short, 'f': float, ' ': does not exist. + /// second: true: script of reference virtual bool isId (const std::string& name) const; ///< Does \a name match an ID, that can be referenced? diff --git a/apps/openmw/mwscript/globalscripts.cpp b/apps/openmw/mwscript/globalscripts.cpp index 8f269a0153..179e2bb0bb 100644 --- a/apps/openmw/mwscript/globalscripts.cpp +++ b/apps/openmw/mwscript/globalscripts.cpp @@ -148,4 +148,25 @@ namespace MWScript return false; } + + Locals& GlobalScripts::getLocals (const std::string& name) + { + std::string name2 = Misc::StringUtils::lowerCase (name); + std::map >::iterator iter = + mScripts.find (name2); + + if (iter==mScripts.end()) + { + if (const ESM::Script *script = mStore.get().find (name)) + { + Locals locals; + + locals.configure (*script); + + iter = mScripts.insert (std::make_pair (name, std::make_pair (false, locals))).first; + } + } + + return iter->second.second; + } } diff --git a/apps/openmw/mwscript/globalscripts.hpp b/apps/openmw/mwscript/globalscripts.hpp index cf716c8e42..a4a7662263 100644 --- a/apps/openmw/mwscript/globalscripts.hpp +++ b/apps/openmw/mwscript/globalscripts.hpp @@ -52,6 +52,10 @@ namespace MWScript ///< Records for variables that do not exist are dropped silently. /// /// \return Known type? + + Locals& getLocals (const std::string& name); + ///< If the script \a name has not been added as a global script yet, it is added + /// automatically, but is not set to running state. }; } diff --git a/apps/openmw/mwscript/interpretercontext.cpp b/apps/openmw/mwscript/interpretercontext.cpp index 10e98e3988..17092b41ca 100644 --- a/apps/openmw/mwscript/interpretercontext.cpp +++ b/apps/openmw/mwscript/interpretercontext.cpp @@ -54,6 +54,47 @@ namespace MWScript } } + const Locals& InterpreterContext::getMemberLocals (std::string& id, bool global) + const + { + if (global) + { + return MWBase::Environment::get().getScriptManager()->getGlobalScripts(). + getLocals (id); + } + else + { + const MWWorld::Ptr ptr = getReference (id, false); + + std::string id = MWWorld::Class::get (ptr).getScript (ptr); + + ptr.getRefData().setLocals ( + *MWBase::Environment::get().getWorld()->getStore().get().find (id)); + + return ptr.getRefData().getLocals(); + } + } + + Locals& InterpreterContext::getMemberLocals (std::string& id, bool global) + { + if (global) + { + return MWBase::Environment::get().getScriptManager()->getGlobalScripts(). + getLocals (id); + } + else + { + const MWWorld::Ptr ptr = getReference (id, false); + + std::string id = MWWorld::Class::get (ptr).getScript (ptr); + + ptr.getRefData().setLocals ( + *MWBase::Environment::get().getWorld()->getStore().get().find (id)); + + return ptr.getRefData().getLocals(); + } + } + InterpreterContext::InterpreterContext ( MWScript::Locals *locals, MWWorld::Ptr reference) : mLocals (locals), mReference (reference), @@ -407,82 +448,80 @@ namespace MWScript MWBase::Environment::get().getWorld()->disable (ref); } - int InterpreterContext::getMemberShort (const std::string& id, const std::string& name) const + int InterpreterContext::getMemberShort (const std::string& id, const std::string& name, + bool global) const { - const MWWorld::Ptr ptr = getReference (id, false); + std::string scriptId (id); - std::string scriptId = MWWorld::Class::get (ptr).getScript (ptr); + const Locals& locals = getMemberLocals (scriptId, global); - int index = MWBase::Environment::get().getScriptManager()->getLocalIndex (scriptId, name, 's'); + int index = MWBase::Environment::get().getScriptManager()->getLocalIndex ( + scriptId, name, 's'); - ptr.getRefData().setLocals ( - *MWBase::Environment::get().getWorld()->getStore().get().find (scriptId)); - return ptr.getRefData().getLocals().mShorts[index]; + return locals.mShorts[index]; } - int InterpreterContext::getMemberLong (const std::string& id, const std::string& name) const + int InterpreterContext::getMemberLong (const std::string& id, const std::string& name, + bool global) const { - const MWWorld::Ptr ptr = getReference (id, false); + std::string scriptId (id); - std::string scriptId = MWWorld::Class::get (ptr).getScript (ptr); + const Locals& locals = getMemberLocals (scriptId, global); - int index = MWBase::Environment::get().getScriptManager()->getLocalIndex (scriptId, name, 'l'); + int index = MWBase::Environment::get().getScriptManager()->getLocalIndex ( + scriptId, name, 'l'); - ptr.getRefData().setLocals ( - *MWBase::Environment::get().getWorld()->getStore().get().find (scriptId)); - return ptr.getRefData().getLocals().mLongs[index]; + return locals.mLongs[index]; } - float InterpreterContext::getMemberFloat (const std::string& id, const std::string& name) const + float InterpreterContext::getMemberFloat (const std::string& id, const std::string& name, + bool global) const { - const MWWorld::Ptr ptr = getReference (id, false); + std::string scriptId (id); - std::string scriptId = MWWorld::Class::get (ptr).getScript (ptr); + const Locals& locals = getMemberLocals (scriptId, global); - int index = MWBase::Environment::get().getScriptManager()->getLocalIndex (scriptId, name, 'f'); + int index = MWBase::Environment::get().getScriptManager()->getLocalIndex ( + scriptId, name, 'f'); - ptr.getRefData().setLocals ( - *MWBase::Environment::get().getWorld()->getStore().get().find (scriptId)); - return ptr.getRefData().getLocals().mFloats[index]; + return locals.mFloats[index]; } - void InterpreterContext::setMemberShort (const std::string& id, const std::string& name, int value) + void InterpreterContext::setMemberShort (const std::string& id, const std::string& name, + int value, bool global) { - const MWWorld::Ptr ptr = getReference (id, false); + std::string scriptId (id); - std::string scriptId = MWWorld::Class::get (ptr).getScript (ptr); + Locals& locals = getMemberLocals (scriptId, global); - int index = MWBase::Environment::get().getScriptManager()->getLocalIndex (scriptId, name, 's'); + int index = + MWBase::Environment::get().getScriptManager()->getLocalIndex (scriptId, name, 's'); - ptr.getRefData().setLocals ( - *MWBase::Environment::get().getWorld()->getStore().get().find (scriptId)); - ptr.getRefData().getLocals().mShorts[index] = value; + locals.mShorts[index] = value; } - void InterpreterContext::setMemberLong (const std::string& id, const std::string& name, int value) + void InterpreterContext::setMemberLong (const std::string& id, const std::string& name, int value, bool global) { - const MWWorld::Ptr ptr = getReference (id, false); + std::string scriptId (id); - std::string scriptId = MWWorld::Class::get (ptr).getScript (ptr); + Locals& locals = getMemberLocals (scriptId, global); - int index = MWBase::Environment::get().getScriptManager()->getLocalIndex (scriptId, name, 'l'); + int index = + MWBase::Environment::get().getScriptManager()->getLocalIndex (scriptId, name, 'l'); - ptr.getRefData().setLocals ( - *MWBase::Environment::get().getWorld()->getStore().get().find (scriptId)); - ptr.getRefData().getLocals().mLongs[index] = value; + locals.mLongs[index] = value; } - void InterpreterContext::setMemberFloat (const std::string& id, const std::string& name, float value) + void InterpreterContext::setMemberFloat (const std::string& id, const std::string& name, float value, bool global) { - const MWWorld::Ptr ptr = getReference (id, false); + std::string scriptId (id); - std::string scriptId = MWWorld::Class::get (ptr).getScript (ptr); + Locals& locals = getMemberLocals (scriptId, global); - int index = MWBase::Environment::get().getScriptManager()->getLocalIndex (scriptId, name, 'f'); + int index = + MWBase::Environment::get().getScriptManager()->getLocalIndex (scriptId, name, 'f'); - ptr.getRefData().setLocals ( - *MWBase::Environment::get().getWorld()->getStore().get().find (scriptId)); - ptr.getRefData().getLocals().mFloats[index] = value; + locals.mFloats[index] = value; } MWWorld::Ptr InterpreterContext::getReference(bool required) diff --git a/apps/openmw/mwscript/interpretercontext.hpp b/apps/openmw/mwscript/interpretercontext.hpp index 04546faed7..9fb7fa2bf8 100644 --- a/apps/openmw/mwscript/interpretercontext.hpp +++ b/apps/openmw/mwscript/interpretercontext.hpp @@ -37,6 +37,12 @@ namespace MWScript const MWWorld::Ptr getReference (const std::string& id, bool activeOnly, bool doThrow=true) const; + const Locals& getMemberLocals (std::string& id, bool global) const; + ///< \a id is changed to the respective script ID, if \a id wasn't a script ID before + + Locals& getMemberLocals (std::string& id, bool global); + ///< \a id is changed to the respective script ID, if \a id wasn't a script ID before + public: InterpreterContext (MWScript::Locals *locals, MWWorld::Ptr reference); @@ -75,35 +81,35 @@ namespace MWScript virtual void setGlobalLong (const std::string& name, int value); virtual void setGlobalFloat (const std::string& name, float value); - + virtual std::vector getGlobals () const; virtual char getGlobalType (const std::string& name) const; - + virtual std::string getActionBinding(const std::string& action) const; - + virtual std::string getNPCName() const; - + virtual std::string getNPCRace() const; - + virtual std::string getNPCClass() const; - + virtual std::string getNPCFaction() const; virtual std::string getNPCRank() const; - + virtual std::string getPCName() const; - + virtual std::string getPCRace() const; - + virtual std::string getPCClass() const; - + virtual std::string getPCRank() const; - + virtual std::string getPCNextRank() const; - + virtual int getPCBounty() const; - + virtual std::string getCurrentCellName() const; virtual bool isScriptRunning (const std::string& name) const; @@ -138,17 +144,17 @@ namespace MWScript virtual void disable (const std::string& id = ""); - virtual int getMemberShort (const std::string& id, const std::string& name) const; + virtual int getMemberShort (const std::string& id, const std::string& name, bool global) const; - virtual int getMemberLong (const std::string& id, const std::string& name) const; + virtual int getMemberLong (const std::string& id, const std::string& name, bool global) const; - virtual float getMemberFloat (const std::string& id, const std::string& name) const; + virtual float getMemberFloat (const std::string& id, const std::string& name, bool global) const; - virtual void setMemberShort (const std::string& id, const std::string& name, int value); + virtual void setMemberShort (const std::string& id, const std::string& name, int value, bool global); - virtual void setMemberLong (const std::string& id, const std::string& name, int value); + virtual void setMemberLong (const std::string& id, const std::string& name, int value, bool global); - virtual void setMemberFloat (const std::string& id, const std::string& name, float value); + virtual void setMemberFloat (const std::string& id, const std::string& name, float value, bool global); MWWorld::Ptr getReference(bool required=true); ///< Reference, that the script is running from (can be empty) diff --git a/components/compiler/context.hpp b/components/compiler/context.hpp index 69146e285f..84bb89bdc4 100644 --- a/components/compiler/context.hpp +++ b/components/compiler/context.hpp @@ -33,8 +33,12 @@ namespace Compiler virtual char getGlobalType (const std::string& name) const = 0; ///< 'l: long, 's': short, 'f': float, ' ': does not exist. - virtual char getMemberType (const std::string& name, const std::string& id) const = 0; - ///< 'l: long, 's': short, 'f': float, ' ': does not exist. + virtual std::pair getMemberType (const std::string& name, + const std::string& id) const = 0; + ///< Return type of member variable \a name in script \a id or in script of reference of + /// \a id + /// \return first: 'l: long, 's': short, 'f': float, ' ': does not exist. + /// second: true: script of reference virtual bool isId (const std::string& name) const = 0; ///< Does \a name match an ID, that can be referenced? diff --git a/components/compiler/exprparser.cpp b/components/compiler/exprparser.cpp index 42c88b75ab..283da854c9 100644 --- a/components/compiler/exprparser.cpp +++ b/components/compiler/exprparser.cpp @@ -204,14 +204,15 @@ namespace Compiler std::string name2 = Misc::StringUtils::lowerCase (name); std::string id = Misc::StringUtils::lowerCase (mExplicit); - char type = getContext().getMemberType (name2, id); + std::pair type = getContext().getMemberType (name2, id); - if (type!=' ') + if (type.first!=' ') { - Generator::fetchMember (mCode, mLiterals, type, name2, id); + Generator::fetchMember (mCode, mLiterals, type.first, name2, id, !type.second); + mNextOperand = false; mExplicit.clear(); - mOperands.push_back (type=='f' ? 'f' : 'l'); + mOperands.push_back (type.first=='f' ? 'f' : 'l'); return true; } diff --git a/components/compiler/generator.cpp b/components/compiler/generator.cpp index 9b02e4273f..83e46d5f7b 100644 --- a/components/compiler/generator.cpp +++ b/components/compiler/generator.cpp @@ -260,34 +260,34 @@ namespace code.push_back (Compiler::Generator::segment5 (44)); } - void opStoreMemberShort (Compiler::Generator::CodeContainer& code) + void opStoreMemberShort (Compiler::Generator::CodeContainer& code, bool global) { - code.push_back (Compiler::Generator::segment5 (59)); + code.push_back (Compiler::Generator::segment5 (global ? 65 : 59)); } - void opStoreMemberLong (Compiler::Generator::CodeContainer& code) + void opStoreMemberLong (Compiler::Generator::CodeContainer& code, bool global) { - code.push_back (Compiler::Generator::segment5 (60)); + code.push_back (Compiler::Generator::segment5 (global ? 66 : 60)); } - void opStoreMemberFloat (Compiler::Generator::CodeContainer& code) + void opStoreMemberFloat (Compiler::Generator::CodeContainer& code, bool global) { - code.push_back (Compiler::Generator::segment5 (61)); + code.push_back (Compiler::Generator::segment5 (global ? 67 : 61)); } - void opFetchMemberShort (Compiler::Generator::CodeContainer& code) + void opFetchMemberShort (Compiler::Generator::CodeContainer& code, bool global) { - code.push_back (Compiler::Generator::segment5 (62)); + code.push_back (Compiler::Generator::segment5 (global ? 68 : 62)); } - void opFetchMemberLong (Compiler::Generator::CodeContainer& code) + void opFetchMemberLong (Compiler::Generator::CodeContainer& code, bool global) { - code.push_back (Compiler::Generator::segment5 (63)); + code.push_back (Compiler::Generator::segment5 (global ? 69 : 63)); } - void opFetchMemberFloat (Compiler::Generator::CodeContainer& code) + void opFetchMemberFloat (Compiler::Generator::CodeContainer& code, bool global) { - code.push_back (Compiler::Generator::segment5 (64)); + code.push_back (Compiler::Generator::segment5 (global ? 70 : 64)); } void opRandom (Compiler::Generator::CodeContainer& code) @@ -738,7 +738,8 @@ namespace Compiler } void assignToMember (CodeContainer& code, Literals& literals, char localType, - const std::string& name, const std::string& id, const CodeContainer& value, char valueType) + const std::string& name, const std::string& id, const CodeContainer& value, + char valueType, bool global) { int index = literals.addString (name); @@ -766,17 +767,17 @@ namespace Compiler { case 'f': - opStoreMemberFloat (code); + opStoreMemberFloat (code, global); break; case 's': - opStoreMemberShort (code); + opStoreMemberShort (code, global); break; case 'l': - opStoreMemberLong (code); + opStoreMemberLong (code, global); break; default: @@ -786,7 +787,7 @@ namespace Compiler } void fetchMember (CodeContainer& code, Literals& literals, char localType, - const std::string& name, const std::string& id) + const std::string& name, const std::string& id, bool global) { int index = literals.addString (name); @@ -800,17 +801,17 @@ namespace Compiler { case 'f': - opFetchMemberFloat (code); + opFetchMemberFloat (code, global); break; case 's': - opFetchMemberShort (code); + opFetchMemberShort (code, global); break; case 'l': - opFetchMemberLong (code); + opFetchMemberLong (code, global); break; default: diff --git a/components/compiler/generator.hpp b/components/compiler/generator.hpp index feab26c93d..b511161225 100644 --- a/components/compiler/generator.hpp +++ b/components/compiler/generator.hpp @@ -102,10 +102,12 @@ namespace Compiler const std::string& name); void assignToMember (CodeContainer& code, Literals& literals, char memberType, - const std::string& name, const std::string& id, const CodeContainer& value, char valueType); + const std::string& name, const std::string& id, const CodeContainer& value, char valueType, bool global); + ///< \param global Member of a global script instead of a script of a reference. void fetchMember (CodeContainer& code, Literals& literals, char memberType, - const std::string& name, const std::string& id); + const std::string& name, const std::string& id, bool global); + ///< \param global Member of a global script instead of a script of a reference. void random (CodeContainer& code); diff --git a/components/compiler/lineparser.cpp b/components/compiler/lineparser.cpp index 368152fd93..5987a48031 100644 --- a/components/compiler/lineparser.cpp +++ b/components/compiler/lineparser.cpp @@ -113,12 +113,13 @@ namespace Compiler if (mState==SetMemberVarState) { mMemberName = name; - char type = getContext().getMemberType (mMemberName, mName); + std::pair type = getContext().getMemberType (mMemberName, mName); - if (type!=' ') + if (type.first!=' ') { mState = SetMemberVarState2; - mType = type; + mType = type.first; + mReferenceMember = type.second; return true; } @@ -353,7 +354,8 @@ namespace Compiler std::vector code; char type = mExprParser.append (code); - Generator::assignToMember (mCode, mLiterals, mType, mMemberName, mName, code, type); + Generator::assignToMember (mCode, mLiterals, mType, mMemberName, mName, code, type, + !mReferenceMember); mState = EndState; return true; diff --git a/components/compiler/lineparser.hpp b/components/compiler/lineparser.hpp index cf72f26a83..0aba30d4b5 100644 --- a/components/compiler/lineparser.hpp +++ b/components/compiler/lineparser.hpp @@ -33,6 +33,7 @@ namespace Compiler State mState; std::string mName; std::string mMemberName; + bool mReferenceMember; int mButtons; std::string mExplicit; char mType; diff --git a/components/interpreter/context.hpp b/components/interpreter/context.hpp index bdba7b6af9..97e4fad4fc 100644 --- a/components/interpreter/context.hpp +++ b/components/interpreter/context.hpp @@ -50,33 +50,33 @@ namespace Interpreter virtual void setGlobalFloat (const std::string& name, float value) = 0; virtual std::vector getGlobals () const = 0; - + virtual char getGlobalType (const std::string& name) const = 0; virtual std::string getActionBinding(const std::string& action) const = 0; - + virtual std::string getNPCName() const = 0; - + virtual std::string getNPCRace() const = 0; - + virtual std::string getNPCClass() const = 0; - + virtual std::string getNPCFaction() const = 0; - + virtual std::string getNPCRank() const = 0; virtual std::string getPCName() const = 0; - + virtual std::string getPCRace() const = 0; - + virtual std::string getPCClass() const = 0; - + virtual std::string getPCRank() const = 0; - + virtual std::string getPCNextRank() const = 0; - + virtual int getPCBounty() const = 0; - + virtual std::string getCurrentCellName() const = 0; virtual bool isScriptRunning (const std::string& name) const = 0; @@ -96,17 +96,17 @@ namespace Interpreter virtual void disable (const std::string& id = "") = 0; - virtual int getMemberShort (const std::string& id, const std::string& name) const = 0; + virtual int getMemberShort (const std::string& id, const std::string& name, bool global) const = 0; - virtual int getMemberLong (const std::string& id, const std::string& name) const = 0; + virtual int getMemberLong (const std::string& id, const std::string& name, bool global) const = 0; - virtual float getMemberFloat (const std::string& id, const std::string& name) const = 0; + virtual float getMemberFloat (const std::string& id, const std::string& name, bool global) const = 0; - virtual void setMemberShort (const std::string& id, const std::string& name, int value) = 0; + virtual void setMemberShort (const std::string& id, const std::string& name, int value, bool global) = 0; - virtual void setMemberLong (const std::string& id, const std::string& name, int value) = 0; + virtual void setMemberLong (const std::string& id, const std::string& name, int value, bool global) = 0; - virtual void setMemberFloat (const std::string& id, const std::string& name, float value) + virtual void setMemberFloat (const std::string& id, const std::string& name, float value, bool global) = 0; }; } diff --git a/components/interpreter/docs/vmformat.txt b/components/interpreter/docs/vmformat.txt index 91e0c060e7..990762268f 100644 --- a/components/interpreter/docs/vmformat.txt +++ b/components/interpreter/docs/vmformat.txt @@ -127,5 +127,11 @@ op 61: store stack[0] in member float stack[2] of object with ID stack[1] op 62: replace stack[0] with member short stack[1] of object with ID stack[0] op 63: replace stack[0] with member short stack[1] of object with ID stack[0] op 64: replace stack[0] with member short stack[1] of object with ID stack[0] -opcodes 65-33554431 unused +op 65: store stack[0] in member short stack[2] of global script with ID stack[1] +op 66: store stack[0] in member long stack[2] of global script with ID stack[1] +op 67: store stack[0] in member float stack[2] of global script with ID stack[1] +op 68: replace stack[0] with member short stack[1] of global script with ID stack[0] +op 69: replace stack[0] with member short stack[1] of global script with ID stack[0] +op 70: replace stack[0] with member short stack[1] of global script with ID stack[0] +opcodes 71-33554431 unused opcodes 33554432-67108863 reserved for extensions diff --git a/components/interpreter/installopcodes.cpp b/components/interpreter/installopcodes.cpp index 05f71f1cca..721cde3d8d 100644 --- a/components/interpreter/installopcodes.cpp +++ b/components/interpreter/installopcodes.cpp @@ -40,12 +40,18 @@ namespace Interpreter interpreter.installSegment5 (42, new OpFetchGlobalShort); interpreter.installSegment5 (43, new OpFetchGlobalLong); interpreter.installSegment5 (44, new OpFetchGlobalFloat); - interpreter.installSegment5 (59, new OpStoreMemberShort); - interpreter.installSegment5 (60, new OpStoreMemberLong); - interpreter.installSegment5 (61, new OpStoreMemberFloat); - interpreter.installSegment5 (62, new OpFetchMemberShort); - interpreter.installSegment5 (63, new OpFetchMemberLong); - interpreter.installSegment5 (64, new OpFetchMemberFloat); + interpreter.installSegment5 (59, new OpStoreMemberShort (false)); + interpreter.installSegment5 (60, new OpStoreMemberLong (false)); + interpreter.installSegment5 (61, new OpStoreMemberFloat (false)); + interpreter.installSegment5 (62, new OpFetchMemberShort (false)); + interpreter.installSegment5 (63, new OpFetchMemberLong (false)); + interpreter.installSegment5 (64, new OpFetchMemberFloat (false)); + interpreter.installSegment5 (65, new OpStoreMemberShort (true)); + interpreter.installSegment5 (66, new OpStoreMemberLong (true)); + interpreter.installSegment5 (67, new OpStoreMemberFloat (true)); + interpreter.installSegment5 (68, new OpFetchMemberShort (true)); + interpreter.installSegment5 (69, new OpFetchMemberLong (true)); + interpreter.installSegment5 (70, new OpFetchMemberFloat (true)); // math interpreter.installSegment5 (9, new OpAddInt); diff --git a/components/interpreter/localopcodes.hpp b/components/interpreter/localopcodes.hpp index 731c16276d..7844a9ea73 100644 --- a/components/interpreter/localopcodes.hpp +++ b/components/interpreter/localopcodes.hpp @@ -208,8 +208,12 @@ namespace Interpreter class OpStoreMemberShort : public Opcode0 { + bool mGlobal; + public: + OpStoreMemberShort (bool global) : mGlobal (global) {} + virtual void execute (Runtime& runtime) { Type_Integer data = runtime[0].mInteger; @@ -218,7 +222,7 @@ namespace Interpreter index = runtime[2].mInteger; std::string variable = runtime.getStringLiteral (index); - runtime.getContext().setMemberShort (id, variable, data); + runtime.getContext().setMemberShort (id, variable, data, mGlobal); runtime.pop(); runtime.pop(); @@ -228,8 +232,12 @@ namespace Interpreter class OpStoreMemberLong : public Opcode0 { + bool mGlobal; + public: + OpStoreMemberLong (bool global) : mGlobal (global) {} + virtual void execute (Runtime& runtime) { Type_Integer data = runtime[0].mInteger; @@ -238,7 +246,7 @@ namespace Interpreter index = runtime[2].mInteger; std::string variable = runtime.getStringLiteral (index); - runtime.getContext().setMemberLong (id, variable, data); + runtime.getContext().setMemberLong (id, variable, data, mGlobal); runtime.pop(); runtime.pop(); @@ -248,8 +256,12 @@ namespace Interpreter class OpStoreMemberFloat : public Opcode0 { + bool mGlobal; + public: + OpStoreMemberFloat (bool global) : mGlobal (global) {} + virtual void execute (Runtime& runtime) { Type_Float data = runtime[0].mFloat; @@ -258,7 +270,7 @@ namespace Interpreter index = runtime[2].mInteger; std::string variable = runtime.getStringLiteral (index); - runtime.getContext().setMemberFloat (id, variable, data); + runtime.getContext().setMemberFloat (id, variable, data, mGlobal); runtime.pop(); runtime.pop(); @@ -268,8 +280,12 @@ namespace Interpreter class OpFetchMemberShort : public Opcode0 { + bool mGlobal; + public: + OpFetchMemberShort (bool global) : mGlobal (global) {} + virtual void execute (Runtime& runtime) { Type_Integer index = runtime[0].mInteger; @@ -278,15 +294,19 @@ namespace Interpreter std::string variable = runtime.getStringLiteral (index); runtime.pop(); - int value = runtime.getContext().getMemberShort (id, variable); + int value = runtime.getContext().getMemberShort (id, variable, mGlobal); runtime[0].mInteger = value; } }; class OpFetchMemberLong : public Opcode0 { + bool mGlobal; + public: + OpFetchMemberLong (bool global) : mGlobal (global) {} + virtual void execute (Runtime& runtime) { Type_Integer index = runtime[0].mInteger; @@ -295,15 +315,19 @@ namespace Interpreter std::string variable = runtime.getStringLiteral (index); runtime.pop(); - int value = runtime.getContext().getMemberLong (id, variable); + int value = runtime.getContext().getMemberLong (id, variable, mGlobal); runtime[0].mInteger = value; } }; class OpFetchMemberFloat : public Opcode0 { + bool mGlobal; + public: + OpFetchMemberFloat (bool global) : mGlobal (global) {} + virtual void execute (Runtime& runtime) { Type_Integer index = runtime[0].mInteger; @@ -312,7 +336,7 @@ namespace Interpreter std::string variable = runtime.getStringLiteral (index); runtime.pop(); - float value = runtime.getContext().getMemberFloat (id, variable); + float value = runtime.getContext().getMemberFloat (id, variable, mGlobal); runtime[0].mFloat = value; } }; From 5c0071f3205b1e796bcb27a83e451d043a24bd6e Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Mon, 10 Feb 2014 14:59:20 +0100 Subject: [PATCH 10/47] fixed spelling of an error message --- components/compiler/generator.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/compiler/generator.cpp b/components/compiler/generator.cpp index 83e46d5f7b..c67e51e572 100644 --- a/components/compiler/generator.cpp +++ b/components/compiler/generator.cpp @@ -593,7 +593,7 @@ namespace Compiler else if (offset<0) opJumpBackward (code, -offset); else - throw std::logic_error ("inifite loop"); + throw std::logic_error ("infinite loop"); } void jumpOnZero (CodeContainer& code, int offset) From f26aa4f6455fe5e8b2fe110ba1a5df3a95a200db Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Tue, 11 Feb 2014 13:31:04 +0100 Subject: [PATCH 11/47] fixed while loop implementation --- components/compiler/controlparser.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/components/compiler/controlparser.cpp b/components/compiler/controlparser.cpp index 3be470c273..ba2db62b66 100644 --- a/components/compiler/controlparser.cpp +++ b/components/compiler/controlparser.cpp @@ -9,6 +9,7 @@ #include "generator.hpp" #include "errorhandler.hpp" +#include namespace Compiler { bool ControlParser::parseIfBody (int keyword, const TokenLoc& loc, Scanner& scanner) @@ -107,7 +108,7 @@ namespace Compiler Codes expr; mExprParser.append (expr); - Generator::jump (loop, -static_cast (mCodeBlock.size()-expr.size())); + Generator::jump (loop, -static_cast (mCodeBlock.size()+expr.size())); std::copy (expr.begin(), expr.end(), std::back_inserter (mCode)); @@ -121,7 +122,7 @@ namespace Compiler Codes loop2; - Generator::jump (loop2, -static_cast (mCodeBlock.size()-expr.size()-skip.size())); + Generator::jump (loop2, -static_cast (mCodeBlock.size()+expr.size()+skip.size())); if (loop.size()!=loop2.size()) throw std::logic_error ( From 9de2922d22c310ae41a6d80ae5374bc4e6296c2f Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Tue, 11 Feb 2014 13:56:56 +0100 Subject: [PATCH 12/47] fixed case problem in remote member variable access --- apps/openmw/mwscript/scriptmanagerimp.cpp | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/apps/openmw/mwscript/scriptmanagerimp.cpp b/apps/openmw/mwscript/scriptmanagerimp.cpp index 6862b9f830..11e094a843 100644 --- a/apps/openmw/mwscript/scriptmanagerimp.cpp +++ b/apps/openmw/mwscript/scriptmanagerimp.cpp @@ -7,12 +7,15 @@ #include #include -#include "../mwworld/esmstore.hpp" + +#include #include #include #include +#include "../mwworld/esmstore.hpp" + #include "extensions.hpp" namespace MWScript @@ -140,15 +143,17 @@ namespace MWScript Compiler::Locals& ScriptManager::getLocals (const std::string& name) { + std::string name2 = Misc::StringUtils::lowerCase (name); + { - ScriptCollection::iterator iter = mScripts.find (name); + ScriptCollection::iterator iter = mScripts.find (name2); if (iter!=mScripts.end()) return iter->second.second; } { - std::map::iterator iter = mOtherLocals.find (name); + std::map::iterator iter = mOtherLocals.find (name2); if (iter!=mOtherLocals.end()) return iter->second; @@ -156,7 +161,7 @@ namespace MWScript Compiler::Locals locals; - if (const ESM::Script *script = mStore.get().find (name)) + if (const ESM::Script *script = mStore.get().find (name2)) { int index = 0; @@ -170,7 +175,7 @@ namespace MWScript locals.declare ('f', script->mVarNames[index++]); std::map::iterator iter = - mOtherLocals.insert (std::make_pair (name, locals)).first; + mOtherLocals.insert (std::make_pair (name2, locals)).first; return iter->second; } From 697bda63719add550ef35d3144592f278b1b86c6 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Tue, 11 Feb 2014 14:55:31 +0100 Subject: [PATCH 13/47] allow (and discard) explicit reference on instructions that do not accept explicit references --- components/compiler/extensions.cpp | 4 ++-- components/compiler/extensions.hpp | 4 +++- components/compiler/lineparser.cpp | 17 ++++++++++++++++- 3 files changed, 21 insertions(+), 4 deletions(-) diff --git a/components/compiler/extensions.cpp b/components/compiler/extensions.cpp index c6a74b234b..6f5c2fc897 100644 --- a/components/compiler/extensions.cpp +++ b/components/compiler/extensions.cpp @@ -38,7 +38,7 @@ namespace Compiler } bool Extensions::isInstruction (int keyword, std::string& argumentType, - bool explicitReference) const + bool& explicitReference) const { std::map::const_iterator iter = mInstructions.find (keyword); @@ -46,7 +46,7 @@ namespace Compiler return false; if (explicitReference && iter->second.mCodeExplicit==-1) - return false; + explicitReference = false; argumentType = iter->second.mArguments; return true; diff --git a/components/compiler/extensions.hpp b/components/compiler/extensions.hpp index 53ebfa31b5..585c42681c 100644 --- a/components/compiler/extensions.hpp +++ b/components/compiler/extensions.hpp @@ -52,8 +52,10 @@ namespace Compiler /// types. bool isInstruction (int keyword, std::string& argumentType, - bool explicitReference) const; + bool& explicitReference) const; ///< Is this keyword registered with a function? If yes, return argument types. + /// \param explicitReference In: has explicit reference; Out: set to false, if + /// explicit reference is not available for this instruction. void registerFunction (const std::string& keyword, char returnType, const std::string& argumentType, int code, int codeExplicit = -1); diff --git a/components/compiler/lineparser.cpp b/components/compiler/lineparser.cpp index 5987a48031..3b27905d46 100644 --- a/components/compiler/lineparser.cpp +++ b/components/compiler/lineparser.cpp @@ -234,8 +234,15 @@ namespace Compiler { std::string argumentType; - if (extensions->isInstruction (keyword, argumentType, mState==ExplicitState)) + bool hasExplicit = mState==ExplicitState; + if (extensions->isInstruction (keyword, argumentType, hasExplicit)) { + if (!hasExplicit && mState==ExplicitState) + { + getErrorHandler().warning ("stray explicit reference (ignoring it)", loc); + mExplicit.clear(); + } + int optionals = mExprParser.parseArguments (argumentType, scanner, mCode, true); extensions->generateInstructionCode (keyword, mCode, mLiterals, mExplicit, optionals); @@ -271,6 +278,14 @@ namespace Compiler } } + if (mState==ExplicitState) + { + // drop stray explicit reference + getErrorHandler().warning ("stray explicit reference (ignoring it)", loc); + mState = BeginState; + mExplicit.clear(); + } + if (mState==BeginState) { switch (keyword) From 6a5d88b640c0ba26f8431e14e891411dcca505c2 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Wed, 12 Feb 2014 08:42:42 +0100 Subject: [PATCH 14/47] ignore stray else and endif in scripts --- components/compiler/lineparser.cpp | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/components/compiler/lineparser.cpp b/components/compiler/lineparser.cpp index 3b27905d46..4a5e1cbd09 100644 --- a/components/compiler/lineparser.cpp +++ b/components/compiler/lineparser.cpp @@ -332,6 +332,18 @@ namespace Compiler Generator::stopScript (mCode); mState = EndState; return true; + + case Scanner::K_else: + + getErrorHandler().warning ("stay else (ignoring it)", loc); + mState = EndState; + return true; + + case Scanner::K_endif: + + getErrorHandler().warning ("stay endif (ignoring it)", loc); + mState = EndState; + return true; } } else if (mState==SetLocalVarState && keyword==Scanner::K_to) From 61626e90da98641db5da0e33457977311ec30c6f Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Wed, 12 Feb 2014 08:53:37 +0100 Subject: [PATCH 15/47] allow additional string argument for stopcombat and addspell (ignored) --- components/compiler/exprparser.cpp | 25 ++++++++++++++----------- components/compiler/exprparser.hpp | 1 + components/compiler/extensions0.cpp | 4 ++-- 3 files changed, 17 insertions(+), 13 deletions(-) diff --git a/components/compiler/exprparser.cpp b/components/compiler/exprparser.cpp index 283da854c9..4af11ec2be 100644 --- a/components/compiler/exprparser.cpp +++ b/components/compiler/exprparser.cpp @@ -705,11 +705,11 @@ namespace Compiler { optional = true; } - else if (*iter=='S' || *iter=='c') + else if (*iter=='S' || *iter=='c' || *iter=='x') { stringParser.reset(); - if (optional) + if (optional || *iter=='x') stringParser.setOptional (true); if (*iter=='c') stringParser.smashCase(); @@ -718,18 +718,21 @@ namespace Compiler if (optional && stringParser.isEmpty()) break; - if (invert) + if (*iter!='x') { - std::vector tmp; - stringParser.append (tmp); + if (invert) + { + std::vector tmp; + stringParser.append (tmp); - stack.push (tmp); - } - else - stringParser.append (code); + stack.push (tmp); + } + else + stringParser.append (code); - if (optional) - ++optionalCount; + if (optional) + ++optionalCount; + } } else { diff --git a/components/compiler/exprparser.hpp b/components/compiler/exprparser.hpp index 8ce5409d23..905f0d454f 100644 --- a/components/compiler/exprparser.hpp +++ b/components/compiler/exprparser.hpp @@ -101,6 +101,7 @@ namespace Compiler /// \param arguments Each character represents one arguments ('l': integer, /// 'f': float, 'S': string, 'c': string (case smashed), '/': following arguments are /// optional) + /// 'x': optional string that will be ignored (die in a fire, MW script compiler!) /// \param invert Store arguments in reverted order. /// \return number of optional arguments }; diff --git a/components/compiler/extensions0.cpp b/components/compiler/extensions0.cpp index ebe46d2826..53f1baaf9d 100644 --- a/components/compiler/extensions0.cpp +++ b/components/compiler/extensions0.cpp @@ -62,7 +62,7 @@ namespace Compiler extensions.registerInstruction ("toggleai", "", opcodeToggleAI, opcodeToggleAI); extensions.registerInstruction ("tai", "", opcodeToggleAI, opcodeToggleAI); extensions.registerInstruction("startcombat", "c", opcodeStartCombat, opcodeStartCombatExplicit); - extensions.registerInstruction("stopcombat", "", opcodeStopCombat, opcodeStopCombatExplicit); + extensions.registerInstruction("stopcombat", "x", opcodeStopCombat, opcodeStopCombatExplicit); extensions.registerFunction ("gethello", 'l', "", opcodeGetHello, opcodeGetHelloExplicit); extensions.registerFunction ("getfight", 'l', "", opcodeGetFight, opcodeGetFightExplicit); extensions.registerFunction ("getflee", 'l', "", opcodeGetFlee, opcodeGetFleeExplicit); @@ -398,7 +398,7 @@ namespace Compiler extensions.registerInstruction ("setpccrimelevel", "f", opcodeSetPCCrimeLevel); extensions.registerInstruction ("modpccrimelevel", "f", opcodeModPCCrimeLevel); - extensions.registerInstruction ("addspell", "c", opcodeAddSpell, opcodeAddSpellExplicit); + extensions.registerInstruction ("addspell", "cx", opcodeAddSpell, opcodeAddSpellExplicit); extensions.registerInstruction ("removespell", "c", opcodeRemoveSpell, opcodeRemoveSpellExplicit); extensions.registerInstruction ("removespelleffects", "c", opcodeRemoveSpellEffects, From bfb0e62c4ab2fc3b6cb391e40ba8a70adc6c3c28 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Wed, 12 Feb 2014 09:10:05 +0100 Subject: [PATCH 16/47] ignore additional string argument after enable/disable --- components/compiler/lineparser.cpp | 14 +++++++++++--- components/compiler/lineparser.hpp | 2 +- 2 files changed, 12 insertions(+), 4 deletions(-) diff --git a/components/compiler/lineparser.cpp b/components/compiler/lineparser.cpp index 4a5e1cbd09..3b2b1f11b3 100644 --- a/components/compiler/lineparser.cpp +++ b/components/compiler/lineparser.cpp @@ -84,6 +84,13 @@ namespace Compiler bool LineParser::parseName (const std::string& name, const TokenLoc& loc, Scanner& scanner) { + if (mState==PotentialEndState) + { + getErrorHandler().warning ("stay string argument (ignoring it)", loc); + mState = EndState; + return true; + } + if (mState==SetState) { std::string name2 = Misc::StringUtils::lowerCase (name); @@ -219,13 +226,13 @@ namespace Compiler case Scanner::K_enable: Generator::enable (mCode, mLiterals, mExplicit); - mState = EndState; + mState = PotentialEndState; return true; case Scanner::K_disable: Generator::disable (mCode, mLiterals, mExplicit); - mState = EndState; + mState = PotentialEndState; return true; } @@ -406,7 +413,8 @@ namespace Compiler bool LineParser::parseSpecial (int code, const TokenLoc& loc, Scanner& scanner) { - if (code==Scanner::S_newline && (mState==EndState || mState==BeginState)) + if (code==Scanner::S_newline && + (mState==EndState || mState==BeginState || mState==PotentialEndState)) return false; if (code==Scanner::S_comma && mState==MessageState) diff --git a/components/compiler/lineparser.hpp b/components/compiler/lineparser.hpp index 0aba30d4b5..c54c764bce 100644 --- a/components/compiler/lineparser.hpp +++ b/components/compiler/lineparser.hpp @@ -23,7 +23,7 @@ namespace Compiler SetState, SetLocalVarState, SetGlobalVarState, SetPotentialMemberVarState, SetMemberVarState, SetMemberVarState2, MessageState, MessageCommaState, MessageButtonState, MessageButtonCommaState, - EndState, + EndState, PotentialEndState /* may have a stray string argument */, PotentialExplicitState, ExplicitState, MemberState }; From b1b0877122a21d48898b46ef49c3062168a5b8fc Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Wed, 12 Feb 2014 09:14:32 +0100 Subject: [PATCH 17/47] allow additional numeric argument for AiFollow and ignore it --- components/compiler/extensions0.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/compiler/extensions0.cpp b/components/compiler/extensions0.cpp index 53f1baaf9d..5079a6064e 100644 --- a/components/compiler/extensions0.cpp +++ b/components/compiler/extensions0.cpp @@ -41,7 +41,7 @@ namespace Compiler opcodeAiEscortCellExplicit); extensions.registerInstruction ("aiwander", "fff/llllllllll", opcodeAiWander, opcodeAiWanderExplicit); - extensions.registerInstruction ("aifollow", "cffff/l", opcodeAiFollow, + extensions.registerInstruction ("aifollow", "cffff/ll", opcodeAiFollow, opcodeAiFollowExplicit); extensions.registerInstruction ("aifollowcell", "ccffff/l", opcodeAiFollowCell, opcodeAiFollowCellExplicit); From c0a6acfe6cb7cf3ea6277c2539de571d6e55ad1e Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Wed, 12 Feb 2014 09:23:23 +0100 Subject: [PATCH 18/47] allow the use of keywords as variable names in more places --- components/compiler/lineparser.cpp | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/components/compiler/lineparser.cpp b/components/compiler/lineparser.cpp index 3b2b1f11b3..3ae24bfb75 100644 --- a/components/compiler/lineparser.cpp +++ b/components/compiler/lineparser.cpp @@ -219,6 +219,12 @@ namespace Compiler bool LineParser::parseKeyword (int keyword, const TokenLoc& loc, Scanner& scanner) { + if (mState==SetState) + { + // allow keywords to be used as variable names when assigning a value to a variable. + return parseName (loc.mLiteral, loc, scanner); + } + if (mState==BeginState || mState==ExplicitState) { switch (keyword) From 93d47430125be4d766d6937541ba826138a790a2 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Wed, 12 Feb 2014 09:56:25 +0100 Subject: [PATCH 19/47] interpret instruction keywords as names within expressions --- components/compiler/exprparser.cpp | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/components/compiler/exprparser.cpp b/components/compiler/exprparser.cpp index 4af11ec2be..319bb44988 100644 --- a/components/compiler/exprparser.cpp +++ b/components/compiler/exprparser.cpp @@ -344,6 +344,17 @@ namespace Compiler bool ExprParser::parseKeyword (int keyword, const TokenLoc& loc, Scanner& scanner) { + if (const Extensions *extensions = getContext().getExtensions()) + { + std::string argumentType; // ignored + bool hasExplicit = false; // ignored + if (extensions->isInstruction (keyword, argumentType, hasExplicit)) + { + // pretend this is not a keyword + return parseName (loc.mLiteral, loc, scanner); + } + } + mFirst = false; if (!mExplicit.empty()) From 388735046fdb75b34744f1c292a8a349f4ab4f40 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Wed, 12 Feb 2014 13:35:24 +0100 Subject: [PATCH 20/47] fixed broken remote member variable access --- apps/openmw/mwscript/interpretercontext.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/apps/openmw/mwscript/interpretercontext.cpp b/apps/openmw/mwscript/interpretercontext.cpp index 17092b41ca..b79808d08b 100644 --- a/apps/openmw/mwscript/interpretercontext.cpp +++ b/apps/openmw/mwscript/interpretercontext.cpp @@ -66,7 +66,7 @@ namespace MWScript { const MWWorld::Ptr ptr = getReference (id, false); - std::string id = MWWorld::Class::get (ptr).getScript (ptr); + id = MWWorld::Class::get (ptr).getScript (ptr); ptr.getRefData().setLocals ( *MWBase::Environment::get().getWorld()->getStore().get().find (id)); @@ -86,7 +86,7 @@ namespace MWScript { const MWWorld::Ptr ptr = getReference (id, false); - std::string id = MWWorld::Class::get (ptr).getScript (ptr); + id = MWWorld::Class::get (ptr).getScript (ptr); ptr.getRefData().setLocals ( *MWBase::Environment::get().getWorld()->getStore().get().find (id)); From dc433a3c093c1a060e2c71c31a9d09a061834093 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Wed, 12 Feb 2014 13:38:16 +0100 Subject: [PATCH 21/47] fixed case handling problem for local variable access --- apps/openmw/mwscript/scriptmanagerimp.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/apps/openmw/mwscript/scriptmanagerimp.cpp b/apps/openmw/mwscript/scriptmanagerimp.cpp index 11e094a843..5e18151da4 100644 --- a/apps/openmw/mwscript/scriptmanagerimp.cpp +++ b/apps/openmw/mwscript/scriptmanagerimp.cpp @@ -221,8 +221,10 @@ namespace MWScript throw std::runtime_error ("invalid variable type"); } + std::string variable2 = Misc::StringUtils::lowerCase (variable); + for (int i=0; imVarNames.at (i+offset)==variable) + if (Misc::StringUtils::lowerCase (script->mVarNames.at (i+offset))==variable2) return i; throw std::runtime_error ("unable to access local variable " + variable + " of " + scriptId); From 6e2e4d1adf9000a81a49c3f7f1bee2245edf933d Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Wed, 12 Feb 2014 13:45:01 +0100 Subject: [PATCH 22/47] ignore stray begin --- components/compiler/lineparser.cpp | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/components/compiler/lineparser.cpp b/components/compiler/lineparser.cpp index 3ae24bfb75..1407d0e956 100644 --- a/components/compiler/lineparser.cpp +++ b/components/compiler/lineparser.cpp @@ -357,6 +357,12 @@ namespace Compiler getErrorHandler().warning ("stay endif (ignoring it)", loc); mState = EndState; return true; + + case Scanner::K_begin: + + getErrorHandler().warning ("stay begin (ignoring it)", loc); + mState = EndState; + return true; } } else if (mState==SetLocalVarState && keyword==Scanner::K_to) From a85d3c7dcb52db79ad8ab0314063e134153e6742 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Wed, 12 Feb 2014 13:53:59 +0100 Subject: [PATCH 23/47] ignore unused explicit references for functions --- components/compiler/exprparser.cpp | 13 +++++++++++-- components/compiler/extensions.cpp | 4 ++-- components/compiler/extensions.hpp | 4 +++- components/compiler/lineparser.cpp | 11 +++++++++-- 4 files changed, 25 insertions(+), 7 deletions(-) diff --git a/components/compiler/exprparser.cpp b/components/compiler/exprparser.cpp index 319bb44988..07f576006f 100644 --- a/components/compiler/exprparser.cpp +++ b/components/compiler/exprparser.cpp @@ -397,8 +397,15 @@ namespace Compiler char returnType; std::string argumentType; - if (extensions->isFunction (keyword, returnType, argumentType, true)) + bool hasExplicit = true; + if (extensions->isFunction (keyword, returnType, argumentType, hasExplicit)) { + if (!hasExplicit) + { + getErrorHandler().warning ("stray explicit reference (ignoring it)", loc); + mExplicit.clear(); + } + start(); mTokenLoc = loc; @@ -519,7 +526,9 @@ namespace Compiler char returnType; std::string argumentType; - if (extensions->isFunction (keyword, returnType, argumentType, false)) + bool hasExplicit = false; + + if (extensions->isFunction (keyword, returnType, argumentType, hasExplicit)) { mTokenLoc = loc; int optionals = parseArguments (argumentType, scanner); diff --git a/components/compiler/extensions.cpp b/components/compiler/extensions.cpp index 6f5c2fc897..c09abcbafd 100644 --- a/components/compiler/extensions.cpp +++ b/components/compiler/extensions.cpp @@ -22,7 +22,7 @@ namespace Compiler } bool Extensions::isFunction (int keyword, char& returnType, std::string& argumentType, - bool explicitReference) const + bool& explicitReference) const { std::map::const_iterator iter = mFunctions.find (keyword); @@ -30,7 +30,7 @@ namespace Compiler return false; if (explicitReference && iter->second.mCodeExplicit==-1) - return false; + explicitReference = false; returnType = iter->second.mReturn; argumentType = iter->second.mArguments; diff --git a/components/compiler/extensions.hpp b/components/compiler/extensions.hpp index 585c42681c..79cfed9e86 100644 --- a/components/compiler/extensions.hpp +++ b/components/compiler/extensions.hpp @@ -47,9 +47,11 @@ namespace Compiler /// - keyword must be all lower case. bool isFunction (int keyword, char& returnType, std::string& argumentType, - bool explicitReference) const; + bool& explicitReference) const; ///< Is this keyword registered with a function? If yes, return return and argument /// types. + /// \param explicitReference In: has explicit reference; Out: set to false, if + /// explicit reference is not available for this instruction. bool isInstruction (int keyword, std::string& argumentType, bool& explicitReference) const; diff --git a/components/compiler/lineparser.cpp b/components/compiler/lineparser.cpp index 1407d0e956..e435b936c3 100644 --- a/components/compiler/lineparser.cpp +++ b/components/compiler/lineparser.cpp @@ -279,9 +279,16 @@ namespace Compiler char returnType; std::string argumentType; - if (extensions->isFunction (keyword, returnType, argumentType, - !mExplicit.empty())) + bool hasExplicit = !mExplicit.empty(); + + if (extensions->isFunction (keyword, returnType, argumentType, hasExplicit)) { + if (!hasExplicit && !mExplicit.empty()) + { + getErrorHandler().warning ("stray explicit reference (ignoring it)", loc); + mExplicit.clear(); + } + scanner.putbackKeyword (keyword, loc); parseExpression (scanner, loc); mState = EndState; From b3412b7eec1c19ae427201c544d778d18cff7a1a Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Wed, 12 Feb 2014 15:22:17 +0100 Subject: [PATCH 24/47] another case fix (remote member access again) --- apps/openmw/mwscript/compilercontext.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/apps/openmw/mwscript/compilercontext.cpp b/apps/openmw/mwscript/compilercontext.cpp index 8018b86e02..1b3e769bf1 100644 --- a/apps/openmw/mwscript/compilercontext.cpp +++ b/apps/openmw/mwscript/compilercontext.cpp @@ -52,7 +52,8 @@ namespace MWScript char type = ' '; if (!script.empty()) - type = MWBase::Environment::get().getScriptManager()->getLocals (script).getType (name); + type = MWBase::Environment::get().getScriptManager()->getLocals (script).getType ( + Misc::StringUtils::lowerCase (name)); return std::make_pair (type, reference); } From 749136bf3394df4498eb1f672313124b3365c1cc Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Wed, 12 Feb 2014 20:23:47 +0100 Subject: [PATCH 25/47] ignore attempts to set non-existing variables --- components/compiler/lineparser.cpp | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/components/compiler/lineparser.cpp b/components/compiler/lineparser.cpp index e435b936c3..495e7e25e5 100644 --- a/components/compiler/lineparser.cpp +++ b/components/compiler/lineparser.cpp @@ -219,6 +219,14 @@ namespace Compiler bool LineParser::parseKeyword (int keyword, const TokenLoc& loc, Scanner& scanner) { + if (mState==SetPotentialMemberVarState && keyword==Scanner::K_to) + { + getErrorHandler().warning ("unknown variable (ignoring set instruction)", loc); + SkipParser skip (getErrorHandler(), getContext()); + scanner.scan (skip); + return false; + } + if (mState==SetState) { // allow keywords to be used as variable names when assigning a value to a variable. From 2eeb0eb4f3fcc60ee206b7fb53786a66a3d2d04c Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Thu, 13 Feb 2014 08:38:26 +0100 Subject: [PATCH 26/47] allow lines to continue with other instructions after an legit else --- components/compiler/controlparser.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/compiler/controlparser.cpp b/components/compiler/controlparser.cpp index ba2db62b66..60d17a8216 100644 --- a/components/compiler/controlparser.cpp +++ b/components/compiler/controlparser.cpp @@ -72,7 +72,7 @@ namespace Compiler } else if (keyword==Scanner::K_else) { - mState = IfElseEndState; + mState = IfElseBodyState; /// \todo should be IfElseEndState; add an option for that } return true; From 0313876d88f9eb55c8ed43a9b79787ec17866b05 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Thu, 13 Feb 2014 08:49:40 +0100 Subject: [PATCH 27/47] allow leaving out if in a top-level if-statement --- components/compiler/scriptparser.cpp | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/components/compiler/scriptparser.cpp b/components/compiler/scriptparser.cpp index 1b613595a6..f34313969a 100644 --- a/components/compiler/scriptparser.cpp +++ b/components/compiler/scriptparser.cpp @@ -71,6 +71,12 @@ namespace Compiler if (code==Scanner::S_newline) // empty line return true; + if (code==Scanner::S_open) /// \todo Option to switch this off + { + scanner.putbackSpecial (code, loc); + return parseKeyword (Scanner::K_if, loc, scanner); + } + mLineParser.reset(); if (mLineParser.parseSpecial (code, loc, scanner)) scanner.scan (mLineParser); From c03bd8ebb6c3b18869c75350f1c276ed03dfdb0e Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Thu, 13 Feb 2014 08:59:33 +0100 Subject: [PATCH 28/47] allow [] as aliases for () --- components/compiler/scanner.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/components/compiler/scanner.cpp b/components/compiler/scanner.cpp index 816443c447..46e50a2e9b 100644 --- a/components/compiler/scanner.cpp +++ b/components/compiler/scanner.cpp @@ -370,9 +370,9 @@ namespace Compiler if (c=='\n') special = S_newline; - else if (c=='(') + else if (c=='(' || c=='[') /// \todo option to disable the use of [ as alias for ( special = S_open; - else if (c==')') + else if (c==')' || c==']') /// \todo option to disable the use of ] as alias for ) special = S_close; else if (c=='.') { From 87b51e47a9d1357d3e1c6968ea3add6ddd58d8d5 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Thu, 13 Feb 2014 09:40:07 +0100 Subject: [PATCH 29/47] fixed another case issue in remote member access --- components/compiler/controlparser.cpp | 1 - components/compiler/locals.cpp | 4 +++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/components/compiler/controlparser.cpp b/components/compiler/controlparser.cpp index 60d17a8216..499358ca02 100644 --- a/components/compiler/controlparser.cpp +++ b/components/compiler/controlparser.cpp @@ -9,7 +9,6 @@ #include "generator.hpp" #include "errorhandler.hpp" -#include namespace Compiler { bool ControlParser::parseIfBody (int keyword, const TokenLoc& loc, Scanner& scanner) diff --git a/components/compiler/locals.cpp b/components/compiler/locals.cpp index e2b1c5c966..60a5704bf3 100644 --- a/components/compiler/locals.cpp +++ b/components/compiler/locals.cpp @@ -7,6 +7,8 @@ #include #include +#include + namespace Compiler { const std::vector& Locals::get (char type) const @@ -97,7 +99,7 @@ namespace Compiler void Locals::declare (char type, const std::string& name) { - get (type).push_back (name); + get (type).push_back (Misc::StringUtils::lowerCase (name)); } void Locals::clear() From dde4fbd8184211700be7d5e5bd1651acafeeb1cb Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Thu, 13 Feb 2014 09:52:44 +0100 Subject: [PATCH 30/47] allow one more integer argument in RemoveSoulGem and up to 6 more in AiFollow and then throw them all away --- apps/openmw/mwscript/docs/vmformat.txt | 8 +++++--- apps/openmw/mwscript/miscextensions.cpp | 12 ++++++++---- components/compiler/extensions0.cpp | 4 ++-- components/compiler/opcodes.hpp | 4 ++-- 4 files changed, 17 insertions(+), 11 deletions(-) diff --git a/apps/openmw/mwscript/docs/vmformat.txt b/apps/openmw/mwscript/docs/vmformat.txt index 2fe4c768ba..70186a089b 100644 --- a/apps/openmw/mwscript/docs/vmformat.txt +++ b/apps/openmw/mwscript/docs/vmformat.txt @@ -52,7 +52,9 @@ op 0x20023: AiFollow, explicit reference op 0x20024: AiFollowCell op 0x20025: AiFollowCell, explicit reference op 0x20026: ModRegion -opcodes 0x20027-0x3ffff unused +op 0x20027: RemoveSoulGem +op 0x20028: RemoveSoulGem, explicit reference +opcodes 0x20029-0x3ffff unused Segment 4: (not implemented yet) @@ -308,8 +310,8 @@ op 0x20001f1: GetDetected op 0x20001f2: GetDetected, explicit reference op 0x20001f3: AddSoulGem op 0x20001f4: AddSoulGem, explicit reference -op 0x20001f5: RemoveSoulGem -op 0x20001f6: RemoveSoulGem, explicit reference +op 0x20001f5: unused +op 0x20001f6: unused op 0x20001f7: PlayBink op 0x20001f8: Drop op 0x20001f9: Drop, explicit reference diff --git a/apps/openmw/mwscript/miscextensions.cpp b/apps/openmw/mwscript/miscextensions.cpp index aa0e775af2..0c60e1c940 100644 --- a/apps/openmw/mwscript/miscextensions.cpp +++ b/apps/openmw/mwscript/miscextensions.cpp @@ -365,17 +365,21 @@ namespace MWScript }; template - class OpRemoveSoulGem : public Interpreter::Opcode0 + class OpRemoveSoulGem : public Interpreter::Opcode1 { public: - virtual void execute (Interpreter::Runtime& runtime) + virtual void execute (Interpreter::Runtime& runtime, unsigned int arg0) { MWWorld::Ptr ptr = R()(runtime); std::string soul = runtime.getStringLiteral (runtime[0].mInteger); runtime.pop(); + // throw away additional arguments + for (unsigned int i=0; i); interpreter.installSegment5 (Compiler::Misc::opcodeAddSoulGem, new OpAddSoulGem); interpreter.installSegment5 (Compiler::Misc::opcodeAddSoulGemExplicit, new OpAddSoulGem); - interpreter.installSegment5 (Compiler::Misc::opcodeRemoveSoulGem, new OpRemoveSoulGem); - interpreter.installSegment5 (Compiler::Misc::opcodeRemoveSoulGemExplicit, new OpRemoveSoulGem); + interpreter.installSegment3 (Compiler::Misc::opcodeRemoveSoulGem, new OpRemoveSoulGem); + interpreter.installSegment3 (Compiler::Misc::opcodeRemoveSoulGemExplicit, new OpRemoveSoulGem); interpreter.installSegment5 (Compiler::Misc::opcodeDrop, new OpDrop); interpreter.installSegment5 (Compiler::Misc::opcodeDropExplicit, new OpDrop); interpreter.installSegment5 (Compiler::Misc::opcodeDropSoulGem, new OpDropSoulGem); diff --git a/components/compiler/extensions0.cpp b/components/compiler/extensions0.cpp index 5079a6064e..78b6409f22 100644 --- a/components/compiler/extensions0.cpp +++ b/components/compiler/extensions0.cpp @@ -41,7 +41,7 @@ namespace Compiler opcodeAiEscortCellExplicit); extensions.registerInstruction ("aiwander", "fff/llllllllll", opcodeAiWander, opcodeAiWanderExplicit); - extensions.registerInstruction ("aifollow", "cffff/ll", opcodeAiFollow, + extensions.registerInstruction ("aifollow", "cffff/llllllll", opcodeAiFollow, opcodeAiFollowExplicit); extensions.registerInstruction ("aifollowcell", "ccffff/l", opcodeAiFollowCell, opcodeAiFollowCellExplicit); @@ -253,7 +253,7 @@ namespace Compiler extensions.registerFunction ("getlocked", 'l', "", opcodeGetLocked, opcodeGetLockedExplicit); extensions.registerFunction ("geteffect", 'l', "S", opcodeGetEffect, opcodeGetEffectExplicit); extensions.registerInstruction ("addsoulgem", "cc", opcodeAddSoulGem, opcodeAddSoulGemExplicit); - extensions.registerInstruction ("removesoulgem", "c", opcodeRemoveSoulGem, opcodeRemoveSoulGemExplicit); + extensions.registerInstruction ("removesoulgem", "c/l", opcodeRemoveSoulGem, opcodeRemoveSoulGemExplicit); extensions.registerInstruction ("drop", "cl", opcodeDrop, opcodeDropExplicit); extensions.registerInstruction ("dropsoulgem", "c", opcodeDropSoulGem, opcodeDropSoulGemExplicit); extensions.registerFunction ("getattacked", 'l', "", opcodeGetAttacked, opcodeGetAttackedExplicit); diff --git a/components/compiler/opcodes.hpp b/components/compiler/opcodes.hpp index 583cf4eea3..1dbdbf7e72 100644 --- a/components/compiler/opcodes.hpp +++ b/components/compiler/opcodes.hpp @@ -203,8 +203,8 @@ namespace Compiler const int opcodeGetEffectExplicit = 0x20001d0; const int opcodeAddSoulGem = 0x20001f3; const int opcodeAddSoulGemExplicit = 0x20001f4; - const int opcodeRemoveSoulGem = 0x20001f5; - const int opcodeRemoveSoulGemExplicit = 0x20001f6; + const int opcodeRemoveSoulGem = 0x20027; + const int opcodeRemoveSoulGemExplicit = 0x20028; const int opcodeDrop = 0x20001f8; const int opcodeDropExplicit = 0x20001f9; const int opcodeDropSoulGem = 0x20001fa; From ac8290c4d3b329073a49369fde82a33d023998a2 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Thu, 13 Feb 2014 09:59:22 +0100 Subject: [PATCH 31/47] fixed problem with line endings in case of a local variable redeclaration --- components/compiler/declarationparser.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/components/compiler/declarationparser.cpp b/components/compiler/declarationparser.cpp index 586b28bc29..9c4e4f631b 100644 --- a/components/compiler/declarationparser.cpp +++ b/components/compiler/declarationparser.cpp @@ -27,8 +27,7 @@ bool Compiler::DeclarationParser::parseName (const std::string& name, const Toke /// \todo add option to make re-declared local variables an error getErrorHandler().warning ("can't re-declare local variable (ignoring declaration)", loc); - SkipParser skip (getErrorHandler(), getContext()); - scanner.scan (skip); + mState = State_End; return true; } From 309573a3ac01f38fe27ce3a3d00b2e0e90187814 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Thu, 13 Feb 2014 14:15:48 +0100 Subject: [PATCH 32/47] allow the use of the keyword end as a variable name in an expression --- components/compiler/exprparser.cpp | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/components/compiler/exprparser.cpp b/components/compiler/exprparser.cpp index 07f576006f..474de856a4 100644 --- a/components/compiler/exprparser.cpp +++ b/components/compiler/exprparser.cpp @@ -355,6 +355,11 @@ namespace Compiler } } + if (keyword==Scanner::K_end) + { + return parseName (loc.mLiteral, loc, scanner); + } + mFirst = false; if (!mExplicit.empty()) From f7ff4fbd51178825a1199ae4b5a5b7cabc765e16 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Thu, 13 Feb 2014 15:31:07 +0100 Subject: [PATCH 33/47] allow disable as an alias for getDisabled (in most cases) --- components/compiler/exprparser.cpp | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/components/compiler/exprparser.cpp b/components/compiler/exprparser.cpp index 474de856a4..6b451292a9 100644 --- a/components/compiler/exprparser.cpp +++ b/components/compiler/exprparser.cpp @@ -366,7 +366,8 @@ namespace Compiler { if (mRefOp && mNextOperand) { - if (keyword==Scanner::K_getdisabled) + if (keyword==Scanner::K_getdisabled || + keyword==Scanner::K_disable) /// \todo add option to disable this { start(); @@ -509,7 +510,8 @@ namespace Compiler mNextOperand = false; return true; } - else if (keyword==Scanner::K_getdisabled) + else if (keyword==Scanner::K_getdisabled || + keyword==Scanner::K_disable) /// \todo add option to disable this { start(); From b01c6dad375375864f5b667b9d31ce8b310ff482 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Fri, 14 Feb 2014 08:29:18 +0100 Subject: [PATCH 34/47] Revert "allow disable as an alias for getDisabled (in most cases)" This reverts commit f7ff4fbd51178825a1199ae4b5a5b7cabc765e16. --- components/compiler/exprparser.cpp | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/components/compiler/exprparser.cpp b/components/compiler/exprparser.cpp index 6b451292a9..474de856a4 100644 --- a/components/compiler/exprparser.cpp +++ b/components/compiler/exprparser.cpp @@ -366,8 +366,7 @@ namespace Compiler { if (mRefOp && mNextOperand) { - if (keyword==Scanner::K_getdisabled || - keyword==Scanner::K_disable) /// \todo add option to disable this + if (keyword==Scanner::K_getdisabled) { start(); @@ -510,8 +509,7 @@ namespace Compiler mNextOperand = false; return true; } - else if (keyword==Scanner::K_getdisabled || - keyword==Scanner::K_disable) /// \todo add option to disable this + else if (keyword==Scanner::K_getdisabled) { start(); From 2086ebe4104a00d00ede72c174138640a43948fa Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Fri, 14 Feb 2014 08:48:26 +0100 Subject: [PATCH 35/47] fix for inappropriate disable (2nd attempt) --- components/compiler/exprparser.cpp | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/components/compiler/exprparser.cpp b/components/compiler/exprparser.cpp index 474de856a4..7d310617ce 100644 --- a/components/compiler/exprparser.cpp +++ b/components/compiler/exprparser.cpp @@ -355,7 +355,16 @@ namespace Compiler } } - if (keyword==Scanner::K_end) + if (keyword==Scanner::K_end || keyword==Scanner::K_begin || + keyword==Scanner::K_short || keyword==Scanner::K_long || + keyword==Scanner::K_float || keyword==Scanner::K_if || + keyword==Scanner::K_endif || keyword==Scanner::K_else || + keyword==Scanner::K_elseif || keyword==Scanner::K_while || + keyword==Scanner::K_endwhile || keyword==Scanner::K_return || + keyword==Scanner::K_messagebox || keyword==Scanner::K_set || + keyword==Scanner::K_to || keyword==Scanner::K_startscript || + keyword==Scanner::K_stopscript || keyword==Scanner::K_enable || + keyword==Scanner::K_disable) { return parseName (loc.mLiteral, loc, scanner); } From e76ef9266995a83fad40f3ebc2b74a54d5d6ff17 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Fri, 14 Feb 2014 09:06:06 +0100 Subject: [PATCH 36/47] also allow the use of keywords as remote local variables in set statements --- components/compiler/lineparser.cpp | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/components/compiler/lineparser.cpp b/components/compiler/lineparser.cpp index 495e7e25e5..b1956e6283 100644 --- a/components/compiler/lineparser.cpp +++ b/components/compiler/lineparser.cpp @@ -219,6 +219,20 @@ namespace Compiler bool LineParser::parseKeyword (int keyword, const TokenLoc& loc, Scanner& scanner) { + if (mState==SetMemberVarState) + { + mMemberName = loc.mLiteral; + std::pair type = getContext().getMemberType (mMemberName, mName); + + if (type.first!=' ') + { + mState = SetMemberVarState2; + mType = type.first; + mReferenceMember = type.second; + return true; + } + } + if (mState==SetPotentialMemberVarState && keyword==Scanner::K_to) { getErrorHandler().warning ("unknown variable (ignoring set instruction)", loc); From 451e1f413ba33170ba01e96788443a51b1c5a113 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Fri, 14 Feb 2014 11:15:16 +0100 Subject: [PATCH 37/47] instead of using pre-compiled variable lists for remote member access get the variable list from the remote script on the fly --- apps/openmw/mwscript/scriptmanagerimp.cpp | 17 +++----- components/CMakeLists.txt | 1 + components/compiler/declarationparser.cpp | 5 +++ components/compiler/declarationparser.hpp | 2 + components/compiler/quickfileparser.cpp | 52 +++++++++++++++++++++++ components/compiler/quickfileparser.hpp | 39 +++++++++++++++++ 6 files changed, 105 insertions(+), 11 deletions(-) create mode 100644 components/compiler/quickfileparser.cpp create mode 100644 components/compiler/quickfileparser.hpp diff --git a/apps/openmw/mwscript/scriptmanagerimp.cpp b/apps/openmw/mwscript/scriptmanagerimp.cpp index 5e18151da4..74c85dbbf7 100644 --- a/apps/openmw/mwscript/scriptmanagerimp.cpp +++ b/apps/openmw/mwscript/scriptmanagerimp.cpp @@ -13,6 +13,7 @@ #include #include #include +#include #include "../mwworld/esmstore.hpp" @@ -159,20 +160,14 @@ namespace MWScript return iter->second; } - Compiler::Locals locals; - if (const ESM::Script *script = mStore.get().find (name2)) { - int index = 0; - - for (int i=0; imData.mNumShorts; ++i) - locals.declare ('s', script->mVarNames[index++]); - - for (int i=0; imData.mNumLongs; ++i) - locals.declare ('l', script->mVarNames[index++]); + Compiler::Locals locals; - for (int i=0; imData.mNumFloats; ++i) - locals.declare ('f', script->mVarNames[index++]); + std::istringstream stream (script->mScriptText); + Compiler::QuickFileParser parser (mErrorHandler, mCompilerContext, locals); + Compiler::Scanner scanner (mErrorHandler, stream, mCompilerContext.getExtensions()); + scanner.scan (parser); std::map::iterator iter = mOtherLocals.insert (std::make_pair (name2, locals)).first; diff --git a/components/CMakeLists.txt b/components/CMakeLists.txt index fbe9ad5bd3..45a91f368c 100644 --- a/components/CMakeLists.txt +++ b/components/CMakeLists.txt @@ -60,6 +60,7 @@ add_component_dir (compiler context controlparser errorhandler exception exprparser extensions fileparser generator lineparser literals locals output parser scanner scriptparser skipparser streamerrorhandler stringparser tokenloc nullerrorhandler opcodes extensions0 declarationparser + quickfileparser ) add_component_dir (interpreter diff --git a/components/compiler/declarationparser.cpp b/components/compiler/declarationparser.cpp index 9c4e4f631b..357f0259be 100644 --- a/components/compiler/declarationparser.cpp +++ b/components/compiler/declarationparser.cpp @@ -75,4 +75,9 @@ bool Compiler::DeclarationParser::parseSpecial (int code, const TokenLoc& loc, S return false; return Parser::parseSpecial (code, loc, scanner); +} + +void Compiler::DeclarationParser::reset() +{ + mState = State_Begin; } \ No newline at end of file diff --git a/components/compiler/declarationparser.hpp b/components/compiler/declarationparser.hpp index 3e0ac57c34..f85b31ba15 100644 --- a/components/compiler/declarationparser.hpp +++ b/components/compiler/declarationparser.hpp @@ -35,6 +35,8 @@ namespace Compiler ///< Handle a special character token. /// \return fetch another token? + void reset(); + }; } diff --git a/components/compiler/quickfileparser.cpp b/components/compiler/quickfileparser.cpp new file mode 100644 index 0000000000..157e152490 --- /dev/null +++ b/components/compiler/quickfileparser.cpp @@ -0,0 +1,52 @@ + +#include "quickfileparser.hpp" + +#include "skipparser.hpp" +#include "scanner.hpp" + +Compiler::QuickFileParser::QuickFileParser (ErrorHandler& errorHandler, Context& context, + Locals& locals) +: Parser (errorHandler, context), mDeclarationParser (errorHandler, context, locals) +{} + +bool Compiler::QuickFileParser::parseName (const std::string& name, const TokenLoc& loc, + Scanner& scanner) +{ + SkipParser skip (getErrorHandler(), getContext()); + scanner.scan (skip); + return true; +} + +bool Compiler::QuickFileParser::parseKeyword (int keyword, const TokenLoc& loc, Scanner& scanner) +{ + if (keyword==Scanner::K_end) + return false; + + if (keyword==Scanner::K_short || keyword==Scanner::K_long || keyword==Scanner::K_float) + { + mDeclarationParser.reset(); + scanner.putbackKeyword (keyword, loc); + scanner.scan (mDeclarationParser); + return true; + } + + SkipParser skip (getErrorHandler(), getContext()); + scanner.scan (skip); + return true; +} + +bool Compiler::QuickFileParser::parseSpecial (int code, const TokenLoc& loc, Scanner& scanner) +{ + if (code!=Scanner::S_newline) + { + SkipParser skip (getErrorHandler(), getContext()); + scanner.scan (skip); + } + + return true; +} + +void Compiler::QuickFileParser::parseEOF (Scanner& scanner) +{ + +} \ No newline at end of file diff --git a/components/compiler/quickfileparser.hpp b/components/compiler/quickfileparser.hpp new file mode 100644 index 0000000000..d2dfafb346 --- /dev/null +++ b/components/compiler/quickfileparser.hpp @@ -0,0 +1,39 @@ +#ifndef COMPILER_QUICKFILEPARSER_H_INCLUDED +#define COMPILER_QUICKFILEPARSER_H_INCLUDED + +#include "parser.hpp" +#include "declarationparser.hpp" + +namespace Compiler +{ + class Locals; + + /// \brief File parser variant that ignores everything but variable declarations + class QuickFileParser : public Parser + { + DeclarationParser mDeclarationParser; + + public: + + QuickFileParser (ErrorHandler& errorHandler, Context& context, Locals& locals); + + 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? + + virtual bool parseSpecial (int code, const TokenLoc& loc, Scanner& scanner); + ///< Handle a special character token. + /// \return fetch another token? + + virtual void parseEOF (Scanner& scanner); + ///< Handle EOF token. + }; +} + +#endif + From 910d62e4b84e701e4da58ac83e0d882804eb6c6f Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Fri, 14 Feb 2014 11:59:33 +0100 Subject: [PATCH 38/47] added missing implementation for CSMWorld::ScriptContext::getGlobalType --- apps/opencs/model/world/scriptcontext.cpp | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/apps/opencs/model/world/scriptcontext.cpp b/apps/opencs/model/world/scriptcontext.cpp index 1b30281595..2627c49f3e 100644 --- a/apps/opencs/model/world/scriptcontext.cpp +++ b/apps/opencs/model/world/scriptcontext.cpp @@ -16,6 +16,20 @@ bool CSMWorld::ScriptContext::canDeclareLocals() const char CSMWorld::ScriptContext::getGlobalType (const std::string& name) const { + int index = mData.getGlobals().searchId (name); + + if (index!=-1) + { + switch (mData.getGlobals().getRecord (index).get().mValue.getType()) + { + case ESM::VT_Short: return 's'; + case ESM::VT_Long: return 'l'; + case ESM::VT_Float: return 'f'; + + default: return ' '; + } + } + return ' '; } From d213c6c36a48f3435e1b42aa9d4101eb0618ebc0 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Fri, 14 Feb 2014 12:23:00 +0100 Subject: [PATCH 39/47] fixed a constness-issue --- components/compiler/controlparser.cpp | 2 +- components/compiler/controlparser.hpp | 2 +- components/compiler/declarationparser.cpp | 2 +- components/compiler/declarationparser.hpp | 2 +- components/compiler/exprparser.cpp | 2 +- components/compiler/exprparser.hpp | 2 +- components/compiler/lineparser.cpp | 2 +- components/compiler/lineparser.hpp | 2 +- components/compiler/parser.cpp | 4 ++-- components/compiler/parser.hpp | 6 +++--- components/compiler/quickfileparser.cpp | 2 +- components/compiler/quickfileparser.hpp | 2 +- components/compiler/scriptparser.cpp | 2 +- components/compiler/scriptparser.hpp | 14 +++++++------- components/compiler/skipparser.cpp | 4 ++-- components/compiler/skipparser.hpp | 8 ++++---- components/compiler/stringparser.cpp | 2 +- components/compiler/stringparser.hpp | 18 +++++++++--------- 18 files changed, 39 insertions(+), 39 deletions(-) diff --git a/components/compiler/controlparser.cpp b/components/compiler/controlparser.cpp index 499358ca02..58542bd739 100644 --- a/components/compiler/controlparser.cpp +++ b/components/compiler/controlparser.cpp @@ -154,7 +154,7 @@ namespace Compiler } } - ControlParser::ControlParser (ErrorHandler& errorHandler, Context& context, Locals& locals, + ControlParser::ControlParser (ErrorHandler& errorHandler, const Context& context, Locals& locals, Literals& literals) : Parser (errorHandler, context), mLocals (locals), mLiterals (literals), mLineParser (errorHandler, context, locals, literals, mCodeBlock), diff --git a/components/compiler/controlparser.hpp b/components/compiler/controlparser.hpp index 50fd2d1f9e..24bc7bec75 100644 --- a/components/compiler/controlparser.hpp +++ b/components/compiler/controlparser.hpp @@ -47,7 +47,7 @@ namespace Compiler public: - ControlParser (ErrorHandler& errorHandler, Context& context, Locals& locals, + ControlParser (ErrorHandler& errorHandler, const Context& context, Locals& locals, Literals& literals); void appendCode (std::vector& code) const; diff --git a/components/compiler/declarationparser.cpp b/components/compiler/declarationparser.cpp index 357f0259be..d17f49caf0 100644 --- a/components/compiler/declarationparser.cpp +++ b/components/compiler/declarationparser.cpp @@ -8,7 +8,7 @@ #include "skipparser.hpp" #include "locals.hpp" -Compiler::DeclarationParser::DeclarationParser (ErrorHandler& errorHandler, Context& context, +Compiler::DeclarationParser::DeclarationParser (ErrorHandler& errorHandler, const Context& context, Locals& locals) : Parser (errorHandler, context), mLocals (locals), mState (State_Begin), mType (0) {} diff --git a/components/compiler/declarationparser.hpp b/components/compiler/declarationparser.hpp index f85b31ba15..43dd835705 100644 --- a/components/compiler/declarationparser.hpp +++ b/components/compiler/declarationparser.hpp @@ -20,7 +20,7 @@ namespace Compiler public: - DeclarationParser (ErrorHandler& errorHandler, Context& context, Locals& locals); + DeclarationParser (ErrorHandler& errorHandler, const Context& context, Locals& locals); virtual bool parseName (const std::string& name, const TokenLoc& loc, Scanner& scanner); diff --git a/components/compiler/exprparser.cpp b/components/compiler/exprparser.cpp index 7d310617ce..6d26ef403c 100644 --- a/components/compiler/exprparser.cpp +++ b/components/compiler/exprparser.cpp @@ -219,7 +219,7 @@ namespace Compiler return false; } - ExprParser::ExprParser (ErrorHandler& errorHandler, Context& context, Locals& locals, + ExprParser::ExprParser (ErrorHandler& errorHandler, const Context& context, Locals& locals, Literals& literals, bool argument) : Parser (errorHandler, context), mLocals (locals), mLiterals (literals), mNextOperand (true), mFirst (true), mArgument (argument), mRefOp (false), mMemberOp (false) diff --git a/components/compiler/exprparser.hpp b/components/compiler/exprparser.hpp index 905f0d454f..6a4e1be2ff 100644 --- a/components/compiler/exprparser.hpp +++ b/components/compiler/exprparser.hpp @@ -58,7 +58,7 @@ namespace Compiler public: - ExprParser (ErrorHandler& errorHandler, Context& context, Locals& locals, + ExprParser (ErrorHandler& errorHandler, const Context& context, Locals& locals, Literals& literals, bool argument = false); ///< constructor /// \param argument Parser is used to parse function- or instruction- diff --git a/components/compiler/lineparser.cpp b/components/compiler/lineparser.cpp index b1956e6283..5457d76255 100644 --- a/components/compiler/lineparser.cpp +++ b/components/compiler/lineparser.cpp @@ -50,7 +50,7 @@ namespace Compiler } } - LineParser::LineParser (ErrorHandler& errorHandler, Context& context, Locals& locals, + LineParser::LineParser (ErrorHandler& errorHandler, const Context& context, Locals& locals, Literals& literals, std::vector& code, bool allowExpression) : Parser (errorHandler, context), mLocals (locals), mLiterals (literals), mCode (code), mState (BeginState), mExprParser (errorHandler, context, locals, literals), diff --git a/components/compiler/lineparser.hpp b/components/compiler/lineparser.hpp index c54c764bce..4f2d33bde5 100644 --- a/components/compiler/lineparser.hpp +++ b/components/compiler/lineparser.hpp @@ -44,7 +44,7 @@ namespace Compiler public: - LineParser (ErrorHandler& errorHandler, Context& context, Locals& locals, + LineParser (ErrorHandler& errorHandler, const Context& context, Locals& locals, Literals& literals, std::vector& code, bool allowExpression = false); ///< \param allowExpression Allow lines consisting of a naked expression diff --git a/components/compiler/parser.cpp b/components/compiler/parser.cpp index 8d11c4086d..781fbad8cb 100644 --- a/components/compiler/parser.cpp +++ b/components/compiler/parser.cpp @@ -52,7 +52,7 @@ namespace Compiler // Return context - Context& Parser::getContext() + const Context& Parser::getContext() const { return mContext; } @@ -64,7 +64,7 @@ namespace Compiler return lowerCase; } - Parser::Parser (ErrorHandler& errorHandler, Context& context) + Parser::Parser (ErrorHandler& errorHandler, const Context& context) : mErrorHandler (errorHandler), mContext (context), mOptional (false), mEmpty (true) {} diff --git a/components/compiler/parser.hpp b/components/compiler/parser.hpp index 4fec570e9f..54e913b202 100644 --- a/components/compiler/parser.hpp +++ b/components/compiler/parser.hpp @@ -17,7 +17,7 @@ namespace Compiler class Parser { ErrorHandler& mErrorHandler; - Context& mContext; + const Context& mContext; bool mOptional; bool mEmpty; @@ -38,14 +38,14 @@ namespace Compiler ErrorHandler& getErrorHandler(); ///< Return error handler - Context& getContext(); + const Context& getContext() const; ///< Return context static std::string toLower (const std::string& name); public: - Parser (ErrorHandler& errorHandler, Context& context); + Parser (ErrorHandler& errorHandler, const Context& context); ///< constructor virtual ~Parser(); diff --git a/components/compiler/quickfileparser.cpp b/components/compiler/quickfileparser.cpp index 157e152490..f3d8063b2f 100644 --- a/components/compiler/quickfileparser.cpp +++ b/components/compiler/quickfileparser.cpp @@ -4,7 +4,7 @@ #include "skipparser.hpp" #include "scanner.hpp" -Compiler::QuickFileParser::QuickFileParser (ErrorHandler& errorHandler, Context& context, +Compiler::QuickFileParser::QuickFileParser (ErrorHandler& errorHandler, const Context& context, Locals& locals) : Parser (errorHandler, context), mDeclarationParser (errorHandler, context, locals) {} diff --git a/components/compiler/quickfileparser.hpp b/components/compiler/quickfileparser.hpp index d2dfafb346..440d910387 100644 --- a/components/compiler/quickfileparser.hpp +++ b/components/compiler/quickfileparser.hpp @@ -15,7 +15,7 @@ namespace Compiler public: - QuickFileParser (ErrorHandler& errorHandler, Context& context, Locals& locals); + QuickFileParser (ErrorHandler& errorHandler, const Context& context, Locals& locals); virtual bool parseName (const std::string& name, const TokenLoc& loc, Scanner& scanner); diff --git a/components/compiler/scriptparser.cpp b/components/compiler/scriptparser.cpp index f34313969a..ea11be5f03 100644 --- a/components/compiler/scriptparser.cpp +++ b/components/compiler/scriptparser.cpp @@ -7,7 +7,7 @@ namespace Compiler { - ScriptParser::ScriptParser (ErrorHandler& errorHandler, Context& context, + ScriptParser::ScriptParser (ErrorHandler& errorHandler, const Context& context, Locals& locals, bool end) : Parser (errorHandler, context), mOutput (locals), mLineParser (errorHandler, context, locals, mOutput.getLiterals(), mOutput.getCode()), diff --git a/components/compiler/scriptparser.hpp b/components/compiler/scriptparser.hpp index bb4809dabd..000244c793 100644 --- a/components/compiler/scriptparser.hpp +++ b/components/compiler/scriptparser.hpp @@ -12,7 +12,7 @@ namespace Compiler class Locals; // Script parser, to be used in dialogue scripts and as part of FileParser - + class ScriptParser : public Parser { Output mOutput; @@ -21,14 +21,14 @@ namespace Compiler bool mEnd; public: - + /// \param end of script is marked by end keyword. - ScriptParser (ErrorHandler& errorHandler, Context& context, Locals& locals, + ScriptParser (ErrorHandler& errorHandler, const Context& context, Locals& locals, bool end = false); - + void getCode (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. @@ -43,8 +43,8 @@ namespace Compiler /// \return fetch another token? virtual void parseEOF (Scanner& scanner); - ///< Handle EOF token. - + ///< Handle EOF token. + void reset(); ///< Reset parser to clean state. }; diff --git a/components/compiler/skipparser.cpp b/components/compiler/skipparser.cpp index 2d09b63ba0..c7cb31f58e 100644 --- a/components/compiler/skipparser.cpp +++ b/components/compiler/skipparser.cpp @@ -5,7 +5,7 @@ namespace Compiler { - SkipParser::SkipParser (ErrorHandler& errorHandler, Context& context) + SkipParser::SkipParser (ErrorHandler& errorHandler, const Context& context) : Parser (errorHandler, context) {} @@ -34,7 +34,7 @@ namespace Compiler { if (code==Scanner::S_newline) return false; - + return true; } } diff --git a/components/compiler/skipparser.hpp b/components/compiler/skipparser.hpp index 17f1c8d988..239c8bb02c 100644 --- a/components/compiler/skipparser.hpp +++ b/components/compiler/skipparser.hpp @@ -8,13 +8,13 @@ namespace Compiler // \brief Skip parser for skipping a line // // This parser is mainly intended for skipping the rest of a faulty line. - + class SkipParser : public Parser { public: - - SkipParser (ErrorHandler& errorHandler, Context& context); - + + SkipParser (ErrorHandler& errorHandler, const Context& context); + virtual bool parseInt (int value, const TokenLoc& loc, Scanner& scanner); ///< Handle an int token. /// \return fetch another token? diff --git a/components/compiler/stringparser.cpp b/components/compiler/stringparser.cpp index 09c902131a..a86c15794f 100644 --- a/components/compiler/stringparser.cpp +++ b/components/compiler/stringparser.cpp @@ -10,7 +10,7 @@ namespace Compiler { - StringParser::StringParser (ErrorHandler& errorHandler, Context& context, Literals& literals) + StringParser::StringParser (ErrorHandler& errorHandler, const Context& context, Literals& literals) : Parser (errorHandler, context), mLiterals (literals), mState (StartState), mSmashCase (false) { diff --git a/components/compiler/stringparser.hpp b/components/compiler/stringparser.hpp index f692c650b8..3859a24965 100644 --- a/components/compiler/stringparser.hpp +++ b/components/compiler/stringparser.hpp @@ -10,22 +10,22 @@ namespace Compiler { class Literals; - + class StringParser : public Parser { enum State { StartState, CommaState }; - + Literals& mLiterals; State mState; std::vector mCode; bool mSmashCase; - + public: - - StringParser (ErrorHandler& errorHandler, Context& context, Literals& literals); + + StringParser (ErrorHandler& errorHandler, const Context& context, Literals& literals); virtual bool parseName (const std::string& name, const TokenLoc& loc, Scanner& scanner); @@ -35,15 +35,15 @@ namespace Compiler virtual bool parseSpecial (int code, const TokenLoc& loc, Scanner& scanner); ///< Handle a special character token. /// \return fetch another token? - + void append (std::vector& code); ///< Append code for parsed string. - + void smashCase(); ///< Transform all scanned strings to lower case - + void reset(); - ///< Reset parser to clean state (this includes the smashCase function). + ///< Reset parser to clean state (this includes the smashCase function). }; } From 0a8ffbfb1d67080b1e22b0f7756794fa6134b94c Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Fri, 14 Feb 2014 12:46:54 +0100 Subject: [PATCH 40/47] added missing implementation for CSMWorld::ScriptContext::getMemberType --- apps/opencs/model/world/scriptcontext.cpp | 56 ++++++++++++++++++++++- apps/opencs/model/world/scriptcontext.hpp | 3 ++ 2 files changed, 58 insertions(+), 1 deletion(-) diff --git a/apps/opencs/model/world/scriptcontext.cpp b/apps/opencs/model/world/scriptcontext.cpp index 2627c49f3e..ee95f06c86 100644 --- a/apps/opencs/model/world/scriptcontext.cpp +++ b/apps/opencs/model/world/scriptcontext.cpp @@ -5,6 +5,10 @@ #include +#include +#include +#include + #include "data.hpp" CSMWorld::ScriptContext::ScriptContext (const Data& data) : mData (data), mIdsUpdated (false) {} @@ -36,7 +40,57 @@ char CSMWorld::ScriptContext::getGlobalType (const std::string& name) const std::pair CSMWorld::ScriptContext::getMemberType (const std::string& name, const std::string& id) const { - return std::make_pair (' ', false); + /// \todo invalidate locals cache on change to scripts + + std::string id2 = Misc::StringUtils::lowerCase (id); + + int index = mData.getScripts().searchId (id2); + bool reference = false; + + if (index!=-1) + { + // ID is not a script ID. Search for a matching referenceable instead. + index = mData.getReferenceables().searchId (id2); + + if (index!=-1) + { + // Referenceable found. + int columnIndex = mData.getReferenceables().searchColumnIndex (Columns::ColumnId_Script); + + if (columnIndex!=-1) + { + id2 = Misc::StringUtils::lowerCase (mData.getReferenceables(). + getData (index, columnIndex).toString().toUtf8().constData()); + + if (!id2.empty()) + { + // Referenceable has a script -> use it. + index = mData.getScripts().searchId (id2); + reference = true; + } + } + } + } + + if (index==-1) + return std::make_pair (' ', false); + + std::map::iterator iter = mLocals.find (id2); + + if (iter==mLocals.end()) + { + Compiler::Locals locals; + + Compiler::NullErrorHandler errorHandler; + std::istringstream stream (mData.getScripts().getRecord (index).get().mScriptText); + Compiler::QuickFileParser parser (errorHandler, *this, locals); + Compiler::Scanner scanner (errorHandler, stream, getExtensions()); + scanner.scan (parser); + + iter = mLocals.insert (std::make_pair (id2, locals)).first; + } + + return std::make_pair (iter->second.getType (Misc::StringUtils::lowerCase (name)), reference); } bool CSMWorld::ScriptContext::isId (const std::string& name) const diff --git a/apps/opencs/model/world/scriptcontext.hpp b/apps/opencs/model/world/scriptcontext.hpp index 3baca99b24..400748e5fa 100644 --- a/apps/opencs/model/world/scriptcontext.hpp +++ b/apps/opencs/model/world/scriptcontext.hpp @@ -3,8 +3,10 @@ #include #include +#include #include +#include namespace CSMWorld { @@ -15,6 +17,7 @@ namespace CSMWorld const Data& mData; mutable std::vector mIds; mutable bool mIdsUpdated; + mutable std::map mLocals; public: From 0ff744c2ff801aee8bd635924d4eaaeca5f25b03 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Fri, 14 Feb 2014 12:56:05 +0100 Subject: [PATCH 41/47] fixed CSMWorld::ScriptContext::isJournalId --- apps/opencs/model/world/scriptcontext.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/apps/opencs/model/world/scriptcontext.cpp b/apps/opencs/model/world/scriptcontext.cpp index ee95f06c86..688c33d308 100644 --- a/apps/opencs/model/world/scriptcontext.cpp +++ b/apps/opencs/model/world/scriptcontext.cpp @@ -109,8 +109,7 @@ bool CSMWorld::ScriptContext::isId (const std::string& name) const bool CSMWorld::ScriptContext::isJournalId (const std::string& name) const { - /// \todo fix this after isId is fixed - return isId (name); + return mData.getJournals().searchId (name)!=-1; } void CSMWorld::ScriptContext::invalidateIds() From e17af4231a9e16eb554a7b2fa56d3ca18fb99ead Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Fri, 14 Feb 2014 13:38:30 +0100 Subject: [PATCH 42/47] added script verifier --- apps/opencs/CMakeLists.txt | 2 +- apps/opencs/model/tools/scriptcheck.cpp | 98 +++++++++++++++++++++++ apps/opencs/model/tools/scriptcheck.hpp | 40 +++++++++ apps/opencs/model/tools/tools.cpp | 3 + apps/opencs/model/world/scriptcontext.cpp | 9 ++- apps/opencs/model/world/scriptcontext.hpp | 3 + 6 files changed, 153 insertions(+), 2 deletions(-) create mode 100644 apps/opencs/model/tools/scriptcheck.cpp create mode 100644 apps/opencs/model/tools/scriptcheck.hpp diff --git a/apps/opencs/CMakeLists.txt b/apps/opencs/CMakeLists.txt index 5c3cd0dcc1..82313b7ed1 100644 --- a/apps/opencs/CMakeLists.txt +++ b/apps/opencs/CMakeLists.txt @@ -38,7 +38,7 @@ opencs_units (model/tools opencs_units_noqt (model/tools mandatoryid skillcheck classcheck factioncheck racecheck soundcheck regioncheck - birthsigncheck spellcheck referenceablecheck + birthsigncheck spellcheck referenceablecheck scriptcheck ) diff --git a/apps/opencs/model/tools/scriptcheck.cpp b/apps/opencs/model/tools/scriptcheck.cpp new file mode 100644 index 0000000000..8ed41ec02d --- /dev/null +++ b/apps/opencs/model/tools/scriptcheck.cpp @@ -0,0 +1,98 @@ + +#include "scriptcheck.hpp" + +#include +#include +#include +#include +#include + +#include "../world/data.hpp" + +void CSMTools::ScriptCheckStage::report (const std::string& message, const Compiler::TokenLoc& loc, + Type type) +{ + std::ostringstream stream; + + CSMWorld::UniversalId id (CSMWorld::UniversalId::Type_Script, mId); + + stream << id.toString() << "|"; + + if (type==ErrorMessage) + stream << "error "; + else + stream << "warning "; + + stream + << "line " << loc.mLine << ", column " << loc.mColumn + << " (" << loc.mLiteral << "): " << message; + + mMessages->push_back (stream.str()); +} + +void CSMTools::ScriptCheckStage::report (const std::string& message, Type type) +{ + std::ostringstream stream; + + CSMWorld::UniversalId id (CSMWorld::UniversalId::Type_Script, mId); + + stream << id.toString() << "|"; + + if (type==ErrorMessage) + stream << "error: "; + else + stream << "warning: "; + + stream << message; + + mMessages->push_back (stream.str()); +} + +CSMTools::ScriptCheckStage::ScriptCheckStage (const CSMWorld::Data& data) +: mData (data), mContext (data), mMessages (0) +{ + Compiler::registerExtensions (mExtensions); + mContext.setExtensions (&mExtensions); +} + +int CSMTools::ScriptCheckStage::setup() +{ + mContext.clear(); + mMessages = 0; + mId.clear(); + + return mData.getScripts().getSize(); +} + +void CSMTools::ScriptCheckStage::perform (int stage, std::vector& messages) +{ + mMessages = &messages; + mId = mData.getScripts().getId (stage); + + try + { + std::istringstream input (mData.getScripts().getRecord (stage).get().mScriptText); + + Compiler::Scanner scanner (*this, input, mContext.getExtensions()); + + Compiler::FileParser parser (*this, mContext); + + scanner.scan (parser); + } + catch (const Compiler::SourceException&) + { + // error has already been reported via error handler + } + catch (const std::exception& error) + { + std::ostringstream stream; + + CSMWorld::UniversalId id (CSMWorld::UniversalId::Type_Script, mId); + + stream << id.toString() << "|Critical compile error: " << error.what(); + + messages.push_back (stream.str()); + } + + mMessages = 0; +} \ No newline at end of file diff --git a/apps/opencs/model/tools/scriptcheck.hpp b/apps/opencs/model/tools/scriptcheck.hpp new file mode 100644 index 0000000000..325280d7ff --- /dev/null +++ b/apps/opencs/model/tools/scriptcheck.hpp @@ -0,0 +1,40 @@ +#ifndef CSM_TOOLS_SCRIPTCHECK_H +#define CSM_TOOLS_SCRIPTCHECK_H + +#include +#include + +#include "../doc/stage.hpp" + +#include "../world/scriptcontext.hpp" + +namespace CSMTools +{ + /// \brief VerifyStage: make sure that scripts compile + class ScriptCheckStage : public CSMDoc::Stage, private Compiler::ErrorHandler + { + const CSMWorld::Data& mData; + Compiler::Extensions mExtensions; + CSMWorld::ScriptContext mContext; + std::string mId; + std::vector *mMessages; + + virtual void report (const std::string& message, const Compiler::TokenLoc& loc, Type type); + ///< Report error to the user. + + virtual void report (const std::string& message, Type type); + ///< Report a file related error + + public: + + ScriptCheckStage (const CSMWorld::Data& data); + + virtual int setup(); + ///< \return number of steps + + virtual void perform (int stage, std::vector& messages); + ///< Messages resulting from this tage will be appended to \a messages. + }; +} + +#endif diff --git a/apps/opencs/model/tools/tools.cpp b/apps/opencs/model/tools/tools.cpp index 64e39ad2f6..79a09dcb48 100644 --- a/apps/opencs/model/tools/tools.cpp +++ b/apps/opencs/model/tools/tools.cpp @@ -20,6 +20,7 @@ #include "birthsigncheck.hpp" #include "spellcheck.hpp" #include "referenceablecheck.hpp" +#include "scriptcheck.hpp" CSMDoc::Operation *CSMTools::Tools::get (int type) { @@ -77,6 +78,8 @@ CSMDoc::Operation *CSMTools::Tools::getVerifier() mVerifier->appendStage (new SpellCheckStage (mData.getSpells())); mVerifier->appendStage (new ReferenceableCheckStage (mData.getReferenceables().getDataSet(), mData.getRaces(), mData.getClasses(), mData.getFactions())); + + mVerifier->appendStage (new ScriptCheckStage (mData)); } return mVerifier; diff --git a/apps/opencs/model/world/scriptcontext.cpp b/apps/opencs/model/world/scriptcontext.cpp index 688c33d308..8a4670ed2e 100644 --- a/apps/opencs/model/world/scriptcontext.cpp +++ b/apps/opencs/model/world/scriptcontext.cpp @@ -15,7 +15,7 @@ CSMWorld::ScriptContext::ScriptContext (const Data& data) : mData (data), mIdsUp bool CSMWorld::ScriptContext::canDeclareLocals() const { - return false; + return true; } char CSMWorld::ScriptContext::getGlobalType (const std::string& name) const @@ -115,4 +115,11 @@ bool CSMWorld::ScriptContext::isJournalId (const std::string& name) const void CSMWorld::ScriptContext::invalidateIds() { mIdsUpdated = false; +} + +void CSMWorld::ScriptContext::clear() +{ + mIds.clear(); + mIdsUpdated = false; + mLocals.clear(); } \ No newline at end of file diff --git a/apps/opencs/model/world/scriptcontext.hpp b/apps/opencs/model/world/scriptcontext.hpp index 400748e5fa..29ee42645a 100644 --- a/apps/opencs/model/world/scriptcontext.hpp +++ b/apps/opencs/model/world/scriptcontext.hpp @@ -43,6 +43,9 @@ namespace CSMWorld ///< Does \a name match a journal ID? void invalidateIds(); + + void clear(); + ///< Remove all cached data. }; } From fd665a19941d072b6bdc3a44eab9aa26b74e1f40 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Sat, 15 Feb 2014 12:45:50 +0100 Subject: [PATCH 43/47] ignore conditions after an else (only works if condition is put in parentheses) --- components/compiler/controlparser.cpp | 15 ++++++++++++--- components/compiler/controlparser.hpp | 3 ++- 2 files changed, 14 insertions(+), 4 deletions(-) diff --git a/components/compiler/controlparser.cpp b/components/compiler/controlparser.cpp index 58542bd739..aefe6d16da 100644 --- a/components/compiler/controlparser.cpp +++ b/components/compiler/controlparser.cpp @@ -8,6 +8,7 @@ #include "scanner.hpp" #include "generator.hpp" #include "errorhandler.hpp" +#include "skipparser.hpp" namespace Compiler { @@ -71,7 +72,7 @@ namespace Compiler } else if (keyword==Scanner::K_else) { - mState = IfElseBodyState; /// \todo should be IfElseEndState; add an option for that + mState = IfElseJunkState; /// \todo should be IfElseEndState; add an option for that } return true; @@ -207,7 +208,8 @@ namespace Compiler return true; } } - else if (mState==IfBodyState || mState==IfElseifBodyState || mState==IfElseBodyState) + else if (mState==IfBodyState || mState==IfElseifBodyState || mState==IfElseBodyState || + mState==IfElseJunkState) { if (parseIfBody (keyword, loc, scanner)) return true; @@ -230,6 +232,7 @@ namespace Compiler case IfEndState: mState = IfBodyState; return true; case IfElseifEndState: mState = IfElseifBodyState; return true; case IfElseEndState: mState = IfElseBodyState; return true; + case IfElseJunkState: mState = IfElseBodyState; return true; case WhileEndState: mState = WhileBodyState; return true; @@ -247,7 +250,13 @@ namespace Compiler default: ; } - + } + else if (code==Scanner::S_open && mState==IfElseJunkState) + { + SkipParser skip (getErrorHandler(), getContext()); + scanner.scan (skip); + mState = IfElseBodyState; + return true; } return Parser::parseSpecial (code, loc, scanner); diff --git a/components/compiler/controlparser.hpp b/components/compiler/controlparser.hpp index 24bc7bec75..1175a0ed58 100644 --- a/components/compiler/controlparser.hpp +++ b/components/compiler/controlparser.hpp @@ -26,7 +26,8 @@ namespace Compiler IfElseEndState, IfElseBodyState, IfEndifState, WhileEndState, WhileBodyState, - WhileEndwhileState + WhileEndwhileState, + IfElseJunkState }; typedef std::vector Codes; From 0d84adb2c601345bb9a782624a9caaa88d0fedbb Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Sat, 15 Feb 2014 12:50:40 +0100 Subject: [PATCH 44/47] allow x->(y) instead of (x->y) --- components/compiler/exprparser.cpp | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/components/compiler/exprparser.cpp b/components/compiler/exprparser.cpp index 6d26ef403c..0c013b18f1 100644 --- a/components/compiler/exprparser.cpp +++ b/components/compiler/exprparser.cpp @@ -570,6 +570,14 @@ namespace Compiler { if (!mExplicit.empty()) { + if (mRefOp && code==Scanner::S_open) + { + /// \todo add option to disable this workaround + mOperators.push_back ('('); + mTokenLoc = loc; + return true; + } + if (!mRefOp && code==Scanner::S_ref) { mRefOp = true; From 2130ec39d698ad92994b216185cf9fbc238ef944 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Sat, 15 Feb 2014 12:58:34 +0100 Subject: [PATCH 45/47] disable warnings by default in script verifier --- apps/opencs/model/tools/scriptcheck.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/apps/opencs/model/tools/scriptcheck.cpp b/apps/opencs/model/tools/scriptcheck.cpp index 8ed41ec02d..2ed8fe6579 100644 --- a/apps/opencs/model/tools/scriptcheck.cpp +++ b/apps/opencs/model/tools/scriptcheck.cpp @@ -51,6 +51,9 @@ void CSMTools::ScriptCheckStage::report (const std::string& message, Type type) CSMTools::ScriptCheckStage::ScriptCheckStage (const CSMWorld::Data& data) : mData (data), mContext (data), mMessages (0) { + /// \todo add an option to configure warning mode + setWarningsMode (0); + Compiler::registerExtensions (mExtensions); mContext.setExtensions (&mExtensions); } From 4e041319578a310e2d6be5be4c118d0e83155b27 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Sat, 15 Feb 2014 13:09:43 +0100 Subject: [PATCH 46/47] fixing case broke sorting in script context --- apps/opencs/model/world/scriptcontext.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/apps/opencs/model/world/scriptcontext.cpp b/apps/opencs/model/world/scriptcontext.cpp index 8a4670ed2e..9da49defe7 100644 --- a/apps/opencs/model/world/scriptcontext.cpp +++ b/apps/opencs/model/world/scriptcontext.cpp @@ -100,6 +100,7 @@ bool CSMWorld::ScriptContext::isId (const std::string& name) const mIds = mData.getIds(); std::for_each (mIds.begin(), mIds.end(), &Misc::StringUtils::lowerCase); + std::sort (mIds.begin(), mIds.end()); mIdsUpdated = true; } From 2007a3e9027c640f1dc6d5ad4259ed632f04d1b8 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Sat, 15 Feb 2014 13:25:38 +0100 Subject: [PATCH 47/47] improved script check error messages --- apps/opencs/model/tools/scriptcheck.cpp | 4 +++- apps/opencs/model/tools/scriptcheck.hpp | 1 + 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/apps/opencs/model/tools/scriptcheck.cpp b/apps/opencs/model/tools/scriptcheck.cpp index 2ed8fe6579..a5154d2926 100644 --- a/apps/opencs/model/tools/scriptcheck.cpp +++ b/apps/opencs/model/tools/scriptcheck.cpp @@ -24,7 +24,8 @@ void CSMTools::ScriptCheckStage::report (const std::string& message, const Compi stream << "warning "; stream - << "line " << loc.mLine << ", column " << loc.mColumn + << "script " << mFile + << ", line " << loc.mLine << ", column " << loc.mColumn << " (" << loc.mLiteral << "): " << message; mMessages->push_back (stream.str()); @@ -74,6 +75,7 @@ void CSMTools::ScriptCheckStage::perform (int stage, std::vector& m try { + mFile = mData.getScripts().getRecord (stage).get().mId; std::istringstream input (mData.getScripts().getRecord (stage).get().mScriptText); Compiler::Scanner scanner (*this, input, mContext.getExtensions()); diff --git a/apps/opencs/model/tools/scriptcheck.hpp b/apps/opencs/model/tools/scriptcheck.hpp index 325280d7ff..8de8e1a667 100644 --- a/apps/opencs/model/tools/scriptcheck.hpp +++ b/apps/opencs/model/tools/scriptcheck.hpp @@ -17,6 +17,7 @@ namespace CSMTools Compiler::Extensions mExtensions; CSMWorld::ScriptContext mContext; std::string mId; + std::string mFile; std::vector *mMessages; virtual void report (const std::string& message, const Compiler::TokenLoc& loc, Type type);