Merge branch 'script'

Conflicts:
	readme.txt
pull/22/head
Marc Zinnschlag 11 years ago
commit 6ac64bbe15

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

@ -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;
}

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

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

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

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

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

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

@ -136,6 +136,13 @@ bool parseOptions (int argc, char** argv, OMW::Engine& engine, Files::Configurat
("script-run", bpo::value<std::string>()->default_value(""),
"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)
->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.setStartupScript (variables["script-run"].as<std::string>());
engine.setActivationDistanceOverride (variables["activate-dist"].as<int>());
engine.setWarningsMode (variables["script-warn"].as<int>());
return true;
}

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

@ -30,11 +30,18 @@ namespace MWScript
/// 'l: long, 's': short, 'f': float, ' ': does not exist.
virtual char getGlobalType (const std::string& name) const;
virtual char getMemberType (const std::string& name, const std::string& id) const;
///< 'l: long, 's': short, 'f': float, ' ': does not exist.
virtual std::pair<char, bool> getMemberType (const std::string& name,
const std::string& id) const;
///< Return type of member variable \a name in script \a id or in script of reference of
/// \a id
/// \return first: 'l: long, 's': short, 'f': float, ' ': does not exist.
/// second: true: script of reference
virtual bool isId (const std::string& name) const;
///< Does \a name match an ID, that can be referenced?
virtual bool isJournalId (const std::string& name) const;
///< Does \a name match a journal ID?
};
}

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

@ -148,4 +148,25 @@ namespace MWScript
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;
}
}

@ -52,6 +52,10 @@ namespace MWScript
///< Records for variables that do not exist are dropped silently.
///
/// \return Known type?
Locals& getLocals (const std::string& name);
///< If the script \a name has not been added as a global script yet, it is added
/// automatically, but is not set to running state.
};
}

@ -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 (
MWScript::Locals *locals, MWWorld::Ptr reference)
: mLocals (locals), mReference (reference),
@ -407,82 +448,80 @@ namespace MWScript
MWBase::Environment::get().getWorld()->disable (ref);
}
int InterpreterContext::getMemberShort (const std::string& id, const std::string& name) const
int InterpreterContext::getMemberShort (const std::string& id, const std::string& name,
bool global) const
{
const MWWorld::Ptr ptr = getReference (id, false);
std::string scriptId (id);
std::string scriptId = MWWorld::Class::get (ptr).getScript (ptr);
const Locals& locals = getMemberLocals (scriptId, global);
int index = MWBase::Environment::get().getScriptManager()->getLocalIndex (scriptId, name, 's');
int index = MWBase::Environment::get().getScriptManager()->getLocalIndex (
scriptId, name, 's');
ptr.getRefData().setLocals (
*MWBase::Environment::get().getWorld()->getStore().get<ESM::Script>().find (scriptId));
return ptr.getRefData().getLocals().mShorts[index];
return locals.mShorts[index];
}
int InterpreterContext::getMemberLong (const std::string& id, const std::string& name) const
int InterpreterContext::getMemberLong (const std::string& id, const std::string& name,
bool global) const
{
const MWWorld::Ptr ptr = getReference (id, false);
std::string scriptId (id);
std::string scriptId = MWWorld::Class::get (ptr).getScript (ptr);
const Locals& locals = getMemberLocals (scriptId, global);
int index = MWBase::Environment::get().getScriptManager()->getLocalIndex (scriptId, name, 'l');
int index = MWBase::Environment::get().getScriptManager()->getLocalIndex (
scriptId, name, 'l');
ptr.getRefData().setLocals (
*MWBase::Environment::get().getWorld()->getStore().get<ESM::Script>().find (scriptId));
return ptr.getRefData().getLocals().mLongs[index];
return locals.mLongs[index];
}
float InterpreterContext::getMemberFloat (const std::string& id, const std::string& name) const
float InterpreterContext::getMemberFloat (const std::string& id, const std::string& name,
bool global) const
{
const MWWorld::Ptr ptr = getReference (id, false);
std::string scriptId (id);
std::string scriptId = MWWorld::Class::get (ptr).getScript (ptr);
const Locals& locals = getMemberLocals (scriptId, global);
int index = MWBase::Environment::get().getScriptManager()->getLocalIndex (scriptId, name, 'f');
int index = MWBase::Environment::get().getScriptManager()->getLocalIndex (
scriptId, name, 'f');
ptr.getRefData().setLocals (
*MWBase::Environment::get().getWorld()->getStore().get<ESM::Script>().find (scriptId));
return ptr.getRefData().getLocals().mFloats[index];
return locals.mFloats[index];
}
void InterpreterContext::setMemberShort (const std::string& id, const std::string& name, int value)
void InterpreterContext::setMemberShort (const std::string& id, const std::string& name,
int value, bool global)
{
const MWWorld::Ptr ptr = getReference (id, false);
std::string scriptId (id);
std::string scriptId = MWWorld::Class::get (ptr).getScript (ptr);
Locals& locals = getMemberLocals (scriptId, global);
int index = MWBase::Environment::get().getScriptManager()->getLocalIndex (scriptId, name, 's');
int index =
MWBase::Environment::get().getScriptManager()->getLocalIndex (scriptId, name, 's');
ptr.getRefData().setLocals (
*MWBase::Environment::get().getWorld()->getStore().get<ESM::Script>().find (scriptId));
ptr.getRefData().getLocals().mShorts[index] = value;
locals.mShorts[index] = value;
}
void InterpreterContext::setMemberLong (const std::string& id, const std::string& name, int value)
void InterpreterContext::setMemberLong (const std::string& id, const std::string& name, int value, bool global)
{
const MWWorld::Ptr ptr = getReference (id, false);
std::string scriptId (id);
std::string scriptId = MWWorld::Class::get (ptr).getScript (ptr);
Locals& locals = getMemberLocals (scriptId, global);
int index = MWBase::Environment::get().getScriptManager()->getLocalIndex (scriptId, name, 'l');
int index =
MWBase::Environment::get().getScriptManager()->getLocalIndex (scriptId, name, 'l');
ptr.getRefData().setLocals (
*MWBase::Environment::get().getWorld()->getStore().get<ESM::Script>().find (scriptId));
ptr.getRefData().getLocals().mLongs[index] = value;
locals.mLongs[index] = value;
}
void InterpreterContext::setMemberFloat (const std::string& id, const std::string& name, float value)
void InterpreterContext::setMemberFloat (const std::string& id, const std::string& name, float value, bool global)
{
const MWWorld::Ptr ptr = getReference (id, false);
std::string scriptId (id);
std::string scriptId = MWWorld::Class::get (ptr).getScript (ptr);
Locals& locals = getMemberLocals (scriptId, global);
int index = MWBase::Environment::get().getScriptManager()->getLocalIndex (scriptId, name, 'f');
int index =
MWBase::Environment::get().getScriptManager()->getLocalIndex (scriptId, name, 'f');
ptr.getRefData().setLocals (
*MWBase::Environment::get().getWorld()->getStore().get<ESM::Script>().find (scriptId));
ptr.getRefData().getLocals().mFloats[index] = value;
locals.mFloats[index] = value;
}
MWWorld::Ptr InterpreterContext::getReference(bool required)

