1
0
Fork 1
mirror of https://github.com/TES3MP/openmw-tes3mp.git synced 2025-02-21 07:39:40 +00:00

Merge branch 'script'

This commit is contained in:
Marc Zinnschlag 2010-09-01 21:04:16 +02:00
commit 6c4c90ef2d
33 changed files with 1525 additions and 799 deletions

View file

@ -60,6 +60,8 @@ set(GAMESCRIPT
mwscript/skyextensions.cpp
mwscript/statsextensions.cpp
mwscript/containerextensions.cpp
mwscript/aiextensions.cpp
mwscript/controlextensions.cpp
mwscript/extensions.cpp
mwscript/globalscripts.cpp
)
@ -75,6 +77,8 @@ set(GAMESCRIPT_HEADER
mwscript/skyextensions.hpp
mwscript/statsextensions.hpp
mwscript/containerextensions.hpp
mwscript/aiextensions.hpp
mwscript/controlextensions.hpp
mwscript/extensions.hpp
mwscript/globalscripts.hpp
)

View file

@ -15,6 +15,8 @@
#include "../mwrender/cellimp.hpp"
#include <iostream>
namespace MWClass
{
void Door::insertObj (const MWWorld::Ptr& ptr, MWRender::CellRenderImp& cellRender,
@ -50,6 +52,16 @@ namespace MWClass
ESMS::LiveCellRef<ESM::Door, MWWorld::RefData> *ref =
ptr.get<ESM::Door>();
if (ptr.getCellRef().lockLevel>0)
{
// TODO check for key
// TODO report failure to player (message, sound?). Look up behaviour of original MW.
std::cout << "Locked!" << std::endl;
return boost::shared_ptr<MWWorld::Action> (new MWWorld::NullAction);
}
// TODO check trap
if (ref->ref.teleport)
{
// teleport door
@ -74,6 +86,19 @@ namespace MWClass
}
}
void Door::lock (const MWWorld::Ptr& ptr, int lockLevel) const
{
if (lockLevel<0)
lockLevel = 0;
ptr.getCellRef().lockLevel = lockLevel;
}
void Door::unlock (const MWWorld::Ptr& ptr) const
{
ptr.getCellRef().lockLevel = 0;
}
std::string Door::getScript (const MWWorld::Ptr& ptr) const
{
ESMS::LiveCellRef<ESM::Door, MWWorld::RefData> *ref =

View file

@ -21,6 +21,12 @@ namespace MWClass
const MWWorld::Ptr& actor, const MWWorld::Environment& environment) const;
///< Generate action for activation
virtual void lock (const MWWorld::Ptr& ptr, int lockLevel) const;
///< Lock object
virtual void unlock (const MWWorld::Ptr& ptr) const;
///< Unlock object
virtual std::string getScript (const MWWorld::Ptr& ptr) const;
///< Return name of the script attached to ptr

View file

@ -15,9 +15,6 @@ namespace MWGui
ConsoleInterpreterContext (Console& console, MWWorld::Environment& environment,
MWWorld::Ptr reference);
virtual void messageBox (const std::string& message,
const std::vector<std::string>& buttons);
};
ConsoleInterpreterContext::ConsoleInterpreterContext (Console& console,
@ -27,15 +24,6 @@ namespace MWGui
mConsole (console)
{}
void ConsoleInterpreterContext::messageBox (const std::string& message,
const std::vector<std::string>& buttons)
{
if (!buttons.empty())
mConsole.printError ("MessageBox doesn't support buttons while in console mode");
else
mConsole.printOK (message);
}
bool Console::compile (const std::string& cmd, Compiler::Output& output)
{
try
@ -196,7 +184,7 @@ namespace MWGui
Compiler::Locals locals;
Compiler::Output output (locals);
if (compile (cm, output))
if (compile (cm + "\n", output))
{
try
{
@ -216,4 +204,3 @@ namespace MWGui
command->setCaption("");
}
}

View file

@ -4,6 +4,8 @@
#include "console.hpp"
#include <assert.h>
#include <iostream>
#include <iterator>
using namespace MWGui;
@ -95,3 +97,15 @@ void WindowManager::setValue (const std::string& id, const MWMechanics::DynamicS
stats->setValue (id, value);
hud->setValue (id, value);
}
void WindowManager::messageBox (const std::string& message, const std::vector<std::string>& buttons)
{
std::cout << "message box: " << message << std::endl;
if (!buttons.empty())
{
std::cout << "buttons: ";
std::copy (buttons.begin(), buttons.end(), std::ostream_iterator<std::string> (std::cout, ", "));
std::cout << std::endl;
}
}

View file

@ -11,6 +11,7 @@
*/
#include <string>
#include <vector>
#include "../mwmechanics/stat.hpp"
@ -144,6 +145,8 @@ namespace MWGui
void setValue (const std::string& id, const MWMechanics::DynamicStat<int>& value);
///< Set value for the given ID.
void messageBox (const std::string& message, const std::vector<std::string>& buttons);
};
}
#endif

View file

