mirror of
https://gitlab.com/OpenMW/openmw.git
synced 2025-02-04 21:40:03 +00:00
Merge branch 'mwscript' into 'master'
Multiple mwscript optimizations and some refactoring See merge request OpenMW/openmw!2600
This commit is contained in:
commit
dc3ec1a0a0
@ -42,6 +42,7 @@
|
|||||||
Feature #7058: Implement TestModels (T3D) console command
|
Feature #7058: Implement TestModels (T3D) console command
|
||||||
Feature #7087: Block resolution change in the Windowed Fullscreen mode
|
Feature #7087: Block resolution change in the Windowed Fullscreen mode
|
||||||
Feature #7130: Ability to set MyGUI logging verbosity
|
Feature #7130: Ability to set MyGUI logging verbosity
|
||||||
|
Feature #7148: Optimize string literal lookup in mwscript
|
||||||
|
|
||||||
0.48.0
|
0.48.0
|
||||||
------
|
------
|
||||||
|
@ -2,6 +2,7 @@
|
|||||||
|
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
#include <list>
|
#include <list>
|
||||||
|
#include <optional>
|
||||||
#include <sstream>
|
#include <sstream>
|
||||||
|
|
||||||
#include <components/debug/debuglog.hpp>
|
#include <components/debug/debuglog.hpp>
|
||||||
@ -187,10 +188,10 @@ namespace MWDialogue
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool DialogueManager::compile(
|
std::optional<Interpreter::Program> DialogueManager::compile(const std::string& cmd, const MWWorld::Ptr& actor)
|
||||||
const std::string& cmd, std::vector<Interpreter::Type_Code>& code, const MWWorld::Ptr& actor)
|
|
||||||
{
|
{
|
||||||
bool success = true;
|
bool success = true;
|
||||||
|
std::optional<Interpreter::Program> program;
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
@ -220,7 +221,7 @@ namespace MWDialogue
|
|||||||
success = false;
|
success = false;
|
||||||
|
|
||||||
if (success)
|
if (success)
|
||||||
parser.getCode(code);
|
program = parser.getProgram();
|
||||||
}
|
}
|
||||||
catch (const Compiler::SourceException& /* error */)
|
catch (const Compiler::SourceException& /* error */)
|
||||||
{
|
{
|
||||||
@ -238,20 +239,19 @@ namespace MWDialogue
|
|||||||
Log(Debug::Error) << "Error: compiling failed (dialogue script): \n" << cmd << "\n";
|
Log(Debug::Error) << "Error: compiling failed (dialogue script): \n" << cmd << "\n";
|
||||||
}
|
}
|
||||||
|
|
||||||
return success;
|
return program;
|
||||||
}
|
}
|
||||||
|
|
||||||
void DialogueManager::executeScript(const std::string& script, const MWWorld::Ptr& actor)
|
void DialogueManager::executeScript(const std::string& script, const MWWorld::Ptr& actor)
|
||||||
{
|
{
|
||||||
std::vector<Interpreter::Type_Code> code;
|
if (const std::optional<Interpreter::Program> program = compile(script, actor))
|
||||||
if (compile(script, code, actor))
|
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
MWScript::InterpreterContext interpreterContext(&actor.getRefData().getLocals(), actor);
|
MWScript::InterpreterContext interpreterContext(&actor.getRefData().getLocals(), actor);
|
||||||
Interpreter::Interpreter interpreter;
|
Interpreter::Interpreter interpreter;
|
||||||
MWScript::installOpcodes(interpreter);
|
MWScript::installOpcodes(interpreter);
|
||||||
interpreter.run(code.data(), code.size(), interpreterContext);
|
interpreter.run(*program, interpreterContext);
|
||||||
}
|
}
|
||||||
catch (const std::exception& error)
|
catch (const std::exception& error)
|
||||||
{
|
{
|
||||||
|
@ -4,11 +4,13 @@
|
|||||||
#include "../mwbase/dialoguemanager.hpp"
|
#include "../mwbase/dialoguemanager.hpp"
|
||||||
|
|
||||||
#include <map>
|
#include <map>
|
||||||
|
#include <optional>
|
||||||
#include <set>
|
#include <set>
|
||||||
#include <unordered_map>
|
#include <unordered_map>
|
||||||
|
|
||||||
#include <components/compiler/streamerrorhandler.hpp>
|
#include <components/compiler/streamerrorhandler.hpp>
|
||||||
#include <components/esm3/loadinfo.hpp>
|
#include <components/esm3/loadinfo.hpp>
|
||||||
|
#include <components/interpreter/program.hpp>
|
||||||
#include <components/misc/strings/algorithm.hpp>
|
#include <components/misc/strings/algorithm.hpp>
|
||||||
#include <components/translation/translation.hpp>
|
#include <components/translation/translation.hpp>
|
||||||
|
|
||||||
@ -63,7 +65,8 @@ namespace MWDialogue
|
|||||||
void updateActorKnownTopics();
|
void updateActorKnownTopics();
|
||||||
void updateGlobals();
|
void updateGlobals();
|
||||||
|
|
||||||
bool compile(const std::string& cmd, std::vector<Interpreter::Type_Code>& code, const MWWorld::Ptr& actor);
|
std::optional<Interpreter::Program> compile(const std::string& cmd, const MWWorld::Ptr& actor);
|
||||||
|
|
||||||
void executeScript(const std::string& script, const MWWorld::Ptr& actor);
|
void executeScript(const std::string& script, const MWWorld::Ptr& actor);
|
||||||
|
|
||||||
void executeTopic(const ESM::RefId& topic, ResponseCallback* callback);
|
void executeTopic(const ESM::RefId& topic, ResponseCallback* callback);
|
||||||
|
@ -208,9 +208,8 @@ namespace MWGui
|
|||||||
ConsoleInterpreterContext interpreterContext(*this, mPtr);
|
ConsoleInterpreterContext interpreterContext(*this, mPtr);
|
||||||
Interpreter::Interpreter interpreter;
|
Interpreter::Interpreter interpreter;
|
||||||
MWScript::installOpcodes(interpreter, mConsoleOnlyScripts);
|
MWScript::installOpcodes(interpreter, mConsoleOnlyScripts);
|
||||||
std::vector<Interpreter::Type_Code> code;
|
const Interpreter::Program program = output.getProgram();
|
||||||
output.getCode(code);
|
interpreter.run(program, interpreterContext);
|
||||||
interpreter.run(code.data(), code.size(), interpreterContext);
|
|
||||||
}
|
}
|
||||||
catch (const std::exception& error)
|
catch (const std::exception& error)
|
||||||
{
|
{
|
||||||
|
@ -79,9 +79,7 @@ namespace MWScript
|
|||||||
|
|
||||||
if (Success)
|
if (Success)
|
||||||
{
|
{
|
||||||
std::vector<Interpreter::Type_Code> code;
|
mScripts.emplace(name, CompiledScript(mParser.getProgram(), mParser.getLocals()));
|
||||||
mParser.getCode(code);
|
|
||||||
mScripts.emplace(name, CompiledScript(code, mParser.getLocals()));
|
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@ -100,8 +98,7 @@ namespace MWScript
|
|||||||
if (!compile(name))
|
if (!compile(name))
|
||||||
{
|
{
|
||||||
// failed -> ignore script from now on.
|
// failed -> ignore script from now on.
|
||||||
std::vector<Interpreter::Type_Code> empty;
|
mScripts.emplace(name, CompiledScript({}, Compiler::Locals()));
|
||||||
mScripts.emplace(name, CompiledScript(empty, Compiler::Locals()));
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -111,7 +108,8 @@ namespace MWScript
|
|||||||
|
|
||||||
// execute script
|
// execute script
|
||||||
const auto& target = interpreterContext.getTarget();
|
const auto& target = interpreterContext.getTarget();
|
||||||
if (!iter->second.mByteCode.empty() && iter->second.mInactive.find(target) == iter->second.mInactive.end())
|
if (!iter->second.mProgram.mInstructions.empty()
|
||||||
|
&& iter->second.mInactive.find(target) == iter->second.mInactive.end())
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
if (!mOpcodesInstalled)
|
if (!mOpcodesInstalled)
|
||||||
@ -120,7 +118,7 @@ namespace MWScript
|
|||||||
mOpcodesInstalled = true;
|
mOpcodesInstalled = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
mInterpreter.run(&iter->second.mByteCode[0], iter->second.mByteCode.size(), interpreterContext);
|
mInterpreter.run(iter->second.mProgram, interpreterContext);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
catch (const MissingImplicitRefError& e)
|
catch (const MissingImplicitRefError& e)
|
||||||
|
@ -46,12 +46,12 @@ namespace MWScript
|
|||||||
|
|
||||||
struct CompiledScript
|
struct CompiledScript
|
||||||
{
|
{
|
||||||
std::vector<Interpreter::Type_Code> mByteCode;
|
Interpreter::Program mProgram;
|
||||||
Compiler::Locals mLocals;
|
Compiler::Locals mLocals;
|
||||||
std::set<ESM::RefId> mInactive;
|
std::set<ESM::RefId> mInactive;
|
||||||
|
|
||||||
CompiledScript(const std::vector<Interpreter::Type_Code>& code, const Compiler::Locals& locals)
|
explicit CompiledScript(Interpreter::Program&& program, const Compiler::Locals& locals)
|
||||||
: mByteCode(code)
|
: mProgram(std::move(program))
|
||||||
, mLocals(locals)
|
, mLocals(locals)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
@ -21,11 +21,7 @@ namespace
|
|||||||
Compiler::Scanner scanner(mErrorHandler, input, mCompilerContext.getExtensions());
|
Compiler::Scanner scanner(mErrorHandler, input, mCompilerContext.getExtensions());
|
||||||
scanner.scan(mParser);
|
scanner.scan(mParser);
|
||||||
if (mErrorHandler.isGood())
|
if (mErrorHandler.isGood())
|
||||||
{
|
return CompiledScript(mParser.getProgram(), mParser.getLocals());
|
||||||
std::vector<Interpreter::Type_Code> code;
|
|
||||||
mParser.getCode(code);
|
|
||||||
return CompiledScript(code, mParser.getLocals());
|
|
||||||
}
|
|
||||||
else if (!shouldFail)
|
else if (!shouldFail)
|
||||||
logErrors();
|
logErrors();
|
||||||
return {};
|
return {};
|
||||||
@ -50,7 +46,7 @@ namespace
|
|||||||
|
|
||||||
void run(const CompiledScript& script, TestInterpreterContext& context)
|
void run(const CompiledScript& script, TestInterpreterContext& context)
|
||||||
{
|
{
|
||||||
mInterpreter.run(&script.mByteCode[0], static_cast<int>(script.mByteCode.size()), context);
|
mInterpreter.run(script.mProgram, context);
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename T, typename... TArgs>
|
template <typename T, typename... TArgs>
|
||||||
|
@ -249,11 +249,11 @@ namespace
|
|||||||
|
|
||||||
struct CompiledScript
|
struct CompiledScript
|
||||||
{
|
{
|
||||||
std::vector<Interpreter::Type_Code> mByteCode;
|
Interpreter::Program mProgram;
|
||||||
Compiler::Locals mLocals;
|
Compiler::Locals mLocals;
|
||||||
|
|
||||||
CompiledScript(const std::vector<Interpreter::Type_Code>& code, const Compiler::Locals& locals)
|
CompiledScript(Interpreter::Program&& program, const Compiler::Locals& locals)
|
||||||
: mByteCode(code)
|
: mProgram(std::move(program))
|
||||||
, mLocals(locals)
|
, mLocals(locals)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
@ -17,9 +17,9 @@ namespace Compiler
|
|||||||
return mName;
|
return mName;
|
||||||
}
|
}
|
||||||
|
|
||||||
void FileParser::getCode(std::vector<Interpreter::Type_Code>& code) const
|
Interpreter::Program FileParser::getProgram() const
|
||||||
{
|
{
|
||||||
mScriptParser.getCode(code);
|
return mScriptParser.getProgram();
|
||||||
}
|
}
|
||||||
|
|
||||||
const Locals& FileParser::getLocals() const
|
const Locals& FileParser::getLocals() const
|
||||||
|
@ -31,8 +31,7 @@ namespace Compiler
|
|||||||
std::string getName() const;
|
std::string getName() const;
|
||||||
///< Return script name.
|
///< Return script name.
|
||||||
|
|
||||||
void getCode(std::vector<Interpreter::Type_Code>& code) const;
|
Interpreter::Program getProgram() const;
|
||||||
///< store generated code in \a code.
|
|
||||||
|
|
||||||
const Locals& getLocals() const;
|
const Locals& getLocals() const;
|
||||||
///< get local variable declarations.
|
///< get local variable declarations.
|
||||||
|
@ -1,56 +1,10 @@
|
|||||||
#include "literals.hpp"
|
#include "literals.hpp"
|
||||||
|
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
|
#include <cstring>
|
||||||
|
|
||||||
namespace Compiler
|
namespace Compiler
|
||||||
{
|
{
|
||||||
int Literals::getIntegerSize() const
|
|
||||||
{
|
|
||||||
return static_cast<int>(mIntegers.size() * sizeof(Interpreter::Type_Integer));
|
|
||||||
}
|
|
||||||
|
|
||||||
int Literals::getFloatSize() const
|
|
||||||
{
|
|
||||||
return static_cast<int>(mFloats.size() * sizeof(Interpreter::Type_Float));
|
|
||||||
}
|
|
||||||
|
|
||||||
int Literals::getStringSize() const
|
|
||||||
{
|
|
||||||
int size = 0;
|
|
||||||
|
|
||||||
for (std::vector<std::string>::const_iterator iter(mStrings.begin()); iter != mStrings.end(); ++iter)
|
|
||||||
size += static_cast<int>(iter->size()) + 1;
|
|
||||||
|
|
||||||
if (size % 4) // padding
|
|
||||||
size += 4 - size % 4;
|
|
||||||
|
|
||||||
return size;
|
|
||||||
}
|
|
||||||
|
|
||||||
void Literals::append(std::vector<Interpreter::Type_Code>& code) const
|
|
||||||
{
|
|
||||||
for (const int& mInteger : mIntegers)
|
|
||||||
code.push_back(*reinterpret_cast<const Interpreter::Type_Code*>(&mInteger));
|
|
||||||
|
|
||||||
for (const float& mFloat : mFloats)
|
|
||||||
code.push_back(*reinterpret_cast<const Interpreter::Type_Code*>(&mFloat));
|
|
||||||
|
|
||||||
int stringBlockSize = getStringSize();
|
|
||||||
int size = static_cast<int>(code.size());
|
|
||||||
|
|
||||||
code.resize(size + stringBlockSize / 4);
|
|
||||||
|
|
||||||
size_t offset = 0;
|
|
||||||
|
|
||||||
for (const auto& mString : mStrings)
|
|
||||||
{
|
|
||||||
size_t stringSize = mString.size() + 1;
|
|
||||||
|
|
||||||
std::copy(mString.c_str(), mString.c_str() + stringSize, reinterpret_cast<char*>(&code[size]) + offset);
|
|
||||||
offset += stringSize;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
int Literals::addInteger(Interpreter::Type_Integer value)
|
int Literals::addInteger(Interpreter::Type_Integer value)
|
||||||
{
|
{
|
||||||
int index = static_cast<int>(mIntegers.size());
|
int index = static_cast<int>(mIntegers.size());
|
||||||
|
@ -17,18 +17,11 @@ namespace Compiler
|
|||||||
std::vector<std::string> mStrings;
|
std::vector<std::string> mStrings;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
int getIntegerSize() const;
|
const std::vector<Interpreter::Type_Integer>& getIntegers() const { return mIntegers; }
|
||||||
///< Return size of integer block (in bytes).
|
|
||||||
|
|
||||||
int getFloatSize() const;
|
const std::vector<Interpreter::Type_Float>& getFloats() const { return mFloats; }
|
||||||
///< Return size of float block (in bytes).
|
|
||||||
|
|
||||||
int getStringSize() const;
|
const std::vector<std::string>& getStrings() const { return mStrings; }
|
||||||
///< Return size of string block (in bytes).
|
|
||||||
|
|
||||||
void append(std::vector<Interpreter::Type_Code>& code) const;
|
|
||||||
///< Apepnd literal blocks to code.
|
|
||||||
/// \note code blocks will be padded for 32-bit alignment.
|
|
||||||
|
|
||||||
int addInteger(Interpreter::Type_Integer value);
|
int addInteger(Interpreter::Type_Integer value);
|
||||||
///< add integer liternal and return index.
|
///< add integer liternal and return index.
|
||||||
|
@ -13,27 +13,14 @@ namespace Compiler
|
|||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
void Output::getCode(std::vector<Interpreter::Type_Code>& code) const
|
Interpreter::Program Output::getProgram() const
|
||||||
{
|
{
|
||||||
code.clear();
|
return Interpreter::Program{
|
||||||
|
.mInstructions = mCode,
|
||||||
// header
|
.mIntegers = mLiterals.getIntegers(),
|
||||||
code.push_back(static_cast<Interpreter::Type_Code>(mCode.size()));
|
.mFloats = mLiterals.getFloats(),
|
||||||
|
.mStrings = mLiterals.getStrings(),
|
||||||
assert(mLiterals.getIntegerSize() % 4 == 0);
|
};
|
||||||
code.push_back(static_cast<Interpreter::Type_Code>(mLiterals.getIntegerSize() / 4));
|
|
||||||
|
|
||||||
assert(mLiterals.getFloatSize() % 4 == 0);
|
|
||||||
code.push_back(static_cast<Interpreter::Type_Code>(mLiterals.getFloatSize() / 4));
|
|
||||||
|
|
||||||
assert(mLiterals.getStringSize() % 4 == 0);
|
|
||||||
code.push_back(static_cast<Interpreter::Type_Code>(mLiterals.getStringSize() / 4));
|
|
||||||
|
|
||||||
// code
|
|
||||||
std::copy(mCode.begin(), mCode.end(), std::back_inserter(code));
|
|
||||||
|
|
||||||
// literals
|
|
||||||
mLiterals.append(code);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const Literals& Output::getLiterals() const
|
const Literals& Output::getLiterals() const
|
||||||
|
@ -5,6 +5,7 @@
|
|||||||
|
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
|
#include <components/interpreter/program.hpp>
|
||||||
#include <components/interpreter/types.hpp>
|
#include <components/interpreter/types.hpp>
|
||||||
|
|
||||||
namespace Compiler
|
namespace Compiler
|
||||||
@ -20,8 +21,7 @@ namespace Compiler
|
|||||||
public:
|
public:
|
||||||
Output(Locals& locals);
|
Output(Locals& locals);
|
||||||
|
|
||||||
void getCode(std::vector<Interpreter::Type_Code>& code) const;
|
Interpreter::Program getProgram() const;
|
||||||
///< store generated code in \a code.
|
|
||||||
|
|
||||||
const Literals& getLiterals() const;
|
const Literals& getLiterals() const;
|
||||||
|
|
||||||
|
@ -15,9 +15,9 @@ namespace Compiler
|
|||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
void ScriptParser::getCode(std::vector<Interpreter::Type_Code>& code) const
|
Interpreter::Program ScriptParser::getProgram() const
|
||||||
{
|
{
|
||||||
mOutput.getCode(code);
|
return mOutput.getProgram();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool ScriptParser::parseName(const std::string& name, const TokenLoc& loc, Scanner& scanner)
|
bool ScriptParser::parseName(const std::string& name, const TokenLoc& loc, Scanner& scanner)
|
||||||
|
@ -23,8 +23,7 @@ namespace Compiler
|
|||||||
/// \param end of script is marked by end keyword.
|
/// \param end of script is marked by end keyword.
|
||||||
ScriptParser(ErrorHandler& errorHandler, const Context& context, Locals& locals, bool end = false);
|
ScriptParser(ErrorHandler& errorHandler, const Context& context, Locals& locals, bool end = false);
|
||||||
|
|
||||||
void getCode(std::vector<Interpreter::Type_Code>& code) const;
|
Interpreter::Program getProgram() const;
|
||||||
///< store generated code in \a code.
|
|
||||||
|
|
||||||
bool parseName(const std::string& name, const TokenLoc& loc, Scanner& scanner) override;
|
bool parseName(const std::string& name, const TokenLoc& loc, Scanner& scanner) override;
|
||||||
///< Handle a name token.
|
///< Handle a name token.
|
||||||
|
@ -5,6 +5,7 @@
|
|||||||
#include <string>
|
#include <string>
|
||||||
|
|
||||||
#include "opcodes.hpp"
|
#include "opcodes.hpp"
|
||||||
|
#include "program.hpp"
|
||||||
|
|
||||||
namespace Interpreter
|
namespace Interpreter
|
||||||
{
|
{
|
||||||
@ -104,30 +105,19 @@ namespace Interpreter
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Interpreter::Interpreter()
|
void Interpreter::run(const Program& program, Context& context)
|
||||||
: mRunning(false)
|
|
||||||
{
|
{
|
||||||
}
|
|
||||||
|
|
||||||
void Interpreter::run(const Type_Code* code, int codeSize, Context& context)
|
|
||||||
{
|
|
||||||
assert(codeSize >= 4);
|
|
||||||
|
|
||||||
begin();
|
begin();
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
mRuntime.configure(code, codeSize, context);
|
mRuntime.configure(program, context);
|
||||||
|
|
||||||
int opcodes = static_cast<int>(code[0]);
|
while (mRuntime.getPC() >= 0 && static_cast<std::size_t>(mRuntime.getPC()) < program.mInstructions.size())
|
||||||
|
|
||||||
const Type_Code* codeBlock = code + 4;
|
|
||||||
|
|
||||||
while (mRuntime.getPC() >= 0 && mRuntime.getPC() < opcodes)
|
|
||||||
{
|
{
|
||||||
Type_Code runCode = codeBlock[mRuntime.getPC()];
|
const Type_Code instruction = program.mInstructions[mRuntime.getPC()];
|
||||||
mRuntime.setPC(mRuntime.getPC() + 1);
|
mRuntime.setPC(mRuntime.getPC() + 1);
|
||||||
execute(runCode);
|
execute(instruction);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
catch (...)
|
catch (...)
|
||||||
|
@ -7,26 +7,25 @@
|
|||||||
#include <stack>
|
#include <stack>
|
||||||
#include <utility>
|
#include <utility>
|
||||||
|
|
||||||
|
#include "components/interpreter/program.hpp"
|
||||||
#include "opcodes.hpp"
|
#include "opcodes.hpp"
|
||||||
#include "runtime.hpp"
|
#include "runtime.hpp"
|
||||||
#include "types.hpp"
|
#include "types.hpp"
|
||||||
|
|
||||||
namespace Interpreter
|
namespace Interpreter
|
||||||
{
|
{
|
||||||
|
struct Program;
|
||||||
|
|
||||||
class Interpreter
|
class Interpreter
|
||||||
{
|
{
|
||||||
std::stack<Runtime> mCallstack;
|
std::stack<Runtime> mCallstack;
|
||||||
bool mRunning;
|
bool mRunning = false;
|
||||||
Runtime mRuntime;
|
Runtime mRuntime;
|
||||||
std::map<int, std::unique_ptr<Opcode1>> mSegment0;
|
std::map<int, std::unique_ptr<Opcode1>> mSegment0;
|
||||||
std::map<int, std::unique_ptr<Opcode1>> mSegment2;
|
std::map<int, std::unique_ptr<Opcode1>> mSegment2;
|
||||||
std::map<int, std::unique_ptr<Opcode1>> mSegment3;
|
std::map<int, std::unique_ptr<Opcode1>> mSegment3;
|
||||||
std::map<int, std::unique_ptr<Opcode0>> mSegment5;
|
std::map<int, std::unique_ptr<Opcode0>> mSegment5;
|
||||||
|
|
||||||
// not implemented
|
|
||||||
Interpreter(const Interpreter&);
|
|
||||||
Interpreter& operator=(const Interpreter&);
|
|
||||||
|
|
||||||
void execute(Type_Code code);
|
void execute(Type_Code code);
|
||||||
|
|
||||||
void begin();
|
void begin();
|
||||||
@ -41,7 +40,10 @@ namespace Interpreter
|
|||||||
}
|
}
|
||||||
|
|
||||||
public:
|
public:
|
||||||
Interpreter();
|
Interpreter() = default;
|
||||||
|
|
||||||
|
Interpreter(const Interpreter&) = delete;
|
||||||
|
Interpreter& operator=(const Interpreter&) = delete;
|
||||||
|
|
||||||
template <typename T, typename... TArgs>
|
template <typename T, typename... TArgs>
|
||||||
void installSegment0(int code, TArgs&&... args)
|
void installSegment0(int code, TArgs&&... args)
|
||||||
@ -67,7 +69,7 @@ namespace Interpreter
|
|||||||
installSegment(mSegment5, code, std::make_unique<T>(std::forward<TArgs>(args)...));
|
installSegment(mSegment5, code, std::make_unique<T>(std::forward<TArgs>(args)...));
|
||||||
}
|
}
|
||||||
|
|
||||||
void run(const Type_Code* code, int codeSize, Context& context);
|
void run(const Program& program, Context& context);
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
20
components/interpreter/program.hpp
Normal file
20
components/interpreter/program.hpp
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
#ifndef OPENMW_COMPONENTS_INTERPRETER_PROGRAM_H
|
||||||
|
#define OPENMW_COMPONENTS_INTERPRETER_PROGRAM_H
|
||||||
|
|
||||||
|
#include "types.hpp"
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
namespace Interpreter
|
||||||
|
{
|
||||||
|
struct Program
|
||||||
|
{
|
||||||
|
std::vector<Type_Code> mInstructions;
|
||||||
|
std::vector<Type_Integer> mIntegers;
|
||||||
|
std::vector<Type_Float> mFloats;
|
||||||
|
std::vector<std::string> mStrings;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
@ -1,4 +1,5 @@
|
|||||||
#include "runtime.hpp"
|
#include "runtime.hpp"
|
||||||
|
#include "program.hpp"
|
||||||
|
|
||||||
#include <cassert>
|
#include <cassert>
|
||||||
#include <cstring>
|
#include <cstring>
|
||||||
@ -6,81 +7,46 @@
|
|||||||
|
|
||||||
namespace Interpreter
|
namespace Interpreter
|
||||||
{
|
{
|
||||||
Runtime::Runtime()
|
|
||||||
: mContext(nullptr)
|
|
||||||
, mCode(nullptr)
|
|
||||||
, mCodeSize(0)
|
|
||||||
, mPC(0)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
int Runtime::getPC() const
|
|
||||||
{
|
|
||||||
return mPC;
|
|
||||||
}
|
|
||||||
|
|
||||||
int Runtime::getIntegerLiteral(int index) const
|
int Runtime::getIntegerLiteral(int index) const
|
||||||
{
|
{
|
||||||
if (index < 0 || index >= static_cast<int>(mCode[1]))
|
if (index < 0 || mProgram->mIntegers.size() <= static_cast<std::size_t>(index))
|
||||||
throw std::out_of_range("out of range");
|
throw std::out_of_range("Invalid integer index");
|
||||||
|
|
||||||
const Type_Code* literalBlock = mCode + 4 + mCode[0];
|
return mProgram->mIntegers[static_cast<std::size_t>(index)];
|
||||||
|
|
||||||
return *reinterpret_cast<const int*>(&literalBlock[index]);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
float Runtime::getFloatLiteral(int index) const
|
float Runtime::getFloatLiteral(int index) const
|
||||||
{
|
{
|
||||||
if (index < 0 || index >= static_cast<int>(mCode[2]))
|
if (index < 0 || mProgram->mFloats.size() <= static_cast<std::size_t>(index))
|
||||||
throw std::out_of_range("out of range");
|
throw std::out_of_range("Invalid float index");
|
||||||
|
|
||||||
const Type_Code* literalBlock = mCode + 4 + mCode[0] + mCode[1];
|
return mProgram->mFloats[static_cast<std::size_t>(index)];
|
||||||
|
|
||||||
return *reinterpret_cast<const float*>(&literalBlock[index]);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string_view Runtime::getStringLiteral(int index) const
|
std::string_view Runtime::getStringLiteral(int index) const
|
||||||
{
|
{
|
||||||
if (index < 0 || static_cast<int>(mCode[3]) <= 0)
|
if (index < 0 || mProgram->mStrings.size() <= static_cast<std::size_t>(index))
|
||||||
throw std::out_of_range("out of range");
|
throw std::out_of_range("Invalid string literal index");
|
||||||
|
|
||||||
const char* literalBlock = reinterpret_cast<const char*>(mCode + 4 + mCode[0] + mCode[1] + mCode[2]);
|
return mProgram->mStrings[static_cast<std::size_t>(index)];
|
||||||
|
|
||||||
size_t offset = 0;
|
|
||||||
|
|
||||||
for (; index; --index)
|
|
||||||
{
|
|
||||||
offset += std::strlen(literalBlock + offset) + 1;
|
|
||||||
if (offset / 4 >= mCode[3])
|
|
||||||
throw std::out_of_range("out of range");
|
|
||||||
}
|
|
||||||
|
|
||||||
return literalBlock + offset;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Runtime::configure(const Type_Code* code, int codeSize, Context& context)
|
void Runtime::configure(const Program& program, Context& context)
|
||||||
{
|
{
|
||||||
clear();
|
clear();
|
||||||
|
|
||||||
mContext = &context;
|
mContext = &context;
|
||||||
mCode = code;
|
mProgram = &program;
|
||||||
mCodeSize = codeSize;
|
|
||||||
mPC = 0;
|
mPC = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Runtime::clear()
|
void Runtime::clear()
|
||||||
{
|
{
|
||||||
mContext = nullptr;
|
mContext = nullptr;
|
||||||
mCode = nullptr;
|
mProgram = nullptr;
|
||||||
mCodeSize = 0;
|
|
||||||
mStack.clear();
|
mStack.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
void Runtime::setPC(int PC)
|
|
||||||
{
|
|
||||||
mPC = PC;
|
|
||||||
}
|
|
||||||
|
|
||||||
void Runtime::push(const Data& data)
|
void Runtime::push(const Data& data)
|
||||||
{
|
{
|
||||||
mStack.push_back(data);
|
mStack.push_back(data);
|
||||||
@ -108,12 +74,12 @@ namespace Interpreter
|
|||||||
mStack.pop_back();
|
mStack.pop_back();
|
||||||
}
|
}
|
||||||
|
|
||||||
Data& Runtime::operator[](int Index)
|
Data& Runtime::operator[](int index)
|
||||||
{
|
{
|
||||||
if (Index < 0 || Index >= static_cast<int>(mStack.size()))
|
if (index < 0 || index >= static_cast<int>(mStack.size()))
|
||||||
throw std::runtime_error("stack index out of range");
|
throw std::runtime_error("stack index out of range");
|
||||||
|
|
||||||
return mStack[mStack.size() - Index - 1];
|
return mStack[mStack.size() - index - 1];
|
||||||
}
|
}
|
||||||
|
|
||||||
Context& Runtime::getContext()
|
Context& Runtime::getContext()
|
||||||
|
@ -9,21 +9,19 @@
|
|||||||
namespace Interpreter
|
namespace Interpreter
|
||||||
{
|
{
|
||||||
class Context;
|
class Context;
|
||||||
|
struct Program;
|
||||||
|
|
||||||
/// Runtime data and engine interface
|
/// Runtime data and engine interface
|
||||||
|
|
||||||
class Runtime
|
class Runtime
|
||||||
{
|
{
|
||||||
Context* mContext;
|
Context* mContext = nullptr;
|
||||||
const Type_Code* mCode;
|
const Program* mProgram = nullptr;
|
||||||
int mCodeSize;
|
int mPC = 0;
|
||||||
int mPC;
|
|
||||||
std::vector<Data> mStack;
|
std::vector<Data> mStack;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
Runtime();
|
int getPC() const { return mPC; }
|
||||||
|
|
||||||
int getPC() const;
|
|
||||||
///< return program counter.
|
///< return program counter.
|
||||||
|
|
||||||
int getIntegerLiteral(int index) const;
|
int getIntegerLiteral(int index) const;
|
||||||
@ -32,13 +30,13 @@ namespace Interpreter
|
|||||||
|
|
||||||
std::string_view getStringLiteral(int index) const;
|
std::string_view getStringLiteral(int index) const;
|
||||||
|
|
||||||
void configure(const Type_Code* code, int codeSize, Context& context);
|
void configure(const Program& program, Context& context);
|
||||||
///< \a context and \a code must exist as least until either configure, clear or
|
///< \a context and \a code must exist as least until either configure, clear or
|
||||||
/// the destructor is called. \a codeSize is given in 32-bit words.
|
/// the destructor is called.
|
||||||
|
|
||||||
void clear();
|
void clear();
|
||||||
|
|
||||||
void setPC(int PC);
|
void setPC(int value) { mPC = value; }
|
||||||
///< set program counter.
|
///< set program counter.
|
||||||
|
|
||||||
void push(const Data& data);
|
void push(const Data& data);
|
||||||
@ -53,7 +51,7 @@ namespace Interpreter
|
|||||||
void pop();
|
void pop();
|
||||||
///< pop stack
|
///< pop stack
|
||||||
|
|
||||||
Data& operator[](int Index);
|
Data& operator[](int index);
|
||||||
///< Access stack member, counted from the top.
|
///< Access stack member, counted from the top.
|
||||||
|
|
||||||
Context& getContext();
|
Context& getContext();
|
||||||
|
@ -5,15 +5,13 @@
|
|||||||
|
|
||||||
namespace Interpreter
|
namespace Interpreter
|
||||||
{
|
{
|
||||||
typedef unsigned int Type_Code; // 32 bit
|
typedef std::uint32_t Type_Code;
|
||||||
|
|
||||||
typedef unsigned int Type_Data; // 32 bit
|
typedef std::int16_t Type_Short;
|
||||||
|
|
||||||
typedef short Type_Short; // 16 bit
|
typedef std::int32_t Type_Integer;
|
||||||
|
|
||||||
typedef int Type_Integer; // 32 bit
|
typedef float Type_Float;
|
||||||
|
|
||||||
typedef float Type_Float; // 32 bit
|
|
||||||
|
|
||||||
union Data
|
union Data
|
||||||
{
|
{
|
||||||
|
Loading…
x
Reference in New Issue
Block a user