@ -37,6 +37,12 @@ namespace MWScript
const MWWorld::Ptr getReference (const std::string& id, bool activeOnly, bool doThrow=true) const;
const Locals& getMemberLocals (std::string& id, bool global) const;
///< \a id is changed to the respective script ID, if \a id wasn't a script ID before
Locals& getMemberLocals (std::string& id, bool global);
///< \a id is changed to the respective script ID, if \a id wasn't a script ID before
public:
InterpreterContext (MWScript::Locals *locals, MWWorld::Ptr reference);
@ -75,35 +81,35 @@ namespace MWScript
virtual void setGlobalLong (const std::string& name, int value);
virtual void setGlobalFloat (const std::string& name, float value);
virtual std::vector<std::string> getGlobals () const;
virtual char getGlobalType (const std::string& name) const;
virtual std::string getActionBinding(const std::string& action) const;
virtual std::string getNPCName() const;
virtual std::string getNPCRace() const;
virtual std::string getNPCClass() const;
virtual std::string getNPCFaction() const;
virtual std::string getNPCRank() const;
virtual std::string getPCName() const;
virtual std::string getPCRace() const;
virtual std::string getPCClass() const;
virtual std::string getPCRank() const;
virtual std::string getPCNextRank() const;
virtual int getPCBounty() const;
virtual std::string getCurrentCellName() const;
virtual bool isScriptRunning (const std::string& name) const;
@ -138,17 +144,17 @@ namespace MWScript
virtual void disable (const std::string& id = "");
virtual int getMemberShort (const std::string& id, const std::string& name) const;
virtual int getMemberShort (const std::string& id, const std::string& name, bool global) const;
virtual int getMemberLong (const std::string& id, const std::string& name) const;
virtual int getMemberLong (const std::string& id, const std::string& name, bool global) const;
virtual float getMemberFloat (const std::string& id, const std::string& name) const;
virtual float getMemberFloat (const std::string& id, const std::string& name, bool global) const;
virtual void setMemberShort (const std::string& id, const std::string& name, int value);
virtual void setMemberShort (const std::string& id, const std::string& name, int value, bool global);
virtual void setMemberLong (const std::string& id, const std::string& name, int value);
virtual void setMemberLong (const std::string& id, const std::string& name, int value, bool global);
virtual void setMemberFloat (const std::string& id, const std::string& name, float value);
virtual void setMemberFloat (const std::string& id, const std::string& name, float value, bool global);
MWWorld::Ptr getReference(bool required=true);
///< Reference, that the script is running from (can be empty)

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

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

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

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