@ -0,0 +1,215 @@
#include "aiextensions.hpp"
#include <components/compiler/extensions.hpp>
#include <components/interpreter/interpreter.hpp>
#include <components/interpreter/runtime.hpp>
#include <components/interpreter/opcodes.hpp>
#include "interpretercontext.hpp"
#include <iostream>
namespace MWScript
{
namespace Ai
{
class OpAiTravel : public Interpreter::Opcode1
{
public:
virtual void execute (Interpreter::Runtime& runtime, unsigned int arg0)
{
MWScript::InterpreterContext& context
= static_cast<MWScript::InterpreterContext&> (runtime.getContext());
MWWorld::Ptr ptr = context.getReference();
Interpreter::Type_Float x = runtime[0].mInteger;
runtime.pop();
Interpreter::Type_Float y = runtime[0].mInteger;
runtime.pop();
Interpreter::Type_Float z = runtime[0].mInteger;
runtime.pop();
// discard additional arguments (reset), because we have no idea what they mean.
for (unsigned int i=0; i<arg0; ++i) runtime.pop();
std::cout << "AiTravel: " << x << ", " << y << ", " << z << std::endl;
}
};
class OpAiTravelExplicit : public Interpreter::Opcode1
{
public:
virtual void execute (Interpreter::Runtime& runtime, unsigned int arg0)
{
MWScript::InterpreterContext& context
= static_cast<MWScript::InterpreterContext&> (runtime.getContext());
std::string id = runtime.getStringLiteral (runtime[0].mInteger);
runtime.pop();
MWWorld::Ptr ptr = context.getWorld().getPtr (id, false);
Interpreter::Type_Float x = runtime[0].mInteger;
runtime.pop();
Interpreter::Type_Float y = runtime[0].mInteger;
runtime.pop();
Interpreter::Type_Float z = runtime[0].mInteger;
runtime.pop();
// discard additional arguments (reset), because we have no idea what they mean.
for (unsigned int i=0; i<arg0; ++i) runtime.pop();
std::cout << "AiTravel: " << x << ", " << y << ", " << z << std::endl;
}
};
class OpAiEscort : public Interpreter::Opcode1
{
public:
virtual void execute (Interpreter::Runtime& runtime, unsigned int arg0)
{
MWScript::InterpreterContext& context
= static_cast<MWScript::InterpreterContext&> (runtime.getContext());
std::string id = runtime.getStringLiteral (runtime[0].mInteger);
runtime.pop();
MWWorld::Ptr ptr = context.getReference();
std::string actor = runtime.getStringLiteral (runtime[0].mInteger);
runtime.pop();
Interpreter::Type_Float duration = runtime[0].mInteger;
runtime.pop();
Interpreter::Type_Float x = runtime[0].mInteger;
runtime.pop();
Interpreter::Type_Float y = runtime[0].mInteger;
runtime.pop();
Interpreter::Type_Float z = runtime[0].mInteger;
runtime.pop();
// discard additional arguments (reset), because we have no idea what they mean.
for (unsigned int i=0; i<arg0; ++i) runtime.pop();
std::cout << "AiEscort: " << x << ", " << y << ", " << z << ", " << duration
<< std::endl;
}
};
class OpAiEscortExplicit : public Interpreter::Opcode1
{
public:
virtual void execute (Interpreter::Runtime& runtime, unsigned int arg0)
{
MWScript::InterpreterContext& context
= static_cast<MWScript::InterpreterContext&> (runtime.getContext());
std::string id = runtime.getStringLiteral (runtime[0].mInteger);
runtime.pop();
MWWorld::Ptr ptr = context.getWorld().getPtr (id, false);
std::string actor = runtime.getStringLiteral (runtime[0].mInteger);
runtime.pop();
Interpreter::Type_Float duration = runtime[0].mInteger;
runtime.pop();
Interpreter::Type_Float x = runtime[0].mInteger;
runtime.pop();
Interpreter::Type_Float y = runtime[0].mInteger;
runtime.pop();
Interpreter::Type_Float z = runtime[0].mInteger;
runtime.pop();
// discard additional arguments (reset), because we have no idea what they mean.
for (unsigned int i=0; i<arg0; ++i) runtime.pop();
std::cout << "AiEscort: " << x << ", " << y << ", " << z << ", " << duration
<< std::endl;
}
};
class OpGetAiPackageDone : public Interpreter::Opcode0
{
public:
virtual void execute (Interpreter::Runtime& runtime)
{
MWScript::InterpreterContext& context
= static_cast<MWScript::InterpreterContext&> (runtime.getContext());
MWWorld::Ptr ptr = context.getReference();
Interpreter::Type_Integer value = 0;
runtime.push (value);
}
};
class OpGetAiPackageDoneExplicit : public Interpreter::Opcode0
{
public:
virtual void execute (Interpreter::Runtime& runtime)
{
MWScript::InterpreterContext& context
= static_cast<MWScript::InterpreterContext&> (runtime.getContext());
std::string id = runtime.getStringLiteral (runtime[0].mInteger);
runtime.pop();
MWWorld::Ptr ptr = context.getWorld().getPtr (id, false);
Interpreter::Type_Integer value = 0;
runtime.push (value);
}
};
const int opcodeAiTravel = 0x20000;
const int opcodeAiTravelExplicit = 0x20001;
const int opcodeAiEscort = 0x20002;
const int opcodeAiEscortExplicit = 0x20003;
const int opcodeGetAiPackageDone = 0x200007c;
const int opcodeGetAiPackageDoneExplicit = 0x200007d;
void registerExtensions (Compiler::Extensions& extensions)
{
extensions.registerInstruction ("aitravel", "lll/l", opcodeAiTravel,
opcodeAiTravelExplicit);
extensions.registerInstruction ("aiescort", "cllll/l", opcodeAiEscort,
opcodeAiEscortExplicit);
extensions.registerFunction ("getaipackagedone", 'l', "", opcodeGetAiPackageDone,
opcodeGetAiPackageDoneExplicit);
}
void installOpcodes (Interpreter::Interpreter& interpreter)
{
interpreter.installSegment3 (opcodeAiTravel, new OpAiTravel);
interpreter.installSegment3 (opcodeAiTravelExplicit, new OpAiTravelExplicit);
interpreter.installSegment3 (opcodeAiEscort, new OpAiEscort);
interpreter.installSegment3 (opcodeAiEscortExplicit, new OpAiEscortExplicit);
interpreter.installSegment5 (opcodeGetAiPackageDone, new OpGetAiPackageDone);
interpreter.installSegment5 (opcodeGetAiPackageDoneExplicit, new OpGetAiPackageDoneExplicit);
}
}
}

View file

