1
0
Fork 0
mirror of https://github.com/OpenMW/openmw.git synced 2025-01-21 09:53:52 +00:00

Merge branch 'script'

Conflicts:
	readme.txt
This commit is contained in:
Marc Zinnschlag 2014-02-16 12:12:56 +01:00
commit 6ac64bbe15
54 changed files with 1129 additions and 286 deletions

View file

@ -38,7 +38,7 @@ opencs_units (model/tools
opencs_units_noqt (model/tools opencs_units_noqt (model/tools
mandatoryid skillcheck classcheck factioncheck racecheck soundcheck regioncheck mandatoryid skillcheck classcheck factioncheck racecheck soundcheck regioncheck
birthsigncheck spellcheck referenceablecheck birthsigncheck spellcheck referenceablecheck scriptcheck
) )

View file

@ -0,0 +1,103 @@
#include "scriptcheck.hpp"
#include <components/compiler/tokenloc.hpp>
#include <components/compiler/scanner.hpp>
#include <components/compiler/fileparser.hpp>
#include <components/compiler/exception.hpp>
#include <components/compiler/extensions0.hpp>
#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
<< "script " << mFile
<< ", 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)
{
/// \todo add an option to configure warning mode
setWarningsMode (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<std::string>& messages)
{
mMessages = &messages;
mId = mData.getScripts().getId (stage);
try
{
mFile = mData.getScripts().getRecord (stage).get().mId;
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;
}

View file

@ -0,0 +1,41 @@
#ifndef CSM_TOOLS_SCRIPTCHECK_H
#define CSM_TOOLS_SCRIPTCHECK_H
#include <components/compiler/errorhandler.hpp>
#include <components/compiler/extensions.hpp>
#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::string mFile;
std::vector<std::string> *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<std::string>& messages);
///< Messages resulting from this tage will be appended to \a messages.
};
}
#endif

View file

@ -20,6 +20,7 @@
#include "birthsigncheck.hpp" #include "birthsigncheck.hpp"
#include "spellcheck.hpp" #include "spellcheck.hpp"
#include "referenceablecheck.hpp" #include "referenceablecheck.hpp"
#include "scriptcheck.hpp"
CSMDoc::Operation *CSMTools::Tools::get (int type) 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 SpellCheckStage (mData.getSpells()));
mVerifier->appendStage (new ReferenceableCheckStage (mData.getReferenceables().getDataSet(), mData.getRaces(), mData.getClasses(), mData.getFactions())); mVerifier->appendStage (new ReferenceableCheckStage (mData.getReferenceables().getDataSet(), mData.getRaces(), mData.getClasses(), mData.getFactions()));
mVerifier->appendStage (new ScriptCheckStage (mData));
} }
return mVerifier; return mVerifier;

View file

@ -5,23 +5,92 @@
#include <components/misc/stringops.hpp> #include <components/misc/stringops.hpp>
#include <components/compiler/quickfileparser.hpp>
#include <components/compiler/nullerrorhandler.hpp>
#include <components/compiler/scanner.hpp>
#include "data.hpp" #include "data.hpp"
CSMWorld::ScriptContext::ScriptContext (const Data& data) : mData (data), mIdsUpdated (false) {} CSMWorld::ScriptContext::ScriptContext (const Data& data) : mData (data), mIdsUpdated (false) {}
bool CSMWorld::ScriptContext::canDeclareLocals() const bool CSMWorld::ScriptContext::canDeclareLocals() const
{ {
return false; return true;
} }
char CSMWorld::ScriptContext::getGlobalType (const std::string& name) 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 ' '; return ' ';
} }
char CSMWorld::ScriptContext::getMemberType (const std::string& name, const std::string& id) const std::pair<char, bool> CSMWorld::ScriptContext::getMemberType (const std::string& name,
const std::string& id) const
{ {
return ' '; /// \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<std::string, Compiler::Locals>::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 bool CSMWorld::ScriptContext::isId (const std::string& name) const
@ -31,6 +100,7 @@ bool CSMWorld::ScriptContext::isId (const std::string& name) const
mIds = mData.getIds(); mIds = mData.getIds();
std::for_each (mIds.begin(), mIds.end(), &Misc::StringUtils::lowerCase); std::for_each (mIds.begin(), mIds.end(), &Misc::StringUtils::lowerCase);
std::sort (mIds.begin(), mIds.end());
mIdsUpdated = true; mIdsUpdated = true;
} }
@ -38,7 +108,19 @@ bool CSMWorld::ScriptContext::isId (const std::string& name) const
return std::binary_search (mIds.begin(), mIds.end(), Misc::StringUtils::lowerCase (name)); return std::binary_search (mIds.begin(), mIds.end(), Misc::StringUtils::lowerCase (name));
} }
bool CSMWorld::ScriptContext::isJournalId (const std::string& name) const
{
return mData.getJournals().searchId (name)!=-1;
}
void CSMWorld::ScriptContext::invalidateIds() void CSMWorld::ScriptContext::invalidateIds()
{ {
mIdsUpdated = false; mIdsUpdated = false;
} }
void CSMWorld::ScriptContext::clear()
{
mIds.clear();
mIdsUpdated = false;
mLocals.clear();
}

View file

@ -3,8 +3,10 @@
#include <string> #include <string>
#include <vector> #include <vector>
#include <map>
#include <components/compiler/context.hpp> #include <components/compiler/context.hpp>
#include <components/compiler/locals.hpp>
namespace CSMWorld namespace CSMWorld
{ {
@ -15,6 +17,7 @@ namespace CSMWorld
const Data& mData; const Data& mData;
mutable std::vector<std::string> mIds; mutable std::vector<std::string> mIds;
mutable bool mIdsUpdated; mutable bool mIdsUpdated;
mutable std::map<std::string, Compiler::Locals> mLocals;
public: public:
@ -26,13 +29,23 @@ namespace CSMWorld
virtual char getGlobalType (const std::string& name) const; virtual char getGlobalType (const std::string& name) const;
///< 'l: long, 's': short, 'f': float, ' ': does not exist. ///< 'l: long, 's': short, 'f': float, ' ': does not exist.
virtual char getMemberType (const std::string& name, const std::string& id) const; virtual std::pair<char, bool> getMemberType (const std::string& name,
///< 'l: long, 's': short, 'f': float, ' ': does not exist. 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; virtual bool isId (const std::string& name) const;
///< Does \a name match an ID, that can be referenced? ///< 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(); void invalidateIds();
void clear();
///< Remove all cached data.
}; };
} }

View file

@ -155,6 +155,7 @@ OMW::Engine::Engine(Files::ConfigurationManager& configurationManager)
, mSkipMenu (false) , mSkipMenu (false)
, mUseSound (true) , mUseSound (true)
, mCompileAll (false) , mCompileAll (false)
, mWarningsMode (1)
, mScriptContext (0) , mScriptContext (0)
, mFSStrict (false) , mFSStrict (false)
, mScriptConsoleMode (false) , mScriptConsoleMode (false)
@ -424,7 +425,7 @@ void OMW::Engine::prepareEngine (Settings::Manager & settings)
mScriptContext->setExtensions (&mExtensions); mScriptContext->setExtensions (&mExtensions);
mEnvironment.setScriptManager (new MWScript::ScriptManager (MWBase::Environment::get().getWorld()->getStore(), mEnvironment.setScriptManager (new MWScript::ScriptManager (MWBase::Environment::get().getWorld()->getStore(),
mVerboseScripts, *mScriptContext)); mVerboseScripts, *mScriptContext, mWarningsMode));
// Create game mechanics system // Create game mechanics system
MWMechanics::MechanicsManager* mechanics = new MWMechanics::MechanicsManager; MWMechanics::MechanicsManager* mechanics = new MWMechanics::MechanicsManager;
@ -612,8 +613,12 @@ void OMW::Engine::setStartupScript (const std::string& path)
mStartupScript = path; mStartupScript = path;
} }
void OMW::Engine::setActivationDistanceOverride (int distance) void OMW::Engine::setActivationDistanceOverride (int distance)
{ {
mActivationDistanceOverride = distance; mActivationDistanceOverride = distance;
} }
void OMW::Engine::setWarningsMode (int mode)
{
mWarningsMode = mode;
}

View file

@ -74,6 +74,7 @@ namespace OMW
bool mSkipMenu; bool mSkipMenu;
bool mUseSound; bool mUseSound;
bool mCompileAll; bool mCompileAll;
int mWarningsMode;
std::string mFocusName; std::string mFocusName;
std::map<std::string,std::string> mFallbackMap; std::map<std::string,std::string> mFallbackMap;
bool mScriptConsoleMode; bool mScriptConsoleMode;
@ -181,6 +182,8 @@ namespace OMW
/// Override the game setting specified activation distance. /// Override the game setting specified activation distance.
void setActivationDistanceOverride (int distance); void setActivationDistanceOverride (int distance);
void setWarningsMode (int mode);
private: private:
Files::ConfigurationManager& mCfgMgr; Files::ConfigurationManager& mCfgMgr;
}; };