@ -33,11 +33,18 @@ namespace Compiler
virtual char getGlobalType (const std::string& name) const = 0;
///< 'l: long, 's': short, 'f': float, ' ': does not exist.
virtual char getMemberType (const std::string& name, const std::string& id) const = 0;
///< 'l: long, 's': short, 'f': float, ' ': does not exist.
virtual std::pair<char, bool> getMemberType (const std::string& name,
const std::string& id) const = 0;
///< Return type of member variable \a name in script \a id or in script of reference of
/// \a id
/// \return first: 'l: long, 's': short, 'f': float, ' ': does not exist.
/// second: true: script of reference
virtual bool isId (const std::string& name) const = 0;
///< Does \a name match an ID, that can be referenced?
virtual bool isJournalId (const std::string& name) const = 0;
///< Does \a name match a journal ID?
};
}

@ -7,6 +7,8 @@
#include "scanner.hpp"
#include "generator.hpp"
#include "errorhandler.hpp"
#include "skipparser.hpp"
namespace Compiler
{
@ -70,7 +72,7 @@ namespace Compiler
}
else if (keyword==Scanner::K_else)
{
mState = IfElseEndState;
mState = IfElseJunkState; /// \todo should be IfElseEndState; add an option for that
}
return true;
@ -106,7 +108,7 @@ namespace Compiler
Codes 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));
@ -120,7 +122,7 @@ namespace Compiler
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())
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)
: Parser (errorHandler, context), mLocals (locals), mLiterals (literals),
mLineParser (errorHandler, context, locals, literals, mCodeBlock),
@ -186,8 +188,11 @@ namespace Compiler
{
if (mState==StartState)
{
if (keyword==Scanner::K_if)
if (keyword==Scanner::K_if || keyword==Scanner::K_elseif)
{
if (keyword==Scanner::K_elseif)
getErrorHandler().warning ("elseif without matching if", loc);
mExprParser.reset();
scanner.scan (mExprParser);
@ -203,7 +208,8 @@ namespace Compiler
return true;
}
}
else if (mState==IfBodyState || mState==IfElseifBodyState || mState==IfElseBodyState)
else if (mState==IfBodyState || mState==IfElseifBodyState || mState==IfElseBodyState ||
mState==IfElseJunkState)
{
if (parseIfBody (keyword, loc, scanner))
return true;
@ -226,6 +232,7 @@ namespace Compiler
case IfEndState: mState = IfBodyState; return true;
case IfElseifEndState: mState = IfElseifBodyState; return true;
case IfElseEndState: mState = IfElseBodyState; return true;
case IfElseJunkState: mState = IfElseBodyState; return true;
case WhileEndState: mState = WhileBodyState; return true;
@ -243,7 +250,13 @@ namespace Compiler
default: ;
}
}
else if (code==Scanner::S_open && mState==IfElseJunkState)
{
SkipParser skip (getErrorHandler(), getContext());
scanner.scan (skip);
mState = IfElseBodyState;
return true;
}
return Parser::parseSpecial (code, loc, scanner);

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

@ -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;
}

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

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

@ -16,6 +16,7 @@ namespace Compiler
{
int mWarnings;
int mErrors;
int mWarningsMode;
protected:
@ -60,8 +61,11 @@ namespace Compiler
void endOfFile();
///< Generate an error message for an unexpected EOF.
virtual void reset();
virtual void reset();
///< Remove all previous error/warning events
void setWarningsMode (int mode);
///< // 0 ignore, 1 rate as warning, 2 rate as error
};
}