@ -0,0 +1,25 @@
#ifndef GAME_SCRIPT_AIEXTENSIONS_H
#define GAME_SCRIPT_AIEXTENSIONS_H
namespace Compiler
{
class Extensions;
}
namespace Interpreter
{
class Interpreter;
}
namespace MWScript
{
/// \brief AI-related script functionality
namespace Ai
{
void registerExtensions (Compiler::Extensions& extensions);
void installOpcodes (Interpreter::Interpreter& interpreter);
}
}
#endif

View file

@ -0,0 +1,70 @@
#include "statsextensions.hpp"
#include <components/compiler/extensions.hpp>
#include <components/interpreter/interpreter.hpp>
#include <components/interpreter/runtime.hpp>
#include <components/interpreter/opcodes.hpp>
#include "interpretercontext.hpp"
#include <iostream>
namespace MWScript
{
namespace Control
{
class OpSetControl : public Interpreter::Opcode0
{
std::string mControl;
bool mEnable;
public:
OpSetControl (const std::string& control, bool enable)
: mControl (control), mEnable (enable)
{}
virtual void execute (Interpreter::Runtime& runtime)
{
if (mEnable)
std::cout << "enable: " << mControl << std::endl;
else
std::cout << "disable: " << mControl << std::endl;
}
};
const int numberOfControls = 7;
const int opcodeEnable = 0x200007e;
const int opcodeDisable = 0x2000085;
const char *controls[numberOfControls] =
{
"playercontrols", "playerfighting", "playerjumping", "playerlooking", "playermagic",
"playerviewswitch", "vanitymode"
};
void registerExtensions (Compiler::Extensions& extensions)
{
std::string enable ("enable");
std::string disable ("disable");
for (int i=0; i<numberOfControls; ++i)
{
extensions.registerInstruction (enable + controls[i], "", opcodeEnable+i);
extensions.registerInstruction (disable + controls[i], "", opcodeDisable+i);
}
}
void installOpcodes (Interpreter::Interpreter& interpreter)
{
for (int i=0; i<numberOfControls; ++i)
{
interpreter.installSegment5 (opcodeEnable+i, new OpSetControl (controls[i], true));
interpreter.installSegment5 (opcodeDisable+i, new OpSetControl (controls[i], false));
}
}
}
}

View file

@ -0,0 +1,25 @@
#ifndef GAME_SCRIPT_CONTROLEXTENSIONS_H
#define GAME_SCRIPT_CONTROLEXTENSIONS_H
namespace Compiler
{
class Extensions;
}
namespace Interpreter
{
class Interpreter;
}
namespace MWScript
{
/// \brief player controls-related script functionality
namespace Control
{
void registerExtensions (Compiler::Extensions& extensions);
void installOpcodes (Interpreter::Interpreter& interpreter);
}
}
#endif

View file

@ -13,8 +13,13 @@ Segment 2:
opcodes 0x200-0x3ff unused
Segment 3:
(not implemented yet)
opcodes 0x200-0x3ff unused
op 0x20000: AiTravel
op 0x20001: AiTravel, explicit reference
op 0x20002: AiEscort
op 0x20003: AiEscort, explicit reference
op 0x20004: Lock
op 0x20005: Lock, explicit reference
opcodes 0x20006-0x3ffff unused
Segment 4:
(not implemented yet)
@ -83,4 +88,10 @@ op 0x2000078: GetItemCount
op 0x2000079: GetItemCount, explicit reference
op 0x200007a: RemoveItem
op 0x200007b: RemoveItem, explicit reference
opcodes 0x200007c-0x3ffffff unused
op 0x200007c: GetAiPackageDone
op 0x200007d: GetAiPackageDone, explicit reference
op 0x200007e-0x2000084: Enable Controls
op 0x2000085-0x200008b: Disable Controls
op 0x200008c: Unlock
op 0x200008d: Unlock, explicit reference
opcodes 0x200008e-0x3ffffff unused

View file

@ -11,6 +11,8 @@
#include "skyextensions.hpp"
#include "statsextensions.hpp"
#include "containerextensions.hpp"
#include "aiextensions.hpp"
#include "controlextensions.hpp"
namespace MWScript
{
@ -23,6 +25,8 @@ namespace MWScript
Sky::registerExtensions (extensions);
Stats::registerExtensions (extensions);
Container::registerExtensions (extensions);
Ai::registerExtensions (extensions);
Control::registerExtensions (extensions);
}
void installOpcodes (Interpreter::Interpreter& interpreter)
@ -35,5 +39,7 @@ namespace MWScript
Sky::installOpcodes (interpreter);
Stats::installOpcodes (interpreter);
Container::installOpcodes (interpreter);
Ai::installOpcodes (interpreter);
Control::installOpcodes (interpreter);
}
}

View file

@ -105,10 +105,7 @@ namespace MWScript
void InterpreterContext::messageBox (const std::string& message,
const std::vector<std::string>& buttons)
{
std::cout << "message box: " << message << std::endl;
if (!buttons.empty())
std::cerr << "error: message box buttons not supported" << std::endl;
mEnvironment.mWindowManager->messageBox (message, buttons);
}
bool InterpreterContext::menuMode()

View file