View file

@ -136,6 +136,13 @@ bool parseOptions (int argc, char** argv, OMW::Engine& engine, Files::Configurat
("script-run", bpo::value<std::string>()->default_value(""), ("script-run", bpo::value<std::string>()->default_value(""),
"select a file containing a list of console commands that is executed on startup") "select a file containing a list of console commands that is executed on startup")
("script-warn", bpo::value<int>()->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<bool>()->implicit_value(true) ("skip-menu", bpo::value<bool>()->implicit_value(true)
->default_value(false), "skip main menu on game startup") ->default_value(false), "skip main menu on game startup")
@ -241,6 +248,7 @@ bool parseOptions (int argc, char** argv, OMW::Engine& engine, Files::Configurat
engine.setScriptConsoleMode (variables["script-console"].as<bool>()); engine.setScriptConsoleMode (variables["script-console"].as<bool>());
engine.setStartupScript (variables["script-run"].as<std::string>()); engine.setStartupScript (variables["script-run"].as<std::string>());
engine.setActivationDistanceOverride (variables["activate-dist"].as<int>()); engine.setActivationDistanceOverride (variables["activate-dist"].as<int>());
engine.setWarningsMode (variables["script-warn"].as<int>());
return true; return true;
} }

View file

@ -3,6 +3,8 @@
#include "../mwworld/esmstore.hpp" #include "../mwworld/esmstore.hpp"
#include <components/esm/loaddial.hpp>
#include <components/compiler/locals.hpp> #include <components/compiler/locals.hpp>
#include "../mwbase/environment.hpp" #include "../mwbase/environment.hpp"
@ -28,16 +30,32 @@ namespace MWScript
return MWBase::Environment::get().getWorld()->getGlobalVariableType (name); return MWBase::Environment::get().getWorld()->getGlobalVariableType (name);
} }
char CompilerContext::getMemberType (const std::string& name, const std::string& id) const std::pair<char, bool> CompilerContext::getMemberType (const std::string& name,
const std::string& id) const
{
std::string script;
bool reference = false;
if (const ESM::Script *scriptRecord =
MWBase::Environment::get().getWorld()->getStore().get<ESM::Script>().search (id))
{
script = scriptRecord->mId;
}
else
{ {
MWWorld::Ptr ptr = MWBase::Environment::get().getWorld()->getPtr (id, false); MWWorld::Ptr ptr = MWBase::Environment::get().getWorld()->getPtr (id, false);
std::string script = MWWorld::Class::get (ptr).getScript (ptr); script = MWWorld::Class::get (ptr).getScript (ptr);
reference = true;
}
if (script.empty()) char type = ' ';
return ' ';
return MWBase::Environment::get().getScriptManager()->getLocals (script).getType (name); if (!script.empty())
type = MWBase::Environment::get().getScriptManager()->getLocals (script).getType (
Misc::StringUtils::lowerCase (name));
return std::make_pair (type, reference);
} }
bool CompilerContext::isId (const std::string& name) const bool CompilerContext::isId (const std::string& name) const
@ -67,4 +85,14 @@ namespace MWScript
store.get<ESM::Static>().search (name) || store.get<ESM::Static>().search (name) ||
store.get<ESM::Weapon>().search (name); store.get<ESM::Weapon>().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<ESM::Dialogue>().search (name);
return topic && topic->mType==ESM::Dialogue::Journal;
}
} }

View file

@ -30,11 +30,18 @@ namespace MWScript
/// 'l: long, 's': short, 'f': float, ' ': does not exist. /// 'l: long, 's': short, 'f': float, ' ': does not exist.
virtual char getGlobalType (const std::string& name) const; virtual char getGlobalType (const std::string& name) const;
virtual char getMemberType (const std::string& name, const std::string& id) const; virtual std::pair<char, bool> getMemberType (const std::string& name,
///< 'l: long, 's': short, 'f': float, ' ': does not exist. 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; virtual bool isId (const std::string& name) const;
///< Does \a name match an ID, that can be referenced? ///< 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?
}; };
} }

View file

@ -52,7 +52,9 @@ op 0x20023: AiFollow, explicit reference
op 0x20024: AiFollowCell op 0x20024: AiFollowCell
op 0x20025: AiFollowCell, explicit reference op 0x20025: AiFollowCell, explicit reference
op 0x20026: ModRegion op 0x20026: ModRegion
opcodes 0x20027-0x3ffff unused op 0x20027: RemoveSoulGem
op 0x20028: RemoveSoulGem, explicit reference
opcodes 0x20029-0x3ffff unused
Segment 4: Segment 4:
(not implemented yet) (not implemented yet)
@ -308,8 +310,8 @@ op 0x20001f1: GetDetected
op 0x20001f2: GetDetected, explicit reference op 0x20001f2: GetDetected, explicit reference
op 0x20001f3: AddSoulGem op 0x20001f3: AddSoulGem
op 0x20001f4: AddSoulGem, explicit reference op 0x20001f4: AddSoulGem, explicit reference
op 0x20001f5: RemoveSoulGem op 0x20001f5: unused
op 0x20001f6: RemoveSoulGem, explicit reference op 0x20001f6: unused
op 0x20001f7: PlayBink op 0x20001f7: PlayBink
op 0x20001f8: Drop op 0x20001f8: Drop
op 0x20001f9: Drop, explicit reference op 0x20001f9: Drop, explicit reference
@ -381,5 +383,7 @@ op 0x200023a: StartCombat
op 0x200023b: StartCombatExplicit op 0x200023b: StartCombatExplicit
op 0x200023c: StopCombat op 0x200023c: StopCombat
op 0x200023d: StopCombatExplicit op 0x200023d: StopCombatExplicit
op 0x200023e: GetPcInJail
op 0x200023f: GetPcTraveling
opcodes 0x200023e-0x3ffffff unused opcodes 0x2000240-0x3ffffff unused

View file

@ -148,4 +148,25 @@ namespace MWScript
return false; return false;
} }
Locals& GlobalScripts::getLocals (const std::string& name)
{
std::string name2 = Misc::StringUtils::lowerCase (name);
std::map<std::string, std::pair<bool, Locals> >::iterator iter =
mScripts.find (name2);
if (iter==mScripts.end())
{
if (const ESM::Script *script = mStore.get<ESM::Script>().find (name))
{
Locals locals;
locals.configure (*script);
iter = mScripts.insert (std::make_pair (name, std::make_pair (false, locals))).first;
}
}
return iter->second.second;
}
} }

View file

@ -52,6 +52,10 @@ namespace MWScript
///< Records for variables that do not exist are dropped silently. ///< Records for variables that do not exist are dropped silently.
/// ///
/// \return Known type? /// \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.
}; };
} }

View file

@ -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);
id = MWWorld::Class::get (ptr).getScript (ptr);
ptr.getRefData().setLocals (
*MWBase::Environment::get().getWorld()->getStore().get<ESM::Script>().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);
id = MWWorld::Class::get (ptr).getScript (ptr);
ptr.getRefData().setLocals (
*MWBase::Environment::get().getWorld()->getStore().get<ESM::Script>().find (id));
return ptr.getRefData().getLocals();
}
}
InterpreterContext::InterpreterContext ( InterpreterContext::InterpreterContext (
MWScript::Locals *locals, MWWorld::Ptr reference) MWScript::Locals *locals, MWWorld::Ptr reference)
: mLocals (locals), mReference (reference), : mLocals (locals), mReference (reference),
@ -407,82 +448,80 @@ namespace MWScript
MWBase::Environment::get().getWorld()->disable (ref); 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 ( return locals.mShorts[index];
*MWBase::Environment::get().getWorld()->getStore().get<ESM::Script>().find (scriptId));
return ptr.getRefData().getLocals().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 ( return locals.mLongs[index];
*MWBase::Environment::get().getWorld()->getStore().get<ESM::Script>().find (scriptId));
return ptr.getRefData().getLocals().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 ( return locals.mFloats[index];
*MWBase::Environment::get().getWorld()->getStore().get<ESM::Script>().find (scriptId));
return ptr.getRefData().getLocals().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 ( locals.mShorts[index] = value;
*MWBase::Environment::get().getWorld()->getStore().get<ESM::Script>().find (scriptId));
ptr.getRefData().getLocals().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 ( locals.mLongs[index] = value;
*MWBase::Environment::get().getWorld()->getStore().get<ESM::Script>().find (scriptId));
ptr.getRefData().getLocals().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 ( locals.mFloats[index] = value;
*MWBase::Environment::get().getWorld()->getStore().get<ESM::Script>().find (scriptId));
ptr.getRefData().getLocals().mFloats[index] = value;
} }
MWWorld::Ptr InterpreterContext::getReference(bool required) MWWorld::Ptr InterpreterContext::getReference(bool required)