@ -7,6 +7,8 @@
#include <stack>
#include <iterator>
#include <components/misc/stringops.hpp>
#include "generator.hpp"
#include "scanner.hpp"
#include "errorhandler.hpp"
@ -14,7 +16,6 @@
#include "stringparser.hpp"
#include "extensions.hpp"
#include "context.hpp"
#include <components/misc/stringops.hpp>
namespace Compiler
{
@ -203,21 +204,22 @@ namespace Compiler
std::string name2 = Misc::StringUtils::lowerCase (name);
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;
mExplicit.clear();
mOperands.push_back (type=='f' ? 'f' : 'l');
mOperands.push_back (type.first=='f' ? 'f' : 'l');
return true;
}
return false;
}
ExprParser::ExprParser (ErrorHandler& errorHandler, Context& context, Locals& locals,
ExprParser::ExprParser (ErrorHandler& errorHandler, const Context& context, Locals& locals,
Literals& literals, bool argument)
: Parser (errorHandler, context), mLocals (locals), mLiterals (literals),
mNextOperand (true), mFirst (true), mArgument (argument), mRefOp (false), mMemberOp (false)
@ -308,6 +310,22 @@ namespace Compiler
return true;
}
// die in a fire, Morrowind script compiler!
if (const Extensions *extensions = getContext().getExtensions())
{
if (getContext().isJournalId (name2))
{
// JournalID used as an argument. Use the index of that JournalID
Generator::pushString (mCode, mLiterals, name2);
int keyword = extensions->searchKeyword ("getjournalindex");
extensions->generateFunctionCode (keyword, mCode, mLiterals, mExplicit, 0);
mNextOperand = false;
mOperands.push_back ('l');
return 2;
}
}
if (mExplicit.empty() && getContext().isId (name2))
{
mExplicit = name2;
@ -326,6 +344,31 @@ namespace Compiler
bool ExprParser::parseKeyword (int keyword, const TokenLoc& loc, Scanner& scanner)
{
if (const Extensions *extensions = getContext().getExtensions())
{
std::string argumentType; // ignored
bool hasExplicit = false; // ignored
if (extensions->isInstruction (keyword, argumentType, hasExplicit))
{
// pretend this is not a keyword
return parseName (loc.mLiteral, loc, scanner);
}
}
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;
if (!mExplicit.empty())
@ -368,8 +411,15 @@ namespace Compiler
char returnType;
std::string argumentType;
if (extensions->isFunction (keyword, returnType, argumentType, true))
bool hasExplicit = true;
if (extensions->isFunction (keyword, returnType, argumentType, hasExplicit))
{
if (!hasExplicit)
{
getErrorHandler().warning ("stray explicit reference (ignoring it)", loc);
mExplicit.clear();
}
start();
mTokenLoc = loc;
@ -490,7 +540,9 @@ namespace Compiler
char returnType;
std::string argumentType;
if (extensions->isFunction (keyword, returnType, argumentType, false))
bool hasExplicit = false;
if (extensions->isFunction (keyword, returnType, argumentType, hasExplicit))
{
mTokenLoc = loc;
int optionals = parseArguments (argumentType, scanner);
@ -518,6 +570,14 @@ namespace Compiler
{
if (!mExplicit.empty())
{
if (mRefOp && code==Scanner::S_open)
{
/// \todo add option to disable this workaround
mOperators.push_back ('(');
mTokenLoc = loc;
return true;
}
if (!mRefOp && code==Scanner::S_ref)
{
mRefOp = true;
@ -687,11 +747,11 @@ namespace Compiler
{
optional = true;
}
else if (*iter=='S' || *iter=='c')
else if (*iter=='S' || *iter=='c' || *iter=='x')
{
stringParser.reset();
if (optional)
if (optional || *iter=='x')
stringParser.setOptional (true);
if (*iter=='c') stringParser.smashCase();
@ -700,18 +760,21 @@ namespace Compiler
if (optional && stringParser.isEmpty())
break;
if (invert)
if (*iter!='x')
{
std::vector<Interpreter::Type_Code> tmp;
stringParser.append (tmp);
if (invert)
{
std::vector<Interpreter::Type_Code> tmp;
stringParser.append (tmp);
stack.push (tmp);
}
else
stringParser.append (code);
stack.push (tmp);
}
else
stringParser.append (code);
if (optional)
++optionalCount;
if (optional)
++optionalCount;
}
}
else
{

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

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

@ -47,13 +47,17 @@ namespace Compiler
/// - keyword must be all lower case.
bool isFunction (int keyword, char& returnType, std::string& argumentType,
bool explicitReference) const;
bool& explicitReference) const;
///< Is this keyword registered with a function? If yes, return return and argument
/// types.
/// \param explicitReference In: has explicit reference; Out: set to false, if
/// explicit reference is not available for this instruction.
bool isInstruction (int keyword, std::string& argumentType,
bool explicitReference) const;
bool& explicitReference) const;
///< Is this keyword registered with a function? If yes, return argument types.
/// \param explicitReference In: has explicit reference; Out: set to false, if
/// explicit reference is not available for this instruction.
void registerFunction (const std::string& keyword, char returnType,
const std::string& argumentType, int code, int codeExplicit = -1);

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

@ -260,34 +260,34 @@ namespace
code.push_back (Compiler::Generator::segment5 (44));
}
void opStoreMemberShort (Compiler::Generator::CodeContainer& code)
void opStoreMemberShort (Compiler::Generator::CodeContainer& code, bool global)
{
code.push_back (Compiler::Generator::segment5 (59));
code.push_back (Compiler::Generator::segment5 (global ? 65 : 59));
}
void opStoreMemberLong (Compiler::Generator::CodeContainer& code)
void opStoreMemberLong (Compiler::Generator::CodeContainer& code, bool global)
{
code.push_back (Compiler::Generator::segment5 (60));
code.push_back (Compiler::Generator::segment5 (global ? 66 : 60));
}
void opStoreMemberFloat (Compiler::Generator::CodeContainer& code)
void opStoreMemberFloat (Compiler::Generator::CodeContainer& code, bool global)
{
code.push_back (Compiler::Generator::segment5 (61));
code.push_back (Compiler::Generator::segment5 (global ? 67 : 61));
}
void opFetchMemberShort (Compiler::Generator::CodeContainer& code)
void opFetchMemberShort (Compiler::Generator::CodeContainer& code, bool global)
{
code.push_back (Compiler::Generator::segment5 (62));
code.push_back (Compiler::Generator::segment5 (global ? 68 : 62));
}
void opFetchMemberLong (Compiler::Generator::CodeContainer& code)
void opFetchMemberLong (Compiler::Generator::CodeContainer& code, bool global)
{
code.push_back (Compiler::Generator::segment5 (63));
code.push_back (Compiler::Generator::segment5 (global ? 69 : 63));
}
void opFetchMemberFloat (Compiler::Generator::CodeContainer& code)
void opFetchMemberFloat (Compiler::Generator::CodeContainer& code, bool global)
{
code.push_back (Compiler::Generator::segment5 (64));
code.push_back (Compiler::Generator::segment5 (global ? 70 : 64));
}
void opRandom (Compiler::Generator::CodeContainer& code)
@ -593,7 +593,7 @@ namespace Compiler
else if (offset<0)
opJumpBackward (code, -offset);
else
throw std::logic_error ("inifite loop");
throw std::logic_error ("infinite loop");
}
void jumpOnZero (CodeContainer& code, int offset)
@ -738,7 +738,8 @@ namespace Compiler
}
void assignToMember (CodeContainer& code, Literals& literals, char localType,
const std::string& name, const std::string& id, const CodeContainer& value, char valueType)
const std::string& name, const std::string& id, const CodeContainer& value,
char valueType, bool global)
{
int index = literals.addString (name);
@ -766,17 +767,17 @@ namespace Compiler
{
case 'f':
opStoreMemberFloat (code);
opStoreMemberFloat (code, global);
break;
case 's':
opStoreMemberShort (code);
opStoreMemberShort (code, global);
break;
case 'l':
opStoreMemberLong (code);
opStoreMemberLong (code, global);
break;
default:
@ -786,7 +787,7 @@ namespace Compiler
}
void fetchMember (CodeContainer& code, Literals& literals, char localType,
const std::string& name, const std::string& id)
const std::string& name, const std::string& id, bool global)
{
int index = literals.addString (name);
@ -800,17 +801,17 @@ namespace Compiler
{
case 'f':
opFetchMemberFloat (code);
opFetchMemberFloat (code, global);
break;
case 's':
opFetchMemberShort (code);
opFetchMemberShort (code, global);
break;
case 'l':
opFetchMemberLong (code);
opFetchMemberLong (code, global);
break;
default:

@ -102,10 +102,12 @@ namespace Compiler
const std::string& name);
void assignToMember (CodeContainer& code, Literals& literals, char memberType,
const std::string& name, const std::string& id, const CodeContainer& value, char valueType);
const std::string& name, const std::string& id, const CodeContainer& value, char valueType, bool global);
///< \param global Member of a global script instead of a script of a reference.
void fetchMember (CodeContainer& code, Literals& literals, char memberType,
const std::string& name, const std::string& id);
const std::string& name, const std::string& id, bool global);
///< \param global Member of a global script instead of a script of a reference.
void random (CodeContainer& code);