@ -9,6 +9,8 @@
#include "interpretercontext.hpp"
#include "../mwworld/class.hpp"
namespace MWScript
{
namespace Misc
@ -53,15 +55,104 @@ namespace MWScript
}
};
class OpLock : public Interpreter::Opcode1
{
public:
virtual void execute (Interpreter::Runtime& runtime, unsigned int arg0)
{
InterpreterContext& context =
static_cast<InterpreterContext&> (runtime.getContext());
MWWorld::Ptr ptr = context.getReference();
Interpreter::Type_Integer lockLevel = 100;
if (arg0==1)
{
lockLevel = runtime[0].mInteger;
runtime.pop();
}
MWWorld::Class::get (ptr).lock (ptr, lockLevel);
}
};
class OpLockExplicit : public Interpreter::Opcode1
{
public:
virtual void execute (Interpreter::Runtime& runtime, unsigned int arg0)
{
InterpreterContext& context =
static_cast<InterpreterContext&> (runtime.getContext());
std::string id = runtime.getStringLiteral (runtime[0].mInteger);
runtime.pop();
MWWorld::Ptr ptr = context.getWorld().getPtr (id, false);
Interpreter::Type_Integer lockLevel = 100;
if (arg0==1)
{
lockLevel = runtime[0].mInteger;
runtime.pop();
}
MWWorld::Class::get (ptr).lock (ptr, lockLevel);
}
};
class OpUnlock : public Interpreter::Opcode0
{
public:
virtual void execute (Interpreter::Runtime& runtime)
{
InterpreterContext& context =
static_cast<InterpreterContext&> (runtime.getContext());
MWWorld::Ptr ptr = context.getReference();
MWWorld::Class::get (ptr).unlock (ptr);
}
};
class OpUnlockExplicit : public Interpreter::Opcode0
{
public:
virtual void execute (Interpreter::Runtime& runtime)
{
InterpreterContext& context =
static_cast<InterpreterContext&> (runtime.getContext());
std::string id = runtime.getStringLiteral (runtime[0].mInteger);
runtime.pop();
MWWorld::Ptr ptr = context.getWorld().getPtr (id, false);
MWWorld::Class::get (ptr).unlock (ptr);
}
};
const int opcodeXBox = 0x200000c;
const int opcodeOnActivate = 0x200000d;
const int opcodeActivate = 0x2000075;
const int opcodeLock = 0x20004;
const int opcodeLockExplicit = 0x20005;
const int opcodeUnlock = 0x200008c;
const int opcodeUnlockExplicit = 0x200008d;
void registerExtensions (Compiler::Extensions& extensions)
{
extensions.registerFunction ("xbox", 'l', "", opcodeXBox);
extensions.registerFunction ("onactivate", 'l', "", opcodeOnActivate);
extensions.registerInstruction ("activate", "", opcodeActivate);
extensions.registerInstruction ("lock", "/l", opcodeLock, opcodeLockExplicit);
extensions.registerInstruction ("unlock", "", opcodeUnlock, opcodeUnlockExplicit);
}
void installOpcodes (Interpreter::Interpreter& interpreter)
@ -69,6 +160,10 @@ namespace MWScript
interpreter.installSegment5 (opcodeXBox, new OpXBox);
interpreter.installSegment5 (opcodeOnActivate, new OpOnActivate);
interpreter.installSegment5 (opcodeActivate, new OpActivate);
interpreter.installSegment3 (opcodeLock, new OpLock);
interpreter.installSegment3 (opcodeLockExplicit, new OpLockExplicit);
interpreter.installSegment5 (opcodeUnlock, new OpUnlock);
interpreter.installSegment5 (opcodeUnlockExplicit, new OpUnlockExplicit);
}
}
}

View file

@ -77,6 +77,16 @@ namespace MWWorld
throw std::runtime_error ("class does not support inserting into a container");
}
void Class::lock (const Ptr& ptr, int lockLevel) const
{
throw std::runtime_error ("class does not support locking");
}
void Class::unlock (const Ptr& ptr) const
{
throw std::runtime_error ("class does not support unlocking");
}
std::string Class::getScript (const Ptr& ptr) const
{
return "";

View file

@ -98,6 +98,12 @@ namespace MWWorld
///< Insert into a container or throw an exception, if class does not support inserting into
/// a container.
virtual void lock (const Ptr& ptr, int lockLevel) const;
///< Lock object (default implementation: throw an exception)
virtual void unlock (const Ptr& ptr) const;
///< Unlock object (default implementation: throw an exception)
virtual std::string getScript (const Ptr& ptr) const;
///< Return name of the script attached to ptr (default implementation: return an empty
/// string).

View file

@ -172,6 +172,20 @@ namespace Compiler
std::copy (mCode.begin(), mCode.end(), std::back_inserter (code));
}
bool ControlParser::parseName (const std::string& name, const TokenLoc& loc, Scanner& scanner)
{
if (mState==IfBodyState || mState==IfElseifBodyState || mState==IfElseBodyState ||
mState==WhileBodyState)
{
scanner.putbackName (name, loc);
mLineParser.reset();
scanner.scan (mLineParser);
return true;
}
return Parser::parseName (name, loc, scanner);
}
bool ControlParser::parseKeyword (int keyword, const TokenLoc& loc, Scanner& scanner)
{
if (mState==StartState)
@ -245,6 +259,6 @@ namespace Compiler
mCodeBlock.clear();
mIfCode.clear();
mState = StartState;
Parser::reset();
}
}

View file

@ -53,6 +53,11 @@ namespace Compiler
void appendCode (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.
/// \return fetch another token?
virtual bool parseKeyword (int keyword, const TokenLoc& loc, Scanner& scanner);
///< Handle a keyword token.
/// \return fetch another token?
@ -67,4 +72,3 @@ namespace Compiler
}
#endif

View file