View file

@ -37,6 +37,12 @@ namespace MWScript
const MWWorld::Ptr getReference (const std::string& id, bool activeOnly, bool doThrow=true) const; 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: public:
InterpreterContext (MWScript::Locals *locals, MWWorld::Ptr reference); InterpreterContext (MWScript::Locals *locals, MWWorld::Ptr reference);
@ -138,17 +144,17 @@ namespace MWScript
virtual void disable (const std::string& id = ""); 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); MWWorld::Ptr getReference(bool required=true);
///< Reference, that the script is running from (can be empty) ///< Reference, that the script is running from (can be empty)

View file

@ -365,17 +365,21 @@ namespace MWScript
}; };
template<class R> template<class R>
class OpRemoveSoulGem : public Interpreter::Opcode0 class OpRemoveSoulGem : public Interpreter::Opcode1
{ {
public: public:
virtual void execute (Interpreter::Runtime& runtime) virtual void execute (Interpreter::Runtime& runtime, unsigned int arg0)
{ {
MWWorld::Ptr ptr = R()(runtime); MWWorld::Ptr ptr = R()(runtime);
std::string soul = runtime.getStringLiteral (runtime[0].mInteger); std::string soul = runtime.getStringLiteral (runtime[0].mInteger);
runtime.pop(); runtime.pop();
// throw away additional arguments
for (unsigned int i=0; i<arg0; ++i)
runtime.pop();
MWWorld::ContainerStore& store = MWWorld::Class::get (ptr).getContainerStore (ptr); MWWorld::ContainerStore& store = MWWorld::Class::get (ptr).getContainerStore (ptr);
for (MWWorld::ContainerStoreIterator it = store.begin(); it != store.end(); ++it) for (MWWorld::ContainerStoreIterator it = store.begin(); it != store.end(); ++it)
{ {
@ -818,6 +822,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) void installOpcodes (Interpreter::Interpreter& interpreter)
{ {
interpreter.installSegment5 (Compiler::Misc::opcodeXBox, new OpXBox); interpreter.installSegment5 (Compiler::Misc::opcodeXBox, new OpXBox);
@ -850,8 +876,8 @@ namespace MWScript
interpreter.installSegment5 (Compiler::Misc::opcodeGetEffectExplicit, new OpGetEffect<ExplicitRef>); interpreter.installSegment5 (Compiler::Misc::opcodeGetEffectExplicit, new OpGetEffect<ExplicitRef>);
interpreter.installSegment5 (Compiler::Misc::opcodeAddSoulGem, new OpAddSoulGem<ImplicitRef>); interpreter.installSegment5 (Compiler::Misc::opcodeAddSoulGem, new OpAddSoulGem<ImplicitRef>);
interpreter.installSegment5 (Compiler::Misc::opcodeAddSoulGemExplicit, new OpAddSoulGem<ExplicitRef>); interpreter.installSegment5 (Compiler::Misc::opcodeAddSoulGemExplicit, new OpAddSoulGem<ExplicitRef>);
interpreter.installSegment5 (Compiler::Misc::opcodeRemoveSoulGem, new OpRemoveSoulGem<ImplicitRef>); interpreter.installSegment3 (Compiler::Misc::opcodeRemoveSoulGem, new OpRemoveSoulGem<ImplicitRef>);
interpreter.installSegment5 (Compiler::Misc::opcodeRemoveSoulGemExplicit, new OpRemoveSoulGem<ExplicitRef>); interpreter.installSegment3 (Compiler::Misc::opcodeRemoveSoulGemExplicit, new OpRemoveSoulGem<ExplicitRef>);
interpreter.installSegment5 (Compiler::Misc::opcodeDrop, new OpDrop<ImplicitRef>); interpreter.installSegment5 (Compiler::Misc::opcodeDrop, new OpDrop<ImplicitRef>);
interpreter.installSegment5 (Compiler::Misc::opcodeDropExplicit, new OpDrop<ExplicitRef>); interpreter.installSegment5 (Compiler::Misc::opcodeDropExplicit, new OpDrop<ExplicitRef>);
interpreter.installSegment5 (Compiler::Misc::opcodeDropSoulGem, new OpDropSoulGem<ImplicitRef>); interpreter.installSegment5 (Compiler::Misc::opcodeDropSoulGem, new OpDropSoulGem<ImplicitRef>);
@ -888,6 +914,8 @@ namespace MWScript
interpreter.installSegment5 (Compiler::Misc::opcodeCastExplicit, new OpCast<ExplicitRef>); interpreter.installSegment5 (Compiler::Misc::opcodeCastExplicit, new OpCast<ExplicitRef>);
interpreter.installSegment5 (Compiler::Misc::opcodeExplodeSpell, new OpExplodeSpell<ImplicitRef>); interpreter.installSegment5 (Compiler::Misc::opcodeExplodeSpell, new OpExplodeSpell<ImplicitRef>);
interpreter.installSegment5 (Compiler::Misc::opcodeExplodeSpellExplicit, new OpExplodeSpell<ExplicitRef>); interpreter.installSegment5 (Compiler::Misc::opcodeExplodeSpellExplicit, new OpExplodeSpell<ExplicitRef>);
interpreter.installSegment5 (Compiler::Misc::opcodeGetPcInJail, new OpGetPcInJail);
interpreter.installSegment5 (Compiler::Misc::opcodeGetPcTraveling, new OpGetPcTraveling);
} }
} }
} }

View file

@ -7,22 +7,28 @@
#include <exception> #include <exception>
#include <components/esm/loadscpt.hpp> #include <components/esm/loadscpt.hpp>
#include "../mwworld/esmstore.hpp"
#include <components/misc/stringops.hpp>
#include <components/compiler/scanner.hpp> #include <components/compiler/scanner.hpp>
#include <components/compiler/context.hpp> #include <components/compiler/context.hpp>
#include <components/compiler/exception.hpp> #include <components/compiler/exception.hpp>
#include <components/compiler/quickfileparser.hpp>
#include "../mwworld/esmstore.hpp"
#include "extensions.hpp" #include "extensions.hpp"
namespace MWScript namespace MWScript
{ {
ScriptManager::ScriptManager (const MWWorld::ESMStore& store, bool verbose, ScriptManager::ScriptManager (const MWWorld::ESMStore& store, bool verbose,
Compiler::Context& compilerContext) Compiler::Context& compilerContext, int warningsMode)
: mErrorHandler (std::cerr), mStore (store), mVerbose (verbose), : mErrorHandler (std::cerr), mStore (store), mVerbose (verbose),
mCompilerContext (compilerContext), mParser (mErrorHandler, mCompilerContext), mCompilerContext (compilerContext), mParser (mErrorHandler, mCompilerContext),
mOpcodesInstalled (false), mGlobalScripts (store) mOpcodesInstalled (false), mGlobalScripts (store)
{} {
mErrorHandler.setWarningsMode (warningsMode);
}
bool ScriptManager::compile (const std::string& name) bool ScriptManager::compile (const std::string& name)
{ {
@ -138,37 +144,33 @@ namespace MWScript
Compiler::Locals& ScriptManager::getLocals (const std::string& name) 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()) if (iter!=mScripts.end())
return iter->second.second; return iter->second.second;
} }
{ {
std::map<std::string, Compiler::Locals>::iterator iter = mOtherLocals.find (name); std::map<std::string, Compiler::Locals>::iterator iter = mOtherLocals.find (name2);
if (iter!=mOtherLocals.end()) if (iter!=mOtherLocals.end())
return iter->second; return iter->second;
} }
if (const ESM::Script *script = mStore.get<ESM::Script>().find (name2))
{
Compiler::Locals locals; Compiler::Locals locals;
if (const ESM::Script *script = mStore.get<ESM::Script>().find (name)) std::istringstream stream (script->mScriptText);
{ Compiler::QuickFileParser parser (mErrorHandler, mCompilerContext, locals);
int index = 0; Compiler::Scanner scanner (mErrorHandler, stream, mCompilerContext.getExtensions());
scanner.scan (parser);
for (int i=0; i<script->mData.mNumShorts; ++i)
locals.declare ('s', script->mVarNames[index++]);
for (int i=0; i<script->mData.mNumLongs; ++i)
locals.declare ('l', script->mVarNames[index++]);
for (int i=0; i<script->mData.mNumFloats; ++i)
locals.declare ('f', script->mVarNames[index++]);
std::map<std::string, Compiler::Locals>::iterator iter = std::map<std::string, Compiler::Locals>::iterator iter =
mOtherLocals.insert (std::make_pair (name, locals)).first; mOtherLocals.insert (std::make_pair (name2, locals)).first;
return iter->second; return iter->second;
} }
@ -214,8 +216,10 @@ namespace MWScript
throw std::runtime_error ("invalid variable type"); throw std::runtime_error ("invalid variable type");
} }
std::string variable2 = Misc::StringUtils::lowerCase (variable);
for (int i=0; i<size; ++i) for (int i=0; i<size; ++i)
if (script->mVarNames.at (i+offset)==variable) if (Misc::StringUtils::lowerCase (script->mVarNames.at (i+offset))==variable2)
return i; return i;
throw std::runtime_error ("unable to access local variable " + variable + " of " + scriptId); throw std::runtime_error ("unable to access local variable " + variable + " of " + scriptId);

