mirror of
https://github.com/OpenMW/openmw.git
synced 2025-02-06 15:15:34 +00:00
Merge branch 'script'
Conflicts: readme.txt
This commit is contained in:
commit
6ac64bbe15
54 changed files with 1129 additions and 286 deletions
|
@ -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
|
||||
)
|
||||
|
||||
|
||||
|
|
103
apps/opencs/model/tools/scriptcheck.cpp
Normal file
103
apps/opencs/model/tools/scriptcheck.cpp
Normal 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;
|
||||
}
|
41
apps/opencs/model/tools/scriptcheck.hpp
Normal file
41
apps/opencs/model/tools/scriptcheck.hpp
Normal 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
|
|
@ -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;
|
||||
|
||||
std::string script = MWWorld::Class::get (ptr).getScript (ptr);
|
||||
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);
|
||||
|
||||
if (script.empty())
|
||||
return ' ';
|
||||
script = MWWorld::Class::get (ptr).getScript (ptr);
|
||||
reference = true;
|
||||
}
|
||||
|
||||
return MWBase::Environment::get().getScriptManager()->getLocals (script).getType (name);
|
||||
char type = ' ';
|
||||
|
||||
if (!script.empty())
|
||||
type = MWBase::Environment::get().getScriptManager()->getLocals (script).getType (
|
||||
Misc::StringUtils::lowerCase (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;
|
||||
|
|
83
components/compiler/declarationparser.cpp
Normal file
83
components/compiler/declarationparser.cpp
Normal 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;
|
||||
}
|
43
components/compiler/declarationparser.hpp
Normal file
43
components/compiler/declarationparser.hpp
Normal 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
|
|
@ -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);
|
||||
stack.push (tmp);
|
||||
}
|
||||
else
|
||||
stringParser.append (code);
|
||||
|
||||
if (optional)
|
||||
++optionalCount;
|
||||
}
|
||||
else
|
||||
stringParser.append (code);
|
||||
|
||||
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();
|
||||
|
|
52
components/compiler/quickfileparser.cpp
Normal file
52
components/compiler/quickfileparser.cpp
Normal 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)
|
||||
{
|
||||
|
||||
}
|
39
components/compiler/quickfileparser.hpp
Normal file
39
components/compiler/quickfileparser.hpp
Normal 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
|
||||
|
|
@ -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…
Reference in a new issue