@ -190,9 +190,9 @@ namespace Compiler
popOperator();
}
void ExprParser::parseArguments (const std::string& arguments, Scanner& scanner)
int ExprParser::parseArguments (const std::string& arguments, Scanner& scanner)
{
parseArguments (arguments, scanner, mCode);
return parseArguments (arguments, scanner, mCode);
}
ExprParser::ExprParser (ErrorHandler& errorHandler, Context& context, Locals& locals,
@ -210,6 +210,8 @@ namespace Compiler
if (mNextOperand)
{
start();
pushIntegerLiteral (value);
mTokenLoc = loc;
return true;
@ -231,6 +233,8 @@ namespace Compiler
if (mNextOperand)
{
start();
pushFloatLiteral (value);
mTokenLoc = loc;
return true;
@ -253,6 +257,8 @@ namespace Compiler
if (mNextOperand)
{
start();
std::string name2 = toLower (name);
char type = mLocals.getType (name2);
@ -301,6 +307,8 @@ namespace Compiler
{
if (keyword==Scanner::K_getdisabled)
{
start();
mTokenLoc = loc;
Generator::getDisabled (mCode, mLiterals, mExplicit);
@ -313,6 +321,8 @@ namespace Compiler
}
else if (keyword==Scanner::K_getdistance)
{
start();
mTokenLoc = loc;
parseArguments ("c", scanner);
@ -333,10 +343,13 @@ namespace Compiler
if (extensions->isFunction (keyword, returnType, argumentType, true))
{
mTokenLoc = loc;
parseArguments (argumentType, scanner);
start();
extensions->generateFunctionCode (keyword, mCode, mLiterals, mExplicit);
mTokenLoc = loc;
int optionals = parseArguments (argumentType, scanner);
extensions->generateFunctionCode (keyword, mCode, mLiterals, mExplicit,
optionals);
mOperands.push_back (returnType);
mExplicit.clear();
mRefOp = false;
@ -354,6 +367,8 @@ namespace Compiler
{
if (keyword==Scanner::K_getsquareroot)
{
start();
mTokenLoc = loc;
parseArguments ("f", scanner);
@ -365,6 +380,8 @@ namespace Compiler
}
else if (keyword==Scanner::K_menumode)
{
start();
mTokenLoc = loc;
Generator::menuMode (mCode);
@ -375,6 +392,8 @@ namespace Compiler
}
else if (keyword==Scanner::K_random)
{
start();
mTokenLoc = loc;
parseArguments ("l", scanner);
@ -386,6 +405,8 @@ namespace Compiler
}
else if (keyword==Scanner::K_scriptrunning)
{
start();
mTokenLoc = loc;
parseArguments ("c", scanner);
@ -397,6 +418,8 @@ namespace Compiler
}
else if (keyword==Scanner::K_getdistance)
{
start();
mTokenLoc = loc;
parseArguments ("c", scanner);
@ -408,6 +431,8 @@ namespace Compiler
}
else if (keyword==Scanner::K_getsecondspassed)
{
start();
mTokenLoc = loc;
Generator::getSecondsPassed (mCode);
@ -418,6 +443,8 @@ namespace Compiler
}
else if (keyword==Scanner::K_getdisabled)
{
start();
mTokenLoc = loc;
Generator::getDisabled (mCode, mLiterals, "");
@ -431,15 +458,17 @@ namespace Compiler
// check for custom extensions
if (const Extensions *extensions = getContext().getExtensions())
{
start();
char returnType;
std::string argumentType;
if (extensions->isFunction (keyword, returnType, argumentType, false))
{
mTokenLoc = loc;
parseArguments (argumentType, scanner);
int optionals = parseArguments (argumentType, scanner);
extensions->generateFunctionCode (keyword, mCode, mLiterals, "");
extensions->generateFunctionCode (keyword, mCode, mLiterals, "", optionals);
mOperands.push_back (returnType);
mNextOperand = false;
@ -580,6 +609,7 @@ namespace Compiler
mFirst = true;
mExplicit.clear();
mRefOp = false;
Parser::reset();
}
char ExprParser::append (std::vector<Interpreter::Type_Code>& code)
@ -605,9 +635,12 @@ namespace Compiler
return mOperands[0];
}
void ExprParser::parseArguments (const std::string& arguments, Scanner& scanner,
int ExprParser::parseArguments (const std::string& arguments, Scanner& scanner,
std::vector<Interpreter::Type_Code>& code, bool invert)
{
bool optional = false;
bool optionalCount = 0;
ExprParser parser (getErrorHandler(), getContext(), mLocals, mLiterals, true);
StringParser stringParser (getErrorHandler(), getContext(), mLiterals);
@ -616,12 +649,23 @@ namespace Compiler
for (std::string::const_iterator iter (arguments.begin()); iter!=arguments.end();
++iter)
{
if (*iter=='S' || *iter=='c')
if (*iter=='/')
{
optional = true;
}
else if (*iter=='S' || *iter=='c')
{
stringParser.reset();
if (optional)
stringParser.setOptional (true);
if (*iter=='c') stringParser.smashCase();
scanner.scan (stringParser);
if (optional && stringParser.isEmpty())
break;
if (invert)
{
std::vector<Interpreter::Type_Code> tmp;
@ -631,12 +675,22 @@ namespace Compiler
}
else
stringParser.append (code);
if (optional)
++optionalCount;
}
else
{
parser.reset();
if (optional)
parser.setOptional (true);
scanner.scan (parser);
if (optional && parser.isEmpty())
break;
std::vector<Interpreter::Type_Code> tmp;
char type = parser.append (tmp);
@ -648,6 +702,9 @@ namespace Compiler
stack.push (tmp);
else
std::copy (tmp.begin(), tmp.end(), std::back_inserter (code));
if (optional)
++optionalCount;
}
}
@ -659,6 +716,7 @@ namespace Compiler
stack.pop();
}
}
}
return optionalCount;
}
}

View file

@ -51,7 +51,7 @@ namespace Compiler
void close();
void parseArguments (const std::string& arguments, Scanner& scanner);
int parseArguments (const std::string& arguments, Scanner& scanner);
public:
@ -92,12 +92,14 @@ namespace Compiler
///< Generate code for parsed expression.
/// \return Type ('l': integer, 'f': float)
void parseArguments (const std::string& arguments, Scanner& scanner,
int parseArguments (const std::string& arguments, Scanner& scanner,
std::vector<Interpreter::Type_Code>& code, bool invert = false);
///< Parse sequence of arguments specified by \a arguments.
/// \param arguments Each character represents one arguments ('l': integer,
/// 'f': float, 'S': string, 'c': string (case smashed))
/// 'f': float, 'S': string, 'c': string (case smashed), '/': following arguments are
/// optional)
/// \param invert Store arguments in reverted order.
/// \return number of optional arguments
};
}

View file

@ -53,48 +53,77 @@ namespace Compiler
}
void Extensions::registerFunction (const std::string& keyword, char returnType,
const std::string& argumentType, int segment5code, int segment5codeExplicit)
const std::string& argumentType, int code, int codeExplicit)
{
assert (segment5code>=33554432 && segment5code<=67108863);
int code = mNextKeywordIndex--;
mKeywords.insert (std::make_pair (keyword, code));
Function function;
if (argumentType.find ('/')==std::string::npos)
{
function.mSegment = 5;
assert (code>=33554432 && code<=67108863);
assert (codeExplicit==-1 || (codeExplicit>=33554432 && codeExplicit<=67108863));
}
else
{
function.mSegment = 3;
assert (code>=0x20000 && code<=0x2ffff);
assert (codeExplicit==-1 || (codeExplicit>=0x20000 && codeExplicit<=0x2ffff));
}
int keywordIndex = mNextKeywordIndex--;
mKeywords.insert (std::make_pair (keyword, keywordIndex));
function.mReturn = returnType;
function.mArguments = argumentType;
function.mCode = segment5code;
function.mCodeExplicit = segment5codeExplicit;
function.mCode = code;
function.mCodeExplicit = codeExplicit;
mFunctions.insert (std::make_pair (code, function));
mFunctions.insert (std::make_pair (keywordIndex, function));
}
void Extensions::registerInstruction (const std::string& keyword,
const std::string& argumentType, int segment5code, int segment5codeExplicit)
const std::string& argumentType, int code, int codeExplicit)
{
assert (segment5code>=33554432 && segment5code<=67108863);
int code = mNextKeywordIndex--;
mKeywords.insert (std::make_pair (keyword, code));
Instruction instruction;
instruction.mArguments = argumentType;
instruction.mCode = segment5code;
instruction.mCodeExplicit = segment5codeExplicit;
mInstructions.insert (std::make_pair (code, instruction));
if (argumentType.find ('/')==std::string::npos)
{
instruction.mSegment = 5;
assert (code>=33554432 && code<=67108863);
assert (codeExplicit==-1 || (codeExplicit>=33554432 && codeExplicit<=67108863));
}
else
{
instruction.mSegment = 3;
assert (code>=0x20000 && code<=0x2ffff);
assert (codeExplicit==-1 || (codeExplicit>=0x20000 && codeExplicit<=0x2ffff));
}
int keywordIndex = mNextKeywordIndex--;
mKeywords.insert (std::make_pair (keyword, keywordIndex));
instruction.mArguments = argumentType;
instruction.mCode = code;
instruction.mCodeExplicit = codeExplicit;
mInstructions.insert (std::make_pair (keywordIndex, instruction));
}
void Extensions::generateFunctionCode (int keyword, std::vector<Interpreter::Type_Code>& code,
Literals& literals, const std::string& id) const
Literals& literals, const std::string& id, int optionalArguments) const
{
assert (optionalArguments>=0);
std::map<int, Function>::const_iterator iter = mFunctions.find (keyword);
if (iter==mFunctions.end())
throw std::logic_error ("unknown custom function keyword");
if (optionalArguments && iter->second.mSegment!=3)
throw std::logic_error ("functions with optional arguments must be placed into segment 3");
if (!id.empty())
{
if (iter->second.mCodeExplicit==-1)
@ -104,19 +133,46 @@ namespace Compiler
Generator::pushInt (code, literals, index);
}
switch (iter->second.mSegment)
{
case 3:
if (optionalArguments>=256)
throw std::logic_error ("number of optional arguments is too large for segment 3");
code.push_back (Generator::segment3 (
id.empty() ? iter->second.mCode : iter->second.mCodeExplicit,
optionalArguments));
break;
case 5:
code.push_back (Generator::segment5 (
id.empty() ? iter->second.mCode : iter->second.mCodeExplicit));
break;
default:
throw std::logic_error ("unsupported code segment");
}
}
void Extensions::generateInstructionCode (int keyword,
std::vector<Interpreter::Type_Code>& code, Literals& literals, const std::string& id)
const
std::vector<Interpreter::Type_Code>& code, Literals& literals, const std::string& id,
int optionalArguments) const
{
assert (optionalArguments>=0);
std::map<int, Instruction>::const_iterator iter = mInstructions.find (keyword);
if (iter==mInstructions.end())
throw std::logic_error ("unknown custom instruction keyword");
if (optionalArguments && iter->second.mSegment!=3)
throw std::logic_error ("instructions with optional arguments must be placed into segment 3");
if (!id.empty())
{
if (iter->second.mCodeExplicit==-1)
@ -126,7 +182,29 @@ namespace Compiler
Generator::pushInt (code, literals, index);
}
switch (iter->second.mSegment)
{
case 3:
if (optionalArguments>=256)
throw std::logic_error ("number of optional arguments is too large for segment 3");
code.push_back (Generator::segment3 (
id.empty() ? iter->second.mCode : iter->second.mCodeExplicit,
optionalArguments));
break;
case 5:
code.push_back (Generator::segment5 (
id.empty() ? iter->second.mCode : iter->second.mCodeExplicit));
break;
default:
throw std::logic_error ("unsupported code segment");
}
}
}