View file

@ -52,7 +52,7 @@ namespace MWScript
public: public:
ScriptManager (const MWWorld::ESMStore& store, bool verbose, 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); virtual void run (const std::string& name, Interpreter::Context& interpreterContext);
///< Run the script with the given name (compile first, if not compiled yet) ///< Run the script with the given name (compile first, if not compiled yet)

View file

@ -59,7 +59,8 @@ add_component_dir (files
add_component_dir (compiler add_component_dir (compiler
context controlparser errorhandler exception exprparser extensions fileparser generator context controlparser errorhandler exception exprparser extensions fileparser generator
lineparser literals locals output parser scanner scriptparser skipparser streamerrorhandler lineparser literals locals output parser scanner scriptparser skipparser streamerrorhandler
stringparser tokenloc nullerrorhandler opcodes extensions0 stringparser tokenloc nullerrorhandler opcodes extensions0 declarationparser
quickfileparser
) )
add_component_dir (interpreter add_component_dir (interpreter

View file

@ -33,11 +33,18 @@ namespace Compiler
virtual char getGlobalType (const std::string& name) const = 0; virtual char getGlobalType (const std::string& name) const = 0;
///< 'l: long, 's': short, 'f': float, ' ': does not exist. ///< 'l: long, 's': short, 'f': float, ' ': does not exist.
virtual char getMemberType (const std::string& name, const std::string& id) const = 0; virtual std::pair<char, bool> getMemberType (const std::string& name,
///< 'l: long, 's': short, 'f': float, ' ': does not exist. 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; virtual bool isId (const std::string& name) const = 0;
///< Does \a name match an ID, that can be referenced? ///< 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?
}; };
} }

View file

@ -7,6 +7,8 @@
#include "scanner.hpp" #include "scanner.hpp"
#include "generator.hpp" #include "generator.hpp"
#include "errorhandler.hpp"
#include "skipparser.hpp"
namespace Compiler namespace Compiler
{ {
@ -70,7 +72,7 @@ namespace Compiler
} }
else if (keyword==Scanner::K_else) else if (keyword==Scanner::K_else)
{ {
mState = IfElseEndState; mState = IfElseJunkState; /// \todo should be IfElseEndState; add an option for that
} }
return true; return true;
@ -106,7 +108,7 @@ namespace Compiler
Codes expr; Codes expr;
mExprParser.append (expr); mExprParser.append (expr);
Generator::jump (loop, -static_cast<int> (mCodeBlock.size()-expr.size())); Generator::jump (loop, -static_cast<int> (mCodeBlock.size()+expr.size()));
std::copy (expr.begin(), expr.end(), std::back_inserter (mCode)); std::copy (expr.begin(), expr.end(), std::back_inserter (mCode));
@ -120,7 +122,7 @@ namespace Compiler
Codes loop2; Codes loop2;
Generator::jump (loop2, -static_cast<int> (mCodeBlock.size()-expr.size()-skip.size())); Generator::jump (loop2, -static_cast<int> (mCodeBlock.size()+expr.size()+skip.size()));
if (loop.size()!=loop2.size()) if (loop.size()!=loop2.size())
throw std::logic_error ( throw std::logic_error (
@ -153,7 +155,7 @@ namespace Compiler
} }
} }
ControlParser::ControlParser (ErrorHandler& errorHandler, Context& context, Locals& locals, ControlParser::ControlParser (ErrorHandler& errorHandler, const Context& context, Locals& locals,
Literals& literals) Literals& literals)
: Parser (errorHandler, context), mLocals (locals), mLiterals (literals), : Parser (errorHandler, context), mLocals (locals), mLiterals (literals),
mLineParser (errorHandler, context, locals, literals, mCodeBlock), mLineParser (errorHandler, context, locals, literals, mCodeBlock),
@ -186,8 +188,11 @@ namespace Compiler
{ {
if (mState==StartState) 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(); mExprParser.reset();
scanner.scan (mExprParser); scanner.scan (mExprParser);
@ -203,7 +208,8 @@ namespace Compiler
return true; 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)) if (parseIfBody (keyword, loc, scanner))
return true; return true;
@ -226,6 +232,7 @@ namespace Compiler
case IfEndState: mState = IfBodyState; return true; case IfEndState: mState = IfBodyState; return true;
case IfElseifEndState: mState = IfElseifBodyState; return true; case IfElseifEndState: mState = IfElseifBodyState; return true;
case IfElseEndState: mState = IfElseBodyState; return true; case IfElseEndState: mState = IfElseBodyState; return true;
case IfElseJunkState: mState = IfElseBodyState; return true;
case WhileEndState: mState = WhileBodyState; return true; case WhileEndState: mState = WhileBodyState; return true;
@ -243,7 +250,13 @@ namespace Compiler
default: ; 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); return Parser::parseSpecial (code, loc, scanner);

View file

@ -26,7 +26,8 @@ namespace Compiler
IfElseEndState, IfElseBodyState, IfElseEndState, IfElseBodyState,
IfEndifState, IfEndifState,
WhileEndState, WhileBodyState, WhileEndState, WhileBodyState,
WhileEndwhileState WhileEndwhileState,
IfElseJunkState
}; };
typedef std::vector<Interpreter::Type_Code> Codes; typedef std::vector<Interpreter::Type_Code> Codes;
@ -47,7 +48,7 @@ namespace Compiler
public: public:
ControlParser (ErrorHandler& errorHandler, Context& context, Locals& locals, ControlParser (ErrorHandler& errorHandler, const Context& context, Locals& locals,
Literals& literals); Literals& literals);
void appendCode (std::vector<Interpreter::Type_Code>& code) const; void appendCode (std::vector<Interpreter::Type_Code>& code) const;

View file

@ -0,0 +1,83 @@
#include "declarationparser.hpp"
#include <components/misc/stringops.hpp>
#include "scanner.hpp"
#include "errorhandler.hpp"
#include "skipparser.hpp"
#include "locals.hpp"
Compiler::DeclarationParser::DeclarationParser (ErrorHandler& errorHandler, const 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);
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);
}
void Compiler::DeclarationParser::reset()
{
mState = State_Begin;
}

View file

@ -0,0 +1,43 @@
#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, const 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?
void reset();
};
}
#endif

View file

@ -5,7 +5,7 @@ namespace Compiler
{ {
// constructor // constructor
ErrorHandler::ErrorHandler() : mWarnings (0), mErrors (0) {} ErrorHandler::ErrorHandler() : mWarnings (0), mErrors (0), mWarningsMode (1) {}
// destructor // destructor
@ -35,10 +35,15 @@ namespace Compiler
// Generate a warning message. // Generate a warning message.
void ErrorHandler::warning (const std::string& message, const TokenLoc& loc) void ErrorHandler::warning (const std::string& message, const TokenLoc& loc)
{
if (mWarningsMode==1)
{ {
++mWarnings; ++mWarnings;
report (message, loc, WarningMessage); report (message, loc, WarningMessage);
} }
else if (mWarningsMode==2)
error (message, loc);
}
// Generate an error message. // Generate an error message.
@ -62,4 +67,9 @@ namespace Compiler
{ {
mErrors = mWarnings = 0; mErrors = mWarnings = 0;
} }
void ErrorHandler::setWarningsMode (int mode)
{
mWarningsMode = mode;
}
} }

View file

@ -16,6 +16,7 @@ namespace Compiler
{ {
int mWarnings; int mWarnings;
int mErrors; int mErrors;
int mWarningsMode;
protected: protected:
@ -62,6 +63,9 @@ namespace Compiler
virtual void reset(); virtual void reset();
///< Remove all previous error/warning events ///< Remove all previous error/warning events
void setWarningsMode (int mode);
///< // 0 ignore, 1 rate as warning, 2 rate as error
}; };
} }

View file