@ -1,6 +1,8 @@
#include "lineparser.hpp"
#include <components/misc/stringops.hpp>
#include "scanner.hpp"
#include "context.hpp"
#include "errorhandler.hpp"
@ -8,7 +10,7 @@
#include "locals.hpp"
#include "generator.hpp"
#include "extensions.hpp"
#include <components/misc/stringops.hpp>
#include "declarationparser.hpp"
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)
: Parser (errorHandler, context), mLocals (locals), mLiterals (literals), mCode (code),
mState (BeginState), mExprParser (errorHandler, context, locals, literals),
@ -82,33 +84,9 @@ namespace Compiler
bool LineParser::parseName (const std::string& name, const TokenLoc& loc,
Scanner& scanner)
{
if (mState==ShortState || mState==LongState || mState==FloatState)
if (mState==PotentialEndState)
{
if (!getContext().canDeclareLocals())
{
getErrorHandler().error ("local variables can't be declared in this context", loc);
SkipParser skip (getErrorHandler(), getContext());
scanner.scan (skip);
return false;
}
std::string name2 = Misc::StringUtils::lowerCase (name);
char type = mLocals.getType (name2);
if (type!=' ')
{
/// \todo add option to make re-declared local variables an error
getErrorHandler().warning ("can't re-declare local variable", loc);
SkipParser skip (getErrorHandler(), getContext());
scanner.scan (skip);
mState = EndState;
return true;
}
mLocals.declare (mState==ShortState ? 's' : (mState==LongState ? 'l' : 'f'),
name2);
getErrorHandler().warning ("stay string argument (ignoring it)", loc);
mState = EndState;
return true;
}
@ -142,12 +120,13 @@ namespace Compiler
if (mState==SetMemberVarState)
{
mMemberName = name;
char type = getContext().getMemberType (mMemberName, mName);
std::pair<char, bool> type = getContext().getMemberType (mMemberName, mName);
if (type!=' ')
if (type.first!=' ')
{
mState = SetMemberVarState2;
mType = type;
mType = type.first;
mReferenceMember = type.second;
return true;
}
@ -240,6 +219,34 @@ namespace Compiler
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)
{
switch (keyword)
@ -247,13 +254,13 @@ namespace Compiler
case Scanner::K_enable:
Generator::enable (mCode, mLiterals, mExplicit);
mState = EndState;
mState = PotentialEndState;
return true;
case Scanner::K_disable:
Generator::disable (mCode, mLiterals, mExplicit);
mState = EndState;
mState = PotentialEndState;
return true;
}
@ -262,8 +269,15 @@ namespace Compiler
{
std::string argumentType;
if (extensions->isInstruction (keyword, argumentType, mState==ExplicitState))
bool hasExplicit = mState==ExplicitState;
if (extensions->isInstruction (keyword, argumentType, hasExplicit))
{
if (!hasExplicit && mState==ExplicitState)
{
getErrorHandler().warning ("stray explicit reference (ignoring it)", loc);
mExplicit.clear();
}
int optionals = mExprParser.parseArguments (argumentType, scanner, mCode, true);
extensions->generateInstructionCode (keyword, mCode, mLiterals, mExplicit, optionals);
@ -287,9 +301,16 @@ namespace Compiler
char returnType;
std::string argumentType;
if (extensions->isFunction (keyword, returnType, argumentType,
!mExplicit.empty()))
bool hasExplicit = !mExplicit.empty();
if (extensions->isFunction (keyword, returnType, argumentType, hasExplicit))
{
if (!hasExplicit && !mExplicit.empty())
{
getErrorHandler().warning ("stray explicit reference (ignoring it)", loc);
mExplicit.clear();
}
scanner.putbackKeyword (keyword, loc);
parseExpression (scanner, loc);
mState = EndState;
@ -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)
{
switch (keyword)
{
case Scanner::K_short: mState = ShortState; return true;
case Scanner::K_long: mState = LongState; return true;
case Scanner::K_float: mState = FloatState; return true;
case Scanner::K_short:
case Scanner::K_long:
case Scanner::K_float:
{
if (!getContext().canDeclareLocals())
{
getErrorHandler().error (
"local variables can't be declared in this context", loc);
SkipParser skip (getErrorHandler(), getContext());
scanner.scan (skip);
return true;
}
DeclarationParser declaration (getErrorHandler(), getContext(), mLocals);
if (declaration.parseKeyword (keyword, loc, scanner))
scanner.scan (declaration);
return true;
}
case Scanner::K_set: mState = SetState; return true;
case Scanner::K_messagebox: mState = MessageState; return true;
@ -328,6 +374,24 @@ namespace Compiler
Generator::stopScript (mCode);
mState = EndState;
return true;
case Scanner::K_else:
getErrorHandler().warning ("stay else (ignoring it)", loc);
mState = EndState;
return true;
case Scanner::K_endif:
getErrorHandler().warning ("stay endif (ignoring it)", loc);
mState = EndState;
return true;
case Scanner::K_begin:
getErrorHandler().warning ("stay begin (ignoring it)", loc);
mState = EndState;
return true;
}
}
else if (mState==SetLocalVarState && keyword==Scanner::K_to)
@ -365,7 +429,8 @@ namespace Compiler
std::vector<Interpreter::Type_Code> code;
char type = mExprParser.append (code);
Generator::assignToMember (mCode, mLiterals, mType, mMemberName, mName, code, type);
Generator::assignToMember (mCode, mLiterals, mType, mMemberName, mName, code, type,
!mReferenceMember);
mState = EndState;
return true;
@ -389,7 +454,8 @@ namespace Compiler
bool LineParser::parseSpecial (int code, const TokenLoc& loc, Scanner& scanner)
{
if (code==Scanner::S_newline && (mState==EndState || mState==BeginState))
if (code==Scanner::S_newline &&
(mState==EndState || mState==BeginState || mState==PotentialEndState))
return false;
if (code==Scanner::S_comma && mState==MessageState)

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

@ -7,6 +7,8 @@
#include <ostream>
#include <iterator>
#include <components/misc/stringops.hpp>
namespace Compiler
{
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)
{
get (type).push_back (name);
get (type).push_back (Misc::StringUtils::lowerCase (name));
}
void Locals::clear()

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

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

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

@ -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)
{
}

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

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

@ -7,7 +7,7 @@
namespace Compiler
{
ScriptParser::ScriptParser (ErrorHandler& errorHandler, Context& context,
ScriptParser::ScriptParser (ErrorHandler& errorHandler, const Context& context,
Locals& locals, bool end)
: Parser (errorHandler, context), mOutput (locals),
mLineParser (errorHandler, context, locals, mOutput.getLiterals(), mOutput.getCode()),
@ -32,7 +32,7 @@ namespace Compiler
bool ScriptParser::parseKeyword (int keyword, const TokenLoc& loc, Scanner& scanner)
{
if (keyword==Scanner::K_while || keyword==Scanner::K_if)
if (keyword==Scanner::K_while || keyword==Scanner::K_if || keyword==Scanner::K_elseif)
{
mControlParser.reset();
if (mControlParser.parseKeyword (keyword, loc, scanner))
@ -71,6 +71,12 @@ namespace Compiler
if (code==Scanner::S_newline) // empty line
return true;
if (code==Scanner::S_open) /// \todo Option to switch this off
{
scanner.putbackSpecial (code, loc);
return parseKeyword (Scanner::K_if, loc, scanner);
}
mLineParser.reset();
if (mLineParser.parseSpecial (code, loc, scanner))
scanner.scan (mLineParser);

@ -12,7 +12,7 @@ namespace Compiler
class Locals;
// Script parser, to be used in dialogue scripts and as part of FileParser
class ScriptParser : public Parser
{
Output mOutput;
@ -21,14 +21,14 @@ namespace Compiler
bool mEnd;
public:
/// \param end of script is marked by end keyword.
ScriptParser (ErrorHandler& errorHandler, Context& context, Locals& locals,
ScriptParser (ErrorHandler& errorHandler, const Context& context, Locals& locals,
bool end = false);
void getCode (std::vector<Interpreter::Type_Code>& code) const;
///< store generated code in \æ code.
virtual bool parseName (const std::string& name, const TokenLoc& loc,
Scanner& scanner);
///< Handle a name token.
@ -43,8 +43,8 @@ namespace Compiler
/// \return fetch another token?
virtual void parseEOF (Scanner& scanner);
///< Handle EOF token.
///< Handle EOF token.
void reset();
///< Reset parser to clean state.
};

@ -5,7 +5,7 @@
namespace Compiler
{
SkipParser::SkipParser (ErrorHandler& errorHandler, Context& context)
SkipParser::SkipParser (ErrorHandler& errorHandler, const Context& context)
: Parser (errorHandler, context)
{}
@ -34,7 +34,7 @@ namespace Compiler
{
if (code==Scanner::S_newline)
return false;
return true;
}
}

@ -8,13 +8,13 @@ namespace Compiler
// \brief Skip parser for skipping a line
//
// This parser is mainly intended for skipping the rest of a faulty line.
class SkipParser : public Parser
{
public:
SkipParser (ErrorHandler& errorHandler, Context& context);
SkipParser (ErrorHandler& errorHandler, const Context& context);
virtual bool parseInt (int value, const TokenLoc& loc, Scanner& scanner);
///< Handle an int token.
/// \return fetch another token?

@ -10,7 +10,7 @@
namespace Compiler
{
StringParser::StringParser (ErrorHandler& errorHandler, Context& context, Literals& literals)
StringParser::StringParser (ErrorHandler& errorHandler, const Context& context, Literals& literals)
: Parser (errorHandler, context), mLiterals (literals), mState (StartState), mSmashCase (false)
{

@ -10,22 +10,22 @@
namespace Compiler
{
class Literals;
class StringParser : public Parser
{
enum State
{
StartState, CommaState
};
Literals& mLiterals;
State mState;
std::vector<Interpreter::Type_Code> mCode;
bool mSmashCase;
public:
StringParser (ErrorHandler& errorHandler, Context& context, Literals& literals);
StringParser (ErrorHandler& errorHandler, const Context& context, Literals& literals);
virtual bool parseName (const std::string& name, const TokenLoc& loc,
Scanner& scanner);
@ -35,15 +35,15 @@ namespace Compiler
virtual bool parseSpecial (int code, const TokenLoc& loc, Scanner& scanner);
///< Handle a special character token.
/// \return fetch another token?
void append (std::vector<Interpreter::Type_Code>& code);
///< Append code for parsed string.
void smashCase();
///< Transform all scanned strings to lower case
void reset();
///< Reset parser to clean state (this includes the smashCase function).
///< Reset parser to clean state (this includes the smashCase function).
};
}

@ -50,33 +50,33 @@ namespace Interpreter
virtual void setGlobalFloat (const std::string& name, float value) = 0;
virtual std::vector<std::string> getGlobals () const = 0;
virtual char getGlobalType (const std::string& name) const = 0;
virtual std::string getActionBinding(const std::string& action) const = 0;
virtual std::string getNPCName() const = 0;
virtual std::string getNPCRace() const = 0;
virtual std::string getNPCClass() const = 0;
virtual std::string getNPCFaction() const = 0;
virtual std::string getNPCRank() const = 0;
virtual std::string getPCName() const = 0;
virtual std::string getPCRace() const = 0;
virtual std::string getPCClass() const = 0;
virtual std::string getPCRank() const = 0;
virtual std::string getPCNextRank() const = 0;
virtual int getPCBounty() const = 0;
virtual std::string getCurrentCellName() const = 0;
virtual bool isScriptRunning (const std::string& name) const = 0;
@ -96,17 +96,17 @@ namespace Interpreter
virtual void disable (const std::string& id = "") = 0;
virtual int getMemberShort (const std::string& id, const std::string& name) const = 0;
virtual int getMemberShort (const std::string& id, const std::string& name, bool global) const = 0;
virtual int getMemberLong (const std::string& id, const std::string& name) const = 0;
virtual int getMemberLong (const std::string& id, const std::string& name, bool global) const = 0;
virtual float getMemberFloat (const std::string& id, const std::string& name) const = 0;
virtual float getMemberFloat (const std::string& id, const std::string& name, bool global) const = 0;
virtual void setMemberShort (const std::string& id, const std::string& name, int value) = 0;
virtual void setMemberShort (const std::string& id, const std::string& name, int value, bool global) = 0;
virtual void setMemberLong (const std::string& id, const std::string& name, int value) = 0;
virtual void setMemberLong (const std::string& id, const std::string& name, int value, bool global) = 0;
virtual void setMemberFloat (const std::string& id, const std::string& name, float value)
virtual void setMemberFloat (const std::string& id, const std::string& name, float value, bool global)
= 0;
};
}

@ -127,5 +127,11 @@ op 61: store stack[0] in member float stack[2] of object with ID stack[1]
op 62: replace stack[0] with member short stack[1] of object with ID stack[0]
op 63: replace stack[0] with member short stack[1] of object with ID stack[0]
op 64: replace stack[0] with member short stack[1] of object with ID stack[0]
opcodes 65-33554431 unused
op 65: store stack[0] in member short stack[2] of global script with ID stack[1]
op 66: store stack[0] in member long stack[2] of global script with ID stack[1]
op 67: store stack[0] in member float stack[2] of global script with ID stack[1]
op 68: replace stack[0] with member short stack[1] of global script with ID stack[0]
op 69: replace stack[0] with member short stack[1] of global script with ID stack[0]
op 70: replace stack[0] with member short stack[1] of global script with ID stack[0]
opcodes 71-33554431 unused
opcodes 33554432-67108863 reserved for extensions

@ -40,12 +40,18 @@ namespace Interpreter
interpreter.installSegment5 (42, new OpFetchGlobalShort);
interpreter.installSegment5 (43, new OpFetchGlobalLong);
interpreter.installSegment5 (44, new OpFetchGlobalFloat);
interpreter.installSegment5 (59, new OpStoreMemberShort);
interpreter.installSegment5 (60, new OpStoreMemberLong);
interpreter.installSegment5 (61, new OpStoreMemberFloat);
interpreter.installSegment5 (62, new OpFetchMemberShort);
interpreter.installSegment5 (63, new OpFetchMemberLong);
interpreter.installSegment5 (64, new OpFetchMemberFloat);
interpreter.installSegment5 (59, new OpStoreMemberShort (false));
interpreter.installSegment5 (60, new OpStoreMemberLong (false));
interpreter.installSegment5 (61, new OpStoreMemberFloat (false));
interpreter.installSegment5 (62, new OpFetchMemberShort (false));
interpreter.installSegment5 (63, new OpFetchMemberLong (false));
interpreter.installSegment5 (64, new OpFetchMemberFloat (false));
interpreter.installSegment5 (65, new OpStoreMemberShort (true));
interpreter.installSegment5 (66, new OpStoreMemberLong (true));
interpreter.installSegment5 (67, new OpStoreMemberFloat (true));
interpreter.installSegment5 (68, new OpFetchMemberShort (true));
interpreter.installSegment5 (69, new OpFetchMemberLong (true));
interpreter.installSegment5 (70, new OpFetchMemberFloat (true));
// math
interpreter.installSegment5 (9, new OpAddInt<Type_Integer>);

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

@ -67,7 +67,13 @@ Allowed options:
--script-run arg select a file containing a list of
console commands that is executed on
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
folding)
--encoding arg (=win1252) Character encoding used in OpenMW game

Loading…
Cancel
Save