View file

@ -21,6 +21,7 @@ namespace Compiler
std::string mArguments;
int mCode;
int mCodeExplicit;
int mSegment;
};
struct Instruction
@ -28,6 +29,7 @@ namespace Compiler
std::string mArguments;
int mCode;
int mCodeExplicit;
int mSegment;
};
int mNextKeywordIndex;
@ -54,30 +56,29 @@ namespace Compiler
///< Is this keyword registered with a function? If yes, return argument types.
void registerFunction (const std::string& keyword, char returnType,
const std::string& argumentType, int segment5code, int segment5codeExplicit = -1);
const std::string& argumentType, int code, int codeExplicit = -1);
///< Register a custom function
/// - keyword must be all lower case.
/// - keyword must be unique
/// - if explicit references are not supported, segment5codeExplicit must be set to -1
/// \note Currently only segment 5 opcodes are supported.
/// \note Currently only segment 3 and segment 5 opcodes are supported.
void registerInstruction (const std::string& keyword,
const std::string& argumentType, int segment5code, int segment5codeExplicit = -1);
const std::string& argumentType, int code, int codeExplicit = -1);
///< Register a custom instruction
/// - keyword must be all lower case.
/// - keyword must be unique
/// - if explicit references are not supported, segment5codeExplicit must be set to -1
/// \note Currently only segment 5 opcodes are supported.
/// \note Currently only segment 3 and segment 5 opcodes are supported.
void generateFunctionCode (int keyword, std::vector<Interpreter::Type_Code>& code,
Literals& literals, const std::string& id) const;
Literals& literals, const std::string& id, int optionalArguments) const;
///< Append code for function to \a code.
void generateInstructionCode (int keyword, std::vector<Interpreter::Type_Code>& code,
Literals& literals, const std::string& id) const;
Literals& literals, const std::string& id, int optionalArguments) const;
///< Append code for function to \a code.
};
}
#endif