@ -7,6 +7,8 @@
#include <stack> #include <stack>
#include <iterator> #include <iterator>
#include <components/misc/stringops.hpp>
#include "generator.hpp" #include "generator.hpp"
#include "scanner.hpp" #include "scanner.hpp"
#include "errorhandler.hpp" #include "errorhandler.hpp"
@ -14,7 +16,6 @@
#include "stringparser.hpp" #include "stringparser.hpp"
#include "extensions.hpp" #include "extensions.hpp"
#include "context.hpp" #include "context.hpp"
#include <components/misc/stringops.hpp>
namespace Compiler namespace Compiler
{ {
@ -203,21 +204,22 @@ namespace Compiler
std::string name2 = Misc::StringUtils::lowerCase (name); std::string name2 = Misc::StringUtils::lowerCase (name);
std::string id = Misc::StringUtils::lowerCase (mExplicit); std::string id = Misc::StringUtils::lowerCase (mExplicit);
char type = getContext().getMemberType (name2, id); std::pair<char, bool> 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; mNextOperand = false;
mExplicit.clear(); mExplicit.clear();
mOperands.push_back (type=='f' ? 'f' : 'l'); mOperands.push_back (type.first=='f' ? 'f' : 'l');
return true; return true;
} }
return false; return false;
} }
ExprParser::ExprParser (ErrorHandler& errorHandler, Context& context, Locals& locals, ExprParser::ExprParser (ErrorHandler& errorHandler, const Context& context, Locals& locals,
Literals& literals, bool argument) Literals& literals, bool argument)
: Parser (errorHandler, context), mLocals (locals), mLiterals (literals), : Parser (errorHandler, context), mLocals (locals), mLiterals (literals),
mNextOperand (true), mFirst (true), mArgument (argument), mRefOp (false), mMemberOp (false) mNextOperand (true), mFirst (true), mArgument (argument), mRefOp (false), mMemberOp (false)
@ -308,6 +310,22 @@ namespace Compiler
return true; 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)) if (mExplicit.empty() && getContext().isId (name2))
{ {
mExplicit = name2; mExplicit = name2;
@ -326,6 +344,31 @@ namespace Compiler
bool ExprParser::parseKeyword (int keyword, const TokenLoc& loc, Scanner& scanner) 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);
}
}
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);
}
mFirst = false; mFirst = false;
if (!mExplicit.empty()) if (!mExplicit.empty())
@ -368,8 +411,15 @@ namespace Compiler
char returnType; char returnType;
std::string argumentType; 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(); start();
mTokenLoc = loc; mTokenLoc = loc;
@ -490,7 +540,9 @@ namespace Compiler
char returnType; char returnType;
std::string argumentType; std::string argumentType;
if (extensions->isFunction (keyword, returnType, argumentType, false)) bool hasExplicit = false;
if (extensions->isFunction (keyword, returnType, argumentType, hasExplicit))
{ {
mTokenLoc = loc; mTokenLoc = loc;
int optionals = parseArguments (argumentType, scanner); int optionals = parseArguments (argumentType, scanner);
@ -518,6 +570,14 @@ namespace Compiler
{ {
if (!mExplicit.empty()) 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) if (!mRefOp && code==Scanner::S_ref)
{ {
mRefOp = true; mRefOp = true;
@ -687,11 +747,11 @@ namespace Compiler
{ {
optional = true; optional = true;
} }
else if (*iter=='S' || *iter=='c') else if (*iter=='S' || *iter=='c' || *iter=='x')
{ {
stringParser.reset(); stringParser.reset();
if (optional) if (optional || *iter=='x')
stringParser.setOptional (true); stringParser.setOptional (true);
if (*iter=='c') stringParser.smashCase(); if (*iter=='c') stringParser.smashCase();
@ -700,6 +760,8 @@ namespace Compiler
if (optional && stringParser.isEmpty()) if (optional && stringParser.isEmpty())
break; break;
if (*iter!='x')
{
if (invert) if (invert)
{ {
std::vector<Interpreter::Type_Code> tmp; std::vector<Interpreter::Type_Code> tmp;
@ -713,6 +775,7 @@ namespace Compiler
if (optional) if (optional)
++optionalCount; ++optionalCount;
} }
}
else else
{ {
parser.reset(); parser.reset();

View file

@ -58,7 +58,7 @@ namespace Compiler
public: public:
ExprParser (ErrorHandler& errorHandler, Context& context, Locals& locals, ExprParser (ErrorHandler& errorHandler, const Context& context, Locals& locals,
Literals& literals, bool argument = false); Literals& literals, bool argument = false);
///< constructor ///< constructor
/// \param argument Parser is used to parse function- or instruction- /// \param argument Parser is used to parse function- or instruction-
@ -101,6 +101,7 @@ namespace Compiler
/// \param arguments Each character represents one arguments ('l': integer, /// \param arguments Each character represents one arguments ('l': integer,
/// 'f': float, 'S': string, 'c': string (case smashed), '/': following arguments are /// 'f': float, 'S': string, 'c': string (case smashed), '/': following arguments are
/// optional) /// optional)
/// 'x': optional string that will be ignored (die in a fire, MW script compiler!)
/// \param invert Store arguments in reverted order. /// \param invert Store arguments in reverted order.
/// \return number of optional arguments /// \return number of optional arguments
}; };

View file

@ -22,7 +22,7 @@ namespace Compiler
} }
bool Extensions::isFunction (int keyword, char& returnType, std::string& argumentType, bool Extensions::isFunction (int keyword, char& returnType, std::string& argumentType,
bool explicitReference) const bool& explicitReference) const
{ {
std::map<int, Function>::const_iterator iter = mFunctions.find (keyword); std::map<int, Function>::const_iterator iter = mFunctions.find (keyword);
@ -30,7 +30,7 @@ namespace Compiler
return false; return false;
if (explicitReference && iter->second.mCodeExplicit==-1) if (explicitReference && iter->second.mCodeExplicit==-1)
return false; explicitReference = false;
returnType = iter->second.mReturn; returnType = iter->second.mReturn;
argumentType = iter->second.mArguments; argumentType = iter->second.mArguments;
@ -38,7 +38,7 @@ namespace Compiler
} }
bool Extensions::isInstruction (int keyword, std::string& argumentType, bool Extensions::isInstruction (int keyword, std::string& argumentType,
bool explicitReference) const bool& explicitReference) const
{ {
std::map<int, Instruction>::const_iterator iter = mInstructions.find (keyword); std::map<int, Instruction>::const_iterator iter = mInstructions.find (keyword);
@ -46,7 +46,7 @@ namespace Compiler
return false; return false;
if (explicitReference && iter->second.mCodeExplicit==-1) if (explicitReference && iter->second.mCodeExplicit==-1)
return false; explicitReference = false;
argumentType = iter->second.mArguments; argumentType = iter->second.mArguments;
return true; return true;

View file

@ -47,13 +47,17 @@ namespace Compiler
/// - keyword must be all lower case. /// - keyword must be all lower case.
bool isFunction (int keyword, char& returnType, std::string& argumentType, 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 ///< Is this keyword registered with a function? If yes, return return and argument
/// types. /// 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 isInstruction (int keyword, std::string& argumentType,
bool explicitReference) const; bool& explicitReference) const;
///< Is this keyword registered with a function? If yes, return argument types. ///< 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, void registerFunction (const std::string& keyword, char returnType,
const std::string& argumentType, int code, int codeExplicit = -1); const std::string& argumentType, int code, int codeExplicit = -1);

View file

@ -41,7 +41,7 @@ namespace Compiler
opcodeAiEscortCellExplicit); opcodeAiEscortCellExplicit);
extensions.registerInstruction ("aiwander", "fff/llllllllll", opcodeAiWander, extensions.registerInstruction ("aiwander", "fff/llllllllll", opcodeAiWander,
opcodeAiWanderExplicit); opcodeAiWanderExplicit);
extensions.registerInstruction ("aifollow", "cffff/l", opcodeAiFollow, extensions.registerInstruction ("aifollow", "cffff/llllllll", opcodeAiFollow,
opcodeAiFollowExplicit); opcodeAiFollowExplicit);
extensions.registerInstruction ("aifollowcell", "ccffff/l", opcodeAiFollowCell, extensions.registerInstruction ("aifollowcell", "ccffff/l", opcodeAiFollowCell,
opcodeAiFollowCellExplicit); opcodeAiFollowCellExplicit);
@ -62,7 +62,7 @@ namespace Compiler
extensions.registerInstruction ("toggleai", "", opcodeToggleAI, opcodeToggleAI); extensions.registerInstruction ("toggleai", "", opcodeToggleAI, opcodeToggleAI);
extensions.registerInstruction ("tai", "", opcodeToggleAI, opcodeToggleAI); extensions.registerInstruction ("tai", "", opcodeToggleAI, opcodeToggleAI);
extensions.registerInstruction("startcombat", "c", opcodeStartCombat, opcodeStartCombatExplicit); 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 ("gethello", 'l', "", opcodeGetHello, opcodeGetHelloExplicit);
extensions.registerFunction ("getfight", 'l', "", opcodeGetFight, opcodeGetFightExplicit); extensions.registerFunction ("getfight", 'l', "", opcodeGetFight, opcodeGetFightExplicit);
extensions.registerFunction ("getflee", 'l', "", opcodeGetFlee, opcodeGetFleeExplicit); extensions.registerFunction ("getflee", 'l', "", opcodeGetFlee, opcodeGetFleeExplicit);
@ -253,7 +253,7 @@ namespace Compiler
extensions.registerFunction ("getlocked", 'l', "", opcodeGetLocked, opcodeGetLockedExplicit); extensions.registerFunction ("getlocked", 'l', "", opcodeGetLocked, opcodeGetLockedExplicit);
extensions.registerFunction ("geteffect", 'l', "S", opcodeGetEffect, opcodeGetEffectExplicit); extensions.registerFunction ("geteffect", 'l', "S", opcodeGetEffect, opcodeGetEffectExplicit);
extensions.registerInstruction ("addsoulgem", "cc", opcodeAddSoulGem, opcodeAddSoulGemExplicit); 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 ("drop", "cl", opcodeDrop, opcodeDropExplicit);
extensions.registerInstruction ("dropsoulgem", "c", opcodeDropSoulGem, opcodeDropSoulGemExplicit); extensions.registerInstruction ("dropsoulgem", "c", opcodeDropSoulGem, opcodeDropSoulGemExplicit);
extensions.registerFunction ("getattacked", 'l', "", opcodeGetAttacked, opcodeGetAttackedExplicit); extensions.registerFunction ("getattacked", 'l', "", opcodeGetAttacked, opcodeGetAttackedExplicit);
@ -276,6 +276,8 @@ namespace Compiler
extensions.registerInstruction("togglegodmode", "", opcodeToggleGodMode); extensions.registerInstruction("togglegodmode", "", opcodeToggleGodMode);
extensions.registerInstruction ("disablelevitation", "", opcodeDisableLevitation); extensions.registerInstruction ("disablelevitation", "", opcodeDisableLevitation);
extensions.registerInstruction ("enablelevitation", "", opcodeEnableLevitation); extensions.registerInstruction ("enablelevitation", "", opcodeEnableLevitation);
extensions.registerFunction ("getpcinjail", 'l', "", opcodeGetPcInJail);
extensions.registerFunction ("getpctraveling", 'l', "", opcodeGetPcTraveling);
} }
} }
@ -396,7 +398,7 @@ namespace Compiler
extensions.registerInstruction ("setpccrimelevel", "f", opcodeSetPCCrimeLevel); extensions.registerInstruction ("setpccrimelevel", "f", opcodeSetPCCrimeLevel);
extensions.registerInstruction ("modpccrimelevel", "f", opcodeModPCCrimeLevel); extensions.registerInstruction ("modpccrimelevel", "f", opcodeModPCCrimeLevel);
extensions.registerInstruction ("addspell", "c", opcodeAddSpell, opcodeAddSpellExplicit); extensions.registerInstruction ("addspell", "cx", opcodeAddSpell, opcodeAddSpellExplicit);
extensions.registerInstruction ("removespell", "c", opcodeRemoveSpell, extensions.registerInstruction ("removespell", "c", opcodeRemoveSpell,
opcodeRemoveSpellExplicit); opcodeRemoveSpellExplicit);
extensions.registerInstruction ("removespelleffects", "c", opcodeRemoveSpellEffects, extensions.registerInstruction ("removespelleffects", "c", opcodeRemoveSpellEffects,

View file

@ -260,34 +260,34 @@ namespace
code.push_back (Compiler::Generator::segment5 (44)); 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) void opRandom (Compiler::Generator::CodeContainer& code)
@ -593,7 +593,7 @@ namespace Compiler
else if (offset<0) else if (offset<0)
opJumpBackward (code, -offset); opJumpBackward (code, -offset);
else else
throw std::logic_error ("inifite loop"); throw std::logic_error ("infinite loop");
} }
void jumpOnZero (CodeContainer& code, int offset) void jumpOnZero (CodeContainer& code, int offset)
@ -738,7 +738,8 @@ namespace Compiler
} }
void assignToMember (CodeContainer& code, Literals& literals, char localType, 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); int index = literals.addString (name);
@ -766,17 +767,17 @@ namespace Compiler
{ {
case 'f': case 'f':
opStoreMemberFloat (code); opStoreMemberFloat (code, global);
break; break;
case 's': case 's':
opStoreMemberShort (code); opStoreMemberShort (code, global);
break; break;
case 'l': case 'l':
opStoreMemberLong (code); opStoreMemberLong (code, global);
break; break;
default: default:
@ -786,7 +787,7 @@ namespace Compiler
} }
void fetchMember (CodeContainer& code, Literals& literals, char localType, 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); int index = literals.addString (name);
@ -800,17 +801,17 @@ namespace Compiler
{ {
case 'f': case 'f':
opFetchMemberFloat (code); opFetchMemberFloat (code, global);
break; break;
case 's': case 's':
opFetchMemberShort (code); opFetchMemberShort (code, global);
break; break;
case 'l': case 'l':
opFetchMemberLong (code); opFetchMemberLong (code, global);
break; break;
default: default:

View file

@ -102,10 +102,12 @@ namespace Compiler
const std::string& name); const std::string& name);
void assignToMember (CodeContainer& code, Literals& literals, char memberType, 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, 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); void random (CodeContainer& code);