View file

@ -113,6 +113,6 @@ namespace Compiler
mState = BeginState;
mName.clear();
mScriptParser.reset();
Parser::reset();
}
}

View file

@ -505,7 +505,10 @@ namespace Compiler
void message (CodeContainer& code, Literals& literals, const std::string& message,
int buttons)
{
assert (buttons==0);
assert (buttons>=0);
if (buttons>=256)
throw std::runtime_error ("A message box can't have more than 255 buttons");
int index = literals.addString (message);
@ -773,4 +776,3 @@ namespace Compiler
}
}
}

View file

@ -36,8 +36,8 @@ namespace Compiler
inline Interpreter::Type_Code segment3 (unsigned int c, unsigned int arg0)
{
assert (c<1024);
return 0xc0000000 | (c<<20) | (arg0 & 0xffff);
assert (c<262144);
return 0xc0000000 | (c<<8) | (arg0 & 0xff);
}
inline Interpreter::Type_Code segment4 (unsigned int c, unsigned int arg0,
@ -120,4 +120,3 @@ namespace Compiler
}
#endif

View file

@ -168,13 +168,26 @@ namespace Compiler
mExprParser.parseArguments (arguments, scanner, mCode, true);
}
// for now skip buttons
SkipParser skip (getErrorHandler(), getContext());
scanner.scan (skip);
mName = name;
mButtons = 0;
Generator::message (mCode, mLiterals, name, 0);
mState = EndState;
return false;
mState = MessageButtonState;
return true;
}
if (mState==MessageButtonState || mState==MessageButtonCommaState)
{
Generator::pushString (mCode, mLiterals, name);
mState = MessageButtonState;
++mButtons;
return true;
}
if (mState==BeginState && getContext().isId (name))
{
mState = PotentialExplicitState;
mExplicit = toLower (name);
return true;
}
if (mState==BeginState && mAllowExpression)
@ -200,13 +213,6 @@ namespace Compiler
}
}
if (mState==BeginState && getContext().isId (name))
{
mState = PotentialExplicitState;
mExplicit = toLower (name);
return true;
}
return Parser::parseName (name, loc, scanner);
}
@ -236,9 +242,9 @@ namespace Compiler
if (extensions->isInstruction (keyword, argumentType, mState==ExplicitState))
{
mExprParser.parseArguments (argumentType, scanner, mCode, true);
int optionals = mExprParser.parseArguments (argumentType, scanner, mCode, true);
extensions->generateInstructionCode (keyword, mCode, mLiterals, mExplicit);
extensions->generateInstructionCode (keyword, mCode, mLiterals, mExplicit, optionals);
mState = EndState;
return true;
}
@ -360,6 +366,18 @@ namespace Compiler
return true;
}
if (code==Scanner::S_newline && mState==MessageButtonState)
{
Generator::message (mCode, mLiterals, mName, mButtons);
return false;
}
if (code==Scanner::S_comma && mState==MessageButtonState)
{
mState = MessageButtonCommaState;
return true;
}
if (mAllowExpression && mState==BeginState &&
(code==Scanner::S_open || code==Scanner::S_minus))
{
@ -378,4 +396,3 @@ namespace Compiler
mExplicit.clear();
}
}

View file

@ -22,7 +22,7 @@ namespace Compiler
BeginState,
ShortState, LongState, FloatState,
SetState, SetLocalVarState, SetGlobalVarState,
MessageState, MessageCommaState,
MessageState, MessageCommaState, MessageButtonState, MessageButtonCommaState,
EndState,
PotentialExplicitState, ExplicitState
};
@ -32,6 +32,7 @@ namespace Compiler
std::vector<Interpreter::Type_Code>& mCode;
State mState;
std::string mName;
int mButtons;
std::string mExplicit;
char mType;
ExprParser mExprParser;

View file

@ -65,7 +65,7 @@ namespace Compiler
}
Parser::Parser (ErrorHandler& errorHandler, Context& context)
: mErrorHandler (errorHandler), mContext (context)
: mErrorHandler (errorHandler), mContext (context), mOptional (false), mEmpty (true)
{}
// destructor
@ -79,7 +79,9 @@ namespace Compiler
bool Parser::parseInt (int value, const TokenLoc& loc, Scanner& scanner)
{
if (!(mOptional && mEmpty))
reportSeriousError ("Unexpected numeric value", loc);
return false;
}
@ -90,7 +92,9 @@ namespace Compiler
bool Parser::parseFloat (float value, const TokenLoc& loc, Scanner& scanner)
{
if (!(mOptional && mEmpty))
reportSeriousError ("Unexpected floating point value", loc);
return false;
}
@ -102,7 +106,9 @@ namespace Compiler
bool Parser::parseName (const std::string& name, const TokenLoc& loc,
Scanner& scanner)
{
if (!(mOptional && mEmpty))
reportSeriousError ("Unexpected name", loc);
return false;
}
@ -113,7 +119,9 @@ namespace Compiler
bool Parser::parseKeyword (int keyword, const TokenLoc& loc, Scanner& scanner)
{
if (!(mOptional && mEmpty))
reportSeriousError ("Unexpected keyword", loc);
return false;
}
@ -124,7 +132,9 @@ namespace Compiler
bool Parser::parseSpecial (int code, const TokenLoc& loc, Scanner& scanner)
{
if (!(mOptional && mEmpty))
reportSeriousError ("Unexpected special token", loc);
return false;
}
@ -136,5 +146,25 @@ namespace Compiler
{
reportEOF();
}
void Parser::reset()
{
mOptional = false;
mEmpty = true;
}
void Parser::setOptional (bool optional)
{
mOptional = optional;
}
void Parser::start()
{
mEmpty = false;
}
bool Parser::isEmpty() const
{
return mEmpty;
}
}

View file

@ -18,6 +18,8 @@ namespace Compiler
{
ErrorHandler& mErrorHandler;
Context& mContext;
bool mOptional;
bool mEmpty;
protected:
@ -84,6 +86,19 @@ namespace Compiler
///< Handle EOF token.
///
/// - Default-implementation: Report an error.
virtual void reset();
///< Reset parser to clean state.
void setOptional (bool optional);
///< Optional mode: If nothign has been parsed yet and an unexpected token is delivered, stop
/// parsing without raising an exception (after a reset the parser is in non-optional mode).
void start();
///< Mark parser as non-empty (at least one token has been parser).
bool isEmpty() const;
///< Has anything been parsed?
};
}

View file

@ -20,6 +20,7 @@ namespace Compiler
{
if (mState==StartState || mState==CommaState)
{
start();
if (mSmashCase)
Generator::pushString (mCode, mLiterals, toLower (name));
else
@ -52,6 +53,7 @@ namespace Compiler
mState = StartState;
mCode.clear();
mSmashCase = false;
Parser::reset();
}
void StringParser::smashCase()
@ -59,4 +61,3 @@ namespace Compiler
mSmashCase = true;
}
}

View file

@ -19,7 +19,7 @@ Code bit-patterns:
00ccccccAAAAAAAAAAAAAAAAAAAAAAAA segment 0: 64 opcodes, 1 24-bit argument
01ccccccAAAAAAAAAAAABBBBBBBBBBBB segment 1: 64 opcodes, 2 12-bit arguments
10ccccccccccAAAAAAAAAAAAAAAAAAAA segment 2: 1024 opcodes, 1 20-bit argument
110000ccccccccccAAAAAAAAAAAAAAAA segment 3: 1024 opcodes, 1 16-bit argument
110000ccccccccccccccccccAAAAAAAA segment 3: 262144 opcodes, 1 8-bit argument
110001ccccccccccAAAAAAAABBBBBBBB segment 4: 1024 opcodes, 2 8-bit arguments
110010cccccccccccccccccccccccccc segment 5: 67108864 opcodes, no arguments
other bit-patterns reserved
@ -31,8 +31,8 @@ B: argument 1
Segment 0:
op 0: push arg0
op 1: move pv ahead by arg0
op 2: move pv back by arg0
op 1: move pc ahead by arg0
op 2: move pc back by arg0
opcodes 3-31 unused
opcodes 32-63 reserved for extensions
@ -50,8 +50,8 @@ op 0: show message box with message string literal index in stack[0];
additional arguments (if any) in stack[arg0+n]..stack[arg0+1];
n is determined according to the message string
all arguments are removed from stack
opcodes 1-511 unused
opcodes 512-1023 reserved for extensions
opcodes 1-131071 unused
opcodes 131072-262143 reserved for extensions
Segment 4:
opcodes 0-511 unused
@ -119,4 +119,3 @@ op 57: explicit reference = stack[0]; pop;
replace stack[0] with distance between explicit reference and a reference of ID stack[0]
opcodes 58-33554431 unused
opcodes 33554432-67108863 reserved for extensions

View file

@ -69,8 +69,8 @@ namespace Interpreter
{
case 0x30:
{
int opcode = (code>>16) & 0x3ff;
unsigned int arg0 = code & 0xffff;
int opcode = (code>>8) & 0x3ffff;
unsigned int arg0 = code & 0xff;
std::map<int, Opcode1 *>::iterator iter = mSegment3.find (opcode);

View file

@ -6,6 +6,7 @@
#include <vector>
#include <string>
#include <sstream>
#include <algorithm>
#include "opcodes.hpp"
#include "runtime.hpp"
@ -18,14 +19,23 @@ namespace Interpreter
virtual void execute (Runtime& runtime, unsigned int arg0)
{
if (arg0!=0)
throw std::logic_error ("message box buttons not implemented yet");
// message
int index = runtime[0].mInteger;
runtime.pop();
std::string message = runtime.getStringLiteral (index);
// buttons
std::vector<std::string> buttons;
for (std::size_t i=0; i<arg0; ++i)
{
int index = runtime[0].mInteger;
runtime.pop();
buttons.push_back (runtime.getStringLiteral (index));
}
std::reverse (buttons.begin(), buttons.end());
// additional parameters
std::string formattedMessage;
@ -82,9 +92,6 @@ namespace Interpreter
}
}
// buttons (not implemented)
std::vector<std::string> buttons;
runtime.getContext().messageBox (formattedMessage, buttons);
}
};
@ -206,4 +213,3 @@ namespace Interpreter
}
#endif