View file

@ -1,6 +1,8 @@
#include "lineparser.hpp" #include "lineparser.hpp"
#include <components/misc/stringops.hpp>
#include "scanner.hpp" #include "scanner.hpp"
#include "context.hpp" #include "context.hpp"
#include "errorhandler.hpp" #include "errorhandler.hpp"
@ -8,7 +10,7 @@
#include "locals.hpp" #include "locals.hpp"
#include "generator.hpp" #include "generator.hpp"
#include "extensions.hpp" #include "extensions.hpp"
#include <components/misc/stringops.hpp> #include "declarationparser.hpp"
namespace Compiler namespace Compiler
{ {
@ -48,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<Interpreter::Type_Code>& code, bool allowExpression) Literals& literals, std::vector<Interpreter::Type_Code>& code, bool allowExpression)
: Parser (errorHandler, context), mLocals (locals), mLiterals (literals), mCode (code), : Parser (errorHandler, context), mLocals (locals), mLiterals (literals), mCode (code),
mState (BeginState), mExprParser (errorHandler, context, locals, literals), mState (BeginState), mExprParser (errorHandler, context, locals, literals),
@ -82,33 +84,9 @@ namespace Compiler
bool LineParser::parseName (const std::string& name, const TokenLoc& loc, bool LineParser::parseName (const std::string& name, const TokenLoc& loc,
Scanner& scanner) Scanner& scanner)
{ {
if (mState==ShortState || mState==LongState || mState==FloatState) if (mState==PotentialEndState)
{ {
if (!getContext().canDeclareLocals()) getErrorHandler().warning ("stay string argument (ignoring it)", loc);
{
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; mState = EndState;
return true; return true;
} }
@ -142,12 +120,13 @@ namespace Compiler
if (mState==SetMemberVarState) if (mState==SetMemberVarState)
{ {
mMemberName = name; mMemberName = name;
char type = getContext().getMemberType (mMemberName, mName); std::pair<char, bool> type = getContext().getMemberType (mMemberName, mName);
if (type!=' ') if (type.first!=' ')
{ {
mState = SetMemberVarState2; mState = SetMemberVarState2;
mType = type; mType = type.first;
mReferenceMember = type.second;
return true; return true;
} }
@ -240,6 +219,34 @@ namespace Compiler
bool LineParser::parseKeyword (int keyword, const TokenLoc& loc, Scanner& scanner) bool LineParser::parseKeyword (int keyword, const TokenLoc& loc, Scanner& scanner)
{ {
if (mState==SetMemberVarState)
{
mMemberName = loc.mLiteral;
std::pair<char, bool> 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);
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.
return parseName (loc.mLiteral, loc, scanner);
}
if (mState==BeginState || mState==ExplicitState) if (mState==BeginState || mState==ExplicitState)
{ {
switch (keyword) switch (keyword)
@ -247,13 +254,13 @@ namespace Compiler
case Scanner::K_enable: case Scanner::K_enable:
Generator::enable (mCode, mLiterals, mExplicit); Generator::enable (mCode, mLiterals, mExplicit);
mState = EndState; mState = PotentialEndState;
return true; return true;
case Scanner::K_disable: case Scanner::K_disable:
Generator::disable (mCode, mLiterals, mExplicit); Generator::disable (mCode, mLiterals, mExplicit);
mState = EndState; mState = PotentialEndState;
return true; return true;
} }
@ -262,8 +269,15 @@ namespace Compiler
{ {
std::string argumentType; 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); int optionals = mExprParser.parseArguments (argumentType, scanner, mCode, true);
extensions->generateInstructionCode (keyword, mCode, mLiterals, mExplicit, optionals); extensions->generateInstructionCode (keyword, mCode, mLiterals, mExplicit, optionals);
@ -287,9 +301,16 @@ namespace Compiler
char returnType; char returnType;
std::string argumentType; std::string argumentType;
if (extensions->isFunction (keyword, returnType, argumentType, bool hasExplicit = !mExplicit.empty();
!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); scanner.putbackKeyword (keyword, loc);
parseExpression (scanner, loc); parseExpression (scanner, loc);
mState = EndState; mState = EndState;
@ -299,13 +320,38 @@ namespace Compiler
} }
} }
if (mState==ExplicitState)
{
// drop stray explicit reference
getErrorHandler().warning ("stray explicit reference (ignoring it)", loc);
mState = BeginState;
mExplicit.clear();
}
if (mState==BeginState) if (mState==BeginState)
{ {
switch (keyword) switch (keyword)
{ {
case Scanner::K_short: mState = ShortState; return true; case Scanner::K_short:
case Scanner::K_long: mState = LongState; return true; case Scanner::K_long:
case Scanner::K_float: mState = FloatState; return true; 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_set: mState = SetState; return true;
case Scanner::K_messagebox: mState = MessageState; return true; case Scanner::K_messagebox: mState = MessageState; return true;
@ -328,6 +374,24 @@ namespace Compiler
Generator::stopScript (mCode); Generator::stopScript (mCode);
mState = EndState; mState = EndState;
return true; 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;
case Scanner::K_begin:
getErrorHandler().warning ("stay begin (ignoring it)", loc);
mState = EndState;
return true;
} }
} }
else if (mState==SetLocalVarState && keyword==Scanner::K_to) else if (mState==SetLocalVarState && keyword==Scanner::K_to)
@ -365,7 +429,8 @@ namespace Compiler
std::vector<Interpreter::Type_Code> code; std::vector<Interpreter::Type_Code> code;
char type = mExprParser.append (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; mState = EndState;
return true; return true;
@ -389,7 +454,8 @@ namespace Compiler
bool LineParser::parseSpecial (int code, const TokenLoc& loc, Scanner& scanner) 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; return false;
if (code==Scanner::S_comma && mState==MessageState) if (code==Scanner::S_comma && mState==MessageState)

View file

@ -20,11 +20,10 @@ namespace Compiler
enum State enum State
{ {
BeginState, BeginState,
ShortState, LongState, FloatState,
SetState, SetLocalVarState, SetGlobalVarState, SetPotentialMemberVarState, SetState, SetLocalVarState, SetGlobalVarState, SetPotentialMemberVarState,
SetMemberVarState, SetMemberVarState2, SetMemberVarState, SetMemberVarState2,
MessageState, MessageCommaState, MessageButtonState, MessageButtonCommaState, MessageState, MessageCommaState, MessageButtonState, MessageButtonCommaState,
EndState, EndState, PotentialEndState /* may have a stray string argument */,
PotentialExplicitState, ExplicitState, MemberState PotentialExplicitState, ExplicitState, MemberState
}; };
@ -34,6 +33,7 @@ namespace Compiler
State mState; State mState;
std::string mName; std::string mName;
std::string mMemberName; std::string mMemberName;
bool mReferenceMember;
int mButtons; int mButtons;
std::string mExplicit; std::string mExplicit;
char mType; char mType;
@ -44,7 +44,7 @@ namespace Compiler
public: public:
LineParser (ErrorHandler& errorHandler, Context& context, Locals& locals, LineParser (ErrorHandler& errorHandler, const Context& context, Locals& locals,
Literals& literals, std::vector<Interpreter::Type_Code>& code, Literals& literals, std::vector<Interpreter::Type_Code>& code,
bool allowExpression = false); bool allowExpression = false);
///< \param allowExpression Allow lines consisting of a naked expression ///< \param allowExpression Allow lines consisting of a naked expression

View file

@ -7,6 +7,8 @@
#include <ostream> #include <ostream>
#include <iterator> #include <iterator>
#include <components/misc/stringops.hpp>
namespace Compiler namespace Compiler
{ {
const std::vector<std::string>& Locals::get (char type) const const std::vector<std::string>& Locals::get (char type) const
@ -97,7 +99,7 @@ namespace Compiler
void Locals::declare (char type, const std::string& name) 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() void Locals::clear()

View file

@ -203,8 +203,8 @@ namespace Compiler
const int opcodeGetEffectExplicit = 0x20001d0; const int opcodeGetEffectExplicit = 0x20001d0;
const int opcodeAddSoulGem = 0x20001f3; const int opcodeAddSoulGem = 0x20001f3;
const int opcodeAddSoulGemExplicit = 0x20001f4; const int opcodeAddSoulGemExplicit = 0x20001f4;
const int opcodeRemoveSoulGem = 0x20001f5; const int opcodeRemoveSoulGem = 0x20027;
const int opcodeRemoveSoulGemExplicit = 0x20001f6; const int opcodeRemoveSoulGemExplicit = 0x20028;
const int opcodeDrop = 0x20001f8; const int opcodeDrop = 0x20001f8;
const int opcodeDropExplicit = 0x20001f9; const int opcodeDropExplicit = 0x20001f9;
const int opcodeDropSoulGem = 0x20001fa; const int opcodeDropSoulGem = 0x20001fa;
@ -245,6 +245,8 @@ namespace Compiler
const int opcodeCastExplicit = 0x2000228; const int opcodeCastExplicit = 0x2000228;
const int opcodeExplodeSpell = 0x2000229; const int opcodeExplodeSpell = 0x2000229;
const int opcodeExplodeSpellExplicit = 0x200022a; const int opcodeExplodeSpellExplicit = 0x200022a;
const int opcodeGetPcInJail = 0x200023e;
const int opcodeGetPcTraveling = 0x200023f;
} }
namespace Sky namespace Sky

View file

@ -52,7 +52,7 @@ namespace Compiler
// Return context // Return context
Context& Parser::getContext() const Context& Parser::getContext() const
{ {
return mContext; return mContext;
} }
@ -64,7 +64,7 @@ namespace Compiler
return lowerCase; return lowerCase;
} }
Parser::Parser (ErrorHandler& errorHandler, Context& context) Parser::Parser (ErrorHandler& errorHandler, const Context& context)
: mErrorHandler (errorHandler), mContext (context), mOptional (false), mEmpty (true) : mErrorHandler (errorHandler), mContext (context), mOptional (false), mEmpty (true)
{} {}

View file

@ -17,7 +17,7 @@ namespace Compiler
class Parser class Parser
{ {
ErrorHandler& mErrorHandler; ErrorHandler& mErrorHandler;
Context& mContext; const Context& mContext;
bool mOptional; bool mOptional;
bool mEmpty; bool mEmpty;
@ -38,14 +38,14 @@ namespace Compiler
ErrorHandler& getErrorHandler(); ErrorHandler& getErrorHandler();
///< Return error handler ///< Return error handler
Context& getContext(); const Context& getContext() const;
///< Return context ///< Return context
static std::string toLower (const std::string& name); static std::string toLower (const std::string& name);
public: public:
Parser (ErrorHandler& errorHandler, Context& context); Parser (ErrorHandler& errorHandler, const Context& context);
///< constructor ///< constructor
virtual ~Parser(); virtual ~Parser();

View file

@ -0,0 +1,52 @@
#include "quickfileparser.hpp"
#include "skipparser.hpp"
#include "scanner.hpp"
Compiler::QuickFileParser::QuickFileParser (ErrorHandler& errorHandler, const 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)
{
}

View file

@ -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, const 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

View file

@ -370,9 +370,9 @@ namespace Compiler
if (c=='\n') if (c=='\n')
special = S_newline; special = S_newline;
else if (c=='(') else if (c=='(' || c=='[') /// \todo option to disable the use of [ as alias for (
special = S_open; special = S_open;
else if (c==')') else if (c==')' || c==']') /// \todo option to disable the use of ] as alias for )
special = S_close; special = S_close;
else if (c=='.') else if (c=='.')
{ {

View file

@ -7,7 +7,7 @@
namespace Compiler namespace Compiler
{ {
ScriptParser::ScriptParser (ErrorHandler& errorHandler, Context& context, ScriptParser::ScriptParser (ErrorHandler& errorHandler, const Context& context,
Locals& locals, bool end) Locals& locals, bool end)
: Parser (errorHandler, context), mOutput (locals), : Parser (errorHandler, context), mOutput (locals),
mLineParser (errorHandler, context, locals, mOutput.getLiterals(), mOutput.getCode()), mLineParser (errorHandler, context, locals, mOutput.getLiterals(), mOutput.getCode()),
@ -32,7 +32,7 @@ namespace Compiler
bool ScriptParser::parseKeyword (int keyword, const TokenLoc& loc, Scanner& scanner) 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(); mControlParser.reset();
if (mControlParser.parseKeyword (keyword, loc, scanner)) if (mControlParser.parseKeyword (keyword, loc, scanner))
@ -71,6 +71,12 @@ namespace Compiler
if (code==Scanner::S_newline) // empty line if (code==Scanner::S_newline) // empty line
return true; 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(); mLineParser.reset();
if (mLineParser.parseSpecial (code, loc, scanner)) if (mLineParser.parseSpecial (code, loc, scanner))
scanner.scan (mLineParser); scanner.scan (mLineParser);

View file

@ -23,7 +23,7 @@ namespace Compiler
public: public:
/// \param end of script is marked by end keyword. /// \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); bool end = false);
void getCode (std::vector<Interpreter::Type_Code>& code) const; void getCode (std::vector<Interpreter::Type_Code>& code) const;

View file

@ -5,7 +5,7 @@
namespace Compiler namespace Compiler
{ {
SkipParser::SkipParser (ErrorHandler& errorHandler, Context& context) SkipParser::SkipParser (ErrorHandler& errorHandler, const Context& context)
: Parser (errorHandler, context) : Parser (errorHandler, context)
{} {}

View file

@ -13,7 +13,7 @@ namespace Compiler
{ {
public: public:
SkipParser (ErrorHandler& errorHandler, Context& context); SkipParser (ErrorHandler& errorHandler, const Context& context);
virtual bool parseInt (int value, const TokenLoc& loc, Scanner& scanner); virtual bool parseInt (int value, const TokenLoc& loc, Scanner& scanner);
///< Handle an int token. ///< Handle an int token.

View file

@ -10,7 +10,7 @@
namespace Compiler 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) : Parser (errorHandler, context), mLiterals (literals), mState (StartState), mSmashCase (false)
{ {

View file

@ -25,7 +25,7 @@ namespace Compiler
public: 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, virtual bool parseName (const std::string& name, const TokenLoc& loc,
Scanner& scanner); Scanner& scanner);

View file

@ -96,17 +96,17 @@ namespace Interpreter
virtual void disable (const std::string& id = "") = 0; 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; = 0;
}; };
} }

View file

@ -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 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 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] 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 opcodes 33554432-67108863 reserved for extensions

View file

@ -40,12 +40,18 @@ namespace Interpreter
interpreter.installSegment5 (42, new OpFetchGlobalShort); interpreter.installSegment5 (42, new OpFetchGlobalShort);
interpreter.installSegment5 (43, new OpFetchGlobalLong); interpreter.installSegment5 (43, new OpFetchGlobalLong);
interpreter.installSegment5 (44, new OpFetchGlobalFloat); interpreter.installSegment5 (44, new OpFetchGlobalFloat);
interpreter.installSegment5 (59, new OpStoreMemberShort); interpreter.installSegment5 (59, new OpStoreMemberShort (false));
interpreter.installSegment5 (60, new OpStoreMemberLong); interpreter.installSegment5 (60, new OpStoreMemberLong (false));
interpreter.installSegment5 (61, new OpStoreMemberFloat); interpreter.installSegment5 (61, new OpStoreMemberFloat (false));
interpreter.installSegment5 (62, new OpFetchMemberShort); interpreter.installSegment5 (62, new OpFetchMemberShort (false));
interpreter.installSegment5 (63, new OpFetchMemberLong); interpreter.installSegment5 (63, new OpFetchMemberLong (false));
interpreter.installSegment5 (64, new OpFetchMemberFloat); 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 // math
interpreter.installSegment5 (9, new OpAddInt<Type_Integer>); interpreter.installSegment5 (9, new OpAddInt<Type_Integer>);

View file

@ -208,8 +208,12 @@ namespace Interpreter
class OpStoreMemberShort : public Opcode0 class OpStoreMemberShort : public Opcode0
{ {
bool mGlobal;
public: public:
OpStoreMemberShort (bool global) : mGlobal (global) {}
virtual void execute (Runtime& runtime) virtual void execute (Runtime& runtime)
{ {
Type_Integer data = runtime[0].mInteger; Type_Integer data = runtime[0].mInteger;
@ -218,7 +222,7 @@ namespace Interpreter
index = runtime[2].mInteger; index = runtime[2].mInteger;
std::string variable = runtime.getStringLiteral (index); std::string variable = runtime.getStringLiteral (index);
runtime.getContext().setMemberShort (id, variable, data); runtime.getContext().setMemberShort (id, variable, data, mGlobal);
runtime.pop(); runtime.pop();
runtime.pop(); runtime.pop();
@ -228,8 +232,12 @@ namespace Interpreter
class OpStoreMemberLong : public Opcode0 class OpStoreMemberLong : public Opcode0
{ {
bool mGlobal;
public: public:
OpStoreMemberLong (bool global) : mGlobal (global) {}
virtual void execute (Runtime& runtime) virtual void execute (Runtime& runtime)
{ {
Type_Integer data = runtime[0].mInteger; Type_Integer data = runtime[0].mInteger;
@ -238,7 +246,7 @@ namespace Interpreter
index = runtime[2].mInteger; index = runtime[2].mInteger;
std::string variable = runtime.getStringLiteral (index); std::string variable = runtime.getStringLiteral (index);
runtime.getContext().setMemberLong (id, variable, data); runtime.getContext().setMemberLong (id, variable, data, mGlobal);
runtime.pop(); runtime.pop();
runtime.pop(); runtime.pop();
@ -248,8 +256,12 @@ namespace Interpreter
class OpStoreMemberFloat : public Opcode0 class OpStoreMemberFloat : public Opcode0
{ {
bool mGlobal;
public: public:
OpStoreMemberFloat (bool global) : mGlobal (global) {}
virtual void execute (Runtime& runtime) virtual void execute (Runtime& runtime)
{ {
Type_Float data = runtime[0].mFloat; Type_Float data = runtime[0].mFloat;
@ -258,7 +270,7 @@ namespace Interpreter
index = runtime[2].mInteger; index = runtime[2].mInteger;
std::string variable = runtime.getStringLiteral (index); std::string variable = runtime.getStringLiteral (index);
runtime.getContext().setMemberFloat (id, variable, data); runtime.getContext().setMemberFloat (id, variable, data, mGlobal);
runtime.pop(); runtime.pop();
runtime.pop(); runtime.pop();
@ -268,8 +280,12 @@ namespace Interpreter
class OpFetchMemberShort : public Opcode0 class OpFetchMemberShort : public Opcode0
{ {
bool mGlobal;
public: public:
OpFetchMemberShort (bool global) : mGlobal (global) {}
virtual void execute (Runtime& runtime) virtual void execute (Runtime& runtime)
{ {
Type_Integer index = runtime[0].mInteger; Type_Integer index = runtime[0].mInteger;
@ -278,15 +294,19 @@ namespace Interpreter
std::string variable = runtime.getStringLiteral (index); std::string variable = runtime.getStringLiteral (index);
runtime.pop(); runtime.pop();
int value = runtime.getContext().getMemberShort (id, variable); int value = runtime.getContext().getMemberShort (id, variable, mGlobal);
runtime[0].mInteger = value; runtime[0].mInteger = value;
} }
}; };
class OpFetchMemberLong : public Opcode0 class OpFetchMemberLong : public Opcode0
{ {
bool mGlobal;
public: public:
OpFetchMemberLong (bool global) : mGlobal (global) {}
virtual void execute (Runtime& runtime) virtual void execute (Runtime& runtime)
{ {
Type_Integer index = runtime[0].mInteger; Type_Integer index = runtime[0].mInteger;
@ -295,15 +315,19 @@ namespace Interpreter
std::string variable = runtime.getStringLiteral (index); std::string variable = runtime.getStringLiteral (index);
runtime.pop(); runtime.pop();
int value = runtime.getContext().getMemberLong (id, variable); int value = runtime.getContext().getMemberLong (id, variable, mGlobal);
runtime[0].mInteger = value; runtime[0].mInteger = value;
} }
}; };
class OpFetchMemberFloat : public Opcode0 class OpFetchMemberFloat : public Opcode0
{ {
bool mGlobal;
public: public:
OpFetchMemberFloat (bool global) : mGlobal (global) {}
virtual void execute (Runtime& runtime) virtual void execute (Runtime& runtime)
{ {
Type_Integer index = runtime[0].mInteger; Type_Integer index = runtime[0].mInteger;
@ -312,7 +336,7 @@ namespace Interpreter
std::string variable = runtime.getStringLiteral (index); std::string variable = runtime.getStringLiteral (index);
runtime.pop(); runtime.pop();
float value = runtime.getContext().getMemberFloat (id, variable); float value = runtime.getContext().getMemberFloat (id, variable, mGlobal);
runtime[0].mFloat = value; runtime[0].mFloat = value;
} }
}; };

View file

@ -67,7 +67,13 @@ Allowed options:
--script-run arg select a file containing a list of --script-run arg select a file containing a list of
console commands that is executed on console commands that is executed on
startup startup
--new-game [=arg(=1)] (=0) activate char gen/new game mechanics --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
--skip-menu [=arg(=1)] (=0) skip main menu on game startup
--fs-strict [=arg(=1)] (=0) strict file system handling (no case --fs-strict [=arg(=1)] (=0) strict file system handling (no case
folding) folding)
--encoding arg (=win1252) Character encoding used in OpenMW game --encoding arg (=win1252) Character encoding used in OpenMW game