mirror of
				https://github.com/OpenMW/openmw.git
				synced 2025-10-26 14:56:39 +00:00 
			
		
		
		
	Merge branch 'xdoty' into script
This commit is contained in:
		
						commit
						0795730a19
					
				
					 19 changed files with 578 additions and 72 deletions
				
			
		|  | @ -5,6 +5,8 @@ | ||||||
| 
 | 
 | ||||||
| #include "../mwworld/world.hpp" | #include "../mwworld/world.hpp" | ||||||
| 
 | 
 | ||||||
|  | #include "scriptmanager.hpp" | ||||||
|  | 
 | ||||||
| namespace MWScript | namespace MWScript | ||||||
| { | { | ||||||
|     CompilerContext::CompilerContext (Type type) |     CompilerContext::CompilerContext (Type type) | ||||||
|  | @ -21,6 +23,18 @@ namespace MWScript | ||||||
|         return MWBase::Environment::get().getWorld()->getGlobalVariableType (name); |         return MWBase::Environment::get().getWorld()->getGlobalVariableType (name); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|  |     char CompilerContext::getMemberType (const std::string& name, const std::string& id) const | ||||||
|  |     { | ||||||
|  |         MWWorld::Ptr ptr = MWBase::Environment::get().getWorld()->getPtr (id, false); | ||||||
|  | 
 | ||||||
|  |         std::string script = MWWorld::Class::get (ptr).getScript (ptr); | ||||||
|  | 
 | ||||||
|  |         if (script.empty()) | ||||||
|  |             return ' '; | ||||||
|  | 
 | ||||||
|  |         return MWBase::Environment::get().getScriptManager()->getLocals (script).getType (name); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|     bool CompilerContext::isId (const std::string& name) const |     bool CompilerContext::isId (const std::string& name) const | ||||||
|     { |     { | ||||||
|         return |         return | ||||||
|  |  | ||||||
|  | @ -30,6 +30,9 @@ namespace MWScript | ||||||
|             /// 'l: long, 's': short, 'f': float, ' ': does not exist.
 |             /// 'l: long, 's': short, 'f': float, ' ': does not exist.
 | ||||||
|             virtual char getGlobalType (const std::string& name) const; |             virtual char getGlobalType (const std::string& name) const; | ||||||
| 
 | 
 | ||||||
|  |             virtual char getMemberType (const std::string& name, const std::string& id) const; | ||||||
|  |             ///< 'l: long, 's': short, 'f': float, ' ': does not exist.
 | ||||||
|  | 
 | ||||||
|             virtual bool isId (const std::string& name) const; |             virtual bool isId (const std::string& name) const; | ||||||
|             ///< Does \a name match an ID, that can be referenced?
 |             ///< Does \a name match an ID, that can be referenced?
 | ||||||
|     }; |     }; | ||||||
|  |  | ||||||
|  | @ -270,6 +270,84 @@ namespace MWScript | ||||||
|         MWBase::Environment::get().getWorld()->disable (ref); |         MWBase::Environment::get().getWorld()->disable (ref); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|  |     int InterpreterContext::getMemberShort (const std::string& id, const std::string& name) const | ||||||
|  |     { | ||||||
|  |         const MWWorld::Ptr ptr = getReference (id, false); | ||||||
|  | 
 | ||||||
|  |         std::string scriptId = MWWorld::Class::get (ptr).getScript (ptr); | ||||||
|  | 
 | ||||||
|  |         int index = MWBase::Environment::get().getScriptManager()->getLocalIndex (scriptId, name, 's'); | ||||||
|  | 
 | ||||||
|  |         ptr.getRefData().setLocals ( | ||||||
|  |             *MWBase::Environment::get().getWorld()->getStore().scripts.find (scriptId)); | ||||||
|  |         return ptr.getRefData().getLocals().mShorts[index]; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     int InterpreterContext::getMemberLong (const std::string& id, const std::string& name) const | ||||||
|  |     { | ||||||
|  |         const MWWorld::Ptr ptr = getReference (id, false); | ||||||
|  | 
 | ||||||
|  |         std::string scriptId = MWWorld::Class::get (ptr).getScript (ptr); | ||||||
|  | 
 | ||||||
|  |         int index = MWBase::Environment::get().getScriptManager()->getLocalIndex (scriptId, name, 'l'); | ||||||
|  | 
 | ||||||
|  |         ptr.getRefData().setLocals ( | ||||||
|  |             *MWBase::Environment::get().getWorld()->getStore().scripts.find (scriptId)); | ||||||
|  |         return ptr.getRefData().getLocals().mLongs[index]; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     float InterpreterContext::getMemberFloat (const std::string& id, const std::string& name) const | ||||||
|  |     { | ||||||
|  |         const MWWorld::Ptr ptr = getReference (id, false); | ||||||
|  | 
 | ||||||
|  |         std::string scriptId = MWWorld::Class::get (ptr).getScript (ptr); | ||||||
|  | 
 | ||||||
|  |         int index = MWBase::Environment::get().getScriptManager()->getLocalIndex (scriptId, name, 'f'); | ||||||
|  | 
 | ||||||
|  |         ptr.getRefData().setLocals ( | ||||||
|  |             *MWBase::Environment::get().getWorld()->getStore().scripts.find (scriptId)); | ||||||
|  |         return ptr.getRefData().getLocals().mFloats[index]; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     void InterpreterContext::setMemberShort (const std::string& id, const std::string& name, int value) | ||||||
|  |     { | ||||||
|  |         const MWWorld::Ptr ptr = getReference (id, false); | ||||||
|  | 
 | ||||||
|  |         std::string scriptId = MWWorld::Class::get (ptr).getScript (ptr); | ||||||
|  | 
 | ||||||
|  |         int index = MWBase::Environment::get().getScriptManager()->getLocalIndex (scriptId, name, 's'); | ||||||
|  | 
 | ||||||
|  |         ptr.getRefData().setLocals ( | ||||||
|  |             *MWBase::Environment::get().getWorld()->getStore().scripts.find (scriptId)); | ||||||
|  |         ptr.getRefData().getLocals().mShorts[index] = value; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     void InterpreterContext::setMemberLong (const std::string& id, const std::string& name, int value) | ||||||
|  |     { | ||||||
|  |         const MWWorld::Ptr ptr = getReference (id, false); | ||||||
|  | 
 | ||||||
|  |         std::string scriptId = MWWorld::Class::get (ptr).getScript (ptr); | ||||||
|  | 
 | ||||||
|  |         int index = MWBase::Environment::get().getScriptManager()->getLocalIndex (scriptId, name, 'l'); | ||||||
|  | 
 | ||||||
|  |         ptr.getRefData().setLocals ( | ||||||
|  |             *MWBase::Environment::get().getWorld()->getStore().scripts.find (scriptId)); | ||||||
|  |         ptr.getRefData().getLocals().mLongs[index] = value; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     void InterpreterContext::setMemberFloat (const std::string& id, const std::string& name, float value) | ||||||
|  |     { | ||||||
|  |         const MWWorld::Ptr ptr = getReference (id, false); | ||||||
|  | 
 | ||||||
|  |         std::string scriptId = MWWorld::Class::get (ptr).getScript (ptr); | ||||||
|  | 
 | ||||||
|  |         int index = MWBase::Environment::get().getScriptManager()->getLocalIndex (scriptId, name, 'f'); | ||||||
|  | 
 | ||||||
|  |         ptr.getRefData().setLocals ( | ||||||
|  |             *MWBase::Environment::get().getWorld()->getStore().scripts.find (scriptId)); | ||||||
|  |         ptr.getRefData().getLocals().mFloats[index] = value; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|     MWWorld::Ptr InterpreterContext::getReference() |     MWWorld::Ptr InterpreterContext::getReference() | ||||||
|     { |     { | ||||||
|         return getReference ("", true); |         return getReference ("", true); | ||||||
|  |  | ||||||
|  | @ -107,6 +107,18 @@ namespace MWScript | ||||||
| 
 | 
 | ||||||
|             virtual void disable (const std::string& id = ""); |             virtual void disable (const std::string& id = ""); | ||||||
| 
 | 
 | ||||||
|  |             virtual int getMemberShort (const std::string& id, const std::string& name) const; | ||||||
|  | 
 | ||||||
|  |             virtual int getMemberLong (const std::string& id, const std::string& name) const; | ||||||
|  | 
 | ||||||
|  |             virtual float getMemberFloat (const std::string& id, const std::string& name) const; | ||||||
|  | 
 | ||||||
|  |             virtual void setMemberShort (const std::string& id, const std::string& name, int value); | ||||||
|  | 
 | ||||||
|  |             virtual void setMemberLong (const std::string& id, const std::string& name, int value); | ||||||
|  | 
 | ||||||
|  |             virtual void setMemberFloat (const std::string& id, const std::string& name, float value); | ||||||
|  | 
 | ||||||
|             MWWorld::Ptr getReference(); |             MWWorld::Ptr getReference(); | ||||||
|             ///< Reference, that the script is running from (can be empty)
 |             ///< Reference, that the script is running from (can be empty)
 | ||||||
|     }; |     }; | ||||||
|  |  | ||||||
|  | @ -11,6 +11,7 @@ | ||||||
| 
 | 
 | ||||||
| #include <components/compiler/scanner.hpp> | #include <components/compiler/scanner.hpp> | ||||||
| #include <components/compiler/context.hpp> | #include <components/compiler/context.hpp> | ||||||
|  | #include <components/compiler/exception.hpp> | ||||||
| 
 | 
 | ||||||
| #include "extensions.hpp" | #include "extensions.hpp" | ||||||
| 
 | 
 | ||||||
|  | @ -46,8 +47,14 @@ namespace MWScript | ||||||
|                 if (!mErrorHandler.isGood()) |                 if (!mErrorHandler.isGood()) | ||||||
|                     Success = false; |                     Success = false; | ||||||
|             } |             } | ||||||
|             catch (...) |             catch (const Compiler::SourceException&) | ||||||
|             { |             { | ||||||
|  |                 // error has already been reported via error handler
 | ||||||
|  |                 Success = false; | ||||||
|  |             } | ||||||
|  |             catch (const std::exception& error) | ||||||
|  |             { | ||||||
|  |                 std::cerr << "An exception has been thrown: " << error.what() << std::endl; | ||||||
|                 Success = false; |                 Success = false; | ||||||
|             } |             } | ||||||
| 
 | 
 | ||||||
|  | @ -140,6 +147,9 @@ namespace MWScript | ||||||
|         { |         { | ||||||
|             if (!compile (name)) |             if (!compile (name)) | ||||||
|             { |             { | ||||||
|  |                 /// \todo Handle case of cyclic member variable access. Currently this could look up
 | ||||||
|  |                 /// the whole application in an endless recursion.
 | ||||||
|  | 
 | ||||||
|                 // failed -> ignore script from now on.
 |                 // failed -> ignore script from now on.
 | ||||||
|                 std::vector<Interpreter::Type_Code> empty; |                 std::vector<Interpreter::Type_Code> empty; | ||||||
|                 mScripts.insert (std::make_pair (name, std::make_pair (empty, Compiler::Locals()))); |                 mScripts.insert (std::make_pair (name, std::make_pair (empty, Compiler::Locals()))); | ||||||
|  | @ -156,4 +166,43 @@ namespace MWScript | ||||||
|     { |     { | ||||||
|         return mGlobalScripts; |         return mGlobalScripts; | ||||||
|     } |     } | ||||||
|  | 
 | ||||||
|  |     int ScriptManager::getLocalIndex (const std::string& scriptId, const std::string& variable, | ||||||
|  |         char type) | ||||||
|  |     { | ||||||
|  |         const ESM::Script *script = mStore.scripts.find (scriptId); | ||||||
|  | 
 | ||||||
|  |         int offset = 0; | ||||||
|  |         int size = 0; | ||||||
|  | 
 | ||||||
|  |         switch (type) | ||||||
|  |         { | ||||||
|  |             case 's': | ||||||
|  | 
 | ||||||
|  |                 offset = 0; | ||||||
|  |                 size = script->data.numShorts; | ||||||
|  |                 break; | ||||||
|  | 
 | ||||||
|  |             case 'l': | ||||||
|  | 
 | ||||||
|  |                 offset = script->data.numShorts; | ||||||
|  |                 size = script->data.numLongs; | ||||||
|  |                 break; | ||||||
|  | 
 | ||||||
|  |             case 'f': | ||||||
|  | 
 | ||||||
|  |                 offset = script->data.numShorts+script->data.numLongs; | ||||||
|  |                 size = script->data.numFloats; | ||||||
|  | 
 | ||||||
|  |             default: | ||||||
|  | 
 | ||||||
|  |                 throw std::runtime_error ("invalid variable type"); | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         for (int i=0; i<size; ++i) | ||||||
|  |             if (script->varNames.at (i+offset)==variable) | ||||||
|  |                 return i; | ||||||
|  | 
 | ||||||
|  |         throw std::runtime_error ("unable to access local variable " + variable + " of " + scriptId); | ||||||
|  |     } | ||||||
| } | } | ||||||
|  |  | ||||||
|  | @ -67,6 +67,10 @@ namespace MWScript | ||||||
|             ///< Return locals for script \a name.
 |             ///< Return locals for script \a name.
 | ||||||
| 
 | 
 | ||||||
|             GlobalScripts& getGlobalScripts(); |             GlobalScripts& getGlobalScripts(); | ||||||
|  | 
 | ||||||
|  |             int getLocalIndex (const std::string& scriptId, const std::string& variable, char type); | ||||||
|  |             ///< Return index of the variable of the given name and type in the given script. Will
 | ||||||
|  |             /// throw an exception, if there is no such script or variable or the type does not match.
 | ||||||
|     }; |     }; | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -33,10 +33,12 @@ namespace Compiler | ||||||
|             virtual char getGlobalType (const std::string& name) const = 0; |             virtual char getGlobalType (const std::string& name) const = 0; | ||||||
|             ///< 'l: long, 's': short, 'f': float, ' ': does not exist.
 |             ///< 'l: long, 's': short, 'f': float, ' ': does not exist.
 | ||||||
| 
 | 
 | ||||||
|  |             virtual char getMemberType (const std::string& name, const std::string& id) const = 0; | ||||||
|  |             ///< 'l: long, 's': short, 'f': float, ' ': does not exist.
 | ||||||
|  | 
 | ||||||
|             virtual bool isId (const std::string& name) const = 0; |             virtual bool isId (const std::string& name) const = 0; | ||||||
|             ///< Does \a name match an ID, that can be referenced?
 |             ///< Does \a name match an ID, that can be referenced?
 | ||||||
|     }; |     }; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| #endif | #endif | ||||||
| 
 |  | ||||||
|  |  | ||||||
|  | @ -195,10 +195,31 @@ namespace Compiler | ||||||
|         return parseArguments (arguments, scanner, mCode); |         return parseArguments (arguments, scanner, mCode); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|  |     bool ExprParser::handleMemberAccess (const std::string& name) | ||||||
|  |     { | ||||||
|  |         mMemberOp = false; | ||||||
|  | 
 | ||||||
|  |         std::string name2 = toLower (name); | ||||||
|  |         std::string id = toLower (mExplicit); | ||||||
|  | 
 | ||||||
|  |         char type = getContext().getMemberType (name2, id); | ||||||
|  | 
 | ||||||
|  |         if (type!=' ') | ||||||
|  |         { | ||||||
|  |             Generator::fetchMember (mCode, mLiterals, type, name2, id); | ||||||
|  |             mNextOperand = false; | ||||||
|  |             mExplicit.clear(); | ||||||
|  |             mOperands.push_back (type=='f' ? 'f' : 'l'); | ||||||
|  |             return true; | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         return false; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|     ExprParser::ExprParser (ErrorHandler& errorHandler, Context& context, Locals& locals, |     ExprParser::ExprParser (ErrorHandler& errorHandler, Context& context, Locals& locals, | ||||||
|         Literals& literals, bool argument) |         Literals& literals, bool argument) | ||||||
|     : Parser (errorHandler, context), mLocals (locals), mLiterals (literals), |     : Parser (errorHandler, context), mLocals (locals), mLiterals (literals), | ||||||
|       mNextOperand (true), mFirst (true), mArgument (argument) |       mNextOperand (true), mFirst (true), mArgument (argument), mRefOp (false), mMemberOp (false) | ||||||
|     {} |     {} | ||||||
| 
 | 
 | ||||||
|     bool ExprParser::parseInt (int value, const TokenLoc& loc, Scanner& scanner) |     bool ExprParser::parseInt (int value, const TokenLoc& loc, Scanner& scanner) | ||||||
|  | @ -251,7 +272,12 @@ namespace Compiler | ||||||
|         Scanner& scanner) |         Scanner& scanner) | ||||||
|     { |     { | ||||||
|         if (!mExplicit.empty()) |         if (!mExplicit.empty()) | ||||||
|  |         { | ||||||
|  |             if (mMemberOp && handleMemberAccess (name)) | ||||||
|  |                 return true; | ||||||
|  | 
 | ||||||
|             return Parser::parseName (name, loc, scanner); |             return Parser::parseName (name, loc, scanner); | ||||||
|  |         } | ||||||
| 
 | 
 | ||||||
|         mFirst = false; |         mFirst = false; | ||||||
| 
 | 
 | ||||||
|  | @ -281,7 +307,7 @@ namespace Compiler | ||||||
|                 return true; |                 return true; | ||||||
|             } |             } | ||||||
| 
 | 
 | ||||||
|             if (mExplicit.empty() && getContext().isId (name)) |             if (mExplicit.empty() && getContext().isId (name2)) | ||||||
|             { |             { | ||||||
|                 mExplicit = name; |                 mExplicit = name; | ||||||
|                 return true; |                 return true; | ||||||
|  | @ -497,6 +523,12 @@ namespace Compiler | ||||||
|                 return true; |                 return true; | ||||||
|             } |             } | ||||||
| 
 | 
 | ||||||
|  |             if (!mMemberOp && code==Scanner::S_member) | ||||||
|  |             { | ||||||
|  |                 mMemberOp = true; | ||||||
|  |                 return true; | ||||||
|  |             } | ||||||
|  | 
 | ||||||
|             return Parser::parseSpecial (code, loc, scanner); |             return Parser::parseSpecial (code, loc, scanner); | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|  | @ -609,6 +641,7 @@ namespace Compiler | ||||||
|         mFirst = true; |         mFirst = true; | ||||||
|         mExplicit.clear(); |         mExplicit.clear(); | ||||||
|         mRefOp = false; |         mRefOp = false; | ||||||
|  |         mMemberOp = false; | ||||||
|         Parser::reset(); |         Parser::reset(); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -26,6 +26,7 @@ namespace Compiler | ||||||
|             bool mArgument; |             bool mArgument; | ||||||
|             std::string mExplicit; |             std::string mExplicit; | ||||||
|             bool mRefOp; |             bool mRefOp; | ||||||
|  |             bool mMemberOp; | ||||||
| 
 | 
 | ||||||
|             int getPriority (char op) const; |             int getPriority (char op) const; | ||||||
| 
 | 
 | ||||||
|  | @ -53,6 +54,8 @@ namespace Compiler | ||||||
| 
 | 
 | ||||||
|             int parseArguments (const std::string& arguments, Scanner& scanner); |             int parseArguments (const std::string& arguments, Scanner& scanner); | ||||||
| 
 | 
 | ||||||
|  |             bool handleMemberAccess (const std::string& name); | ||||||
|  | 
 | ||||||
|         public: |         public: | ||||||
| 
 | 
 | ||||||
|             ExprParser (ErrorHandler& errorHandler, Context& context, Locals& locals, |             ExprParser (ErrorHandler& errorHandler, Context& context, Locals& locals, | ||||||
|  |  | ||||||
|  | @ -260,6 +260,36 @@ namespace | ||||||
|         code.push_back (Compiler::Generator::segment5 (44)); |         code.push_back (Compiler::Generator::segment5 (44)); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|  |     void opStoreMemberShort (Compiler::Generator::CodeContainer& code) | ||||||
|  |     { | ||||||
|  |         code.push_back (Compiler::Generator::segment5 (59)); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     void opStoreMemberLong (Compiler::Generator::CodeContainer& code) | ||||||
|  |     { | ||||||
|  |         code.push_back (Compiler::Generator::segment5 (60)); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     void opStoreMemberFloat (Compiler::Generator::CodeContainer& code) | ||||||
|  |     { | ||||||
|  |         code.push_back (Compiler::Generator::segment5 (61)); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     void opFetchMemberShort (Compiler::Generator::CodeContainer& code) | ||||||
|  |     { | ||||||
|  |         code.push_back (Compiler::Generator::segment5 (62)); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     void opFetchMemberLong (Compiler::Generator::CodeContainer& code) | ||||||
|  |     { | ||||||
|  |         code.push_back (Compiler::Generator::segment5 (63)); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     void opFetchMemberFloat (Compiler::Generator::CodeContainer& code) | ||||||
|  |     { | ||||||
|  |         code.push_back (Compiler::Generator::segment5 (64)); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|     void opRandom (Compiler::Generator::CodeContainer& code) |     void opRandom (Compiler::Generator::CodeContainer& code) | ||||||
|     { |     { | ||||||
|         code.push_back (Compiler::Generator::segment5 (45)); |         code.push_back (Compiler::Generator::segment5 (45)); | ||||||
|  | @ -644,7 +674,7 @@ namespace Compiler | ||||||
| 
 | 
 | ||||||
|             if (localType!=valueType) |             if (localType!=valueType) | ||||||
|             { |             { | ||||||
|                 if (localType=='f' && valueType=='l') |                 if (localType=='f' && (valueType=='l' || valueType=='s')) | ||||||
|                 { |                 { | ||||||
|                     opIntToFloat (code); |                     opIntToFloat (code); | ||||||
|                 } |                 } | ||||||
|  | @ -707,6 +737,88 @@ namespace Compiler | ||||||
|             } |             } | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|  |         void assignToMember (CodeContainer& code, Literals& literals, char localType, | ||||||
|  |             const std::string& name, const std::string& id, const CodeContainer& value, char valueType) | ||||||
|  |         { | ||||||
|  |             int index = literals.addString (name); | ||||||
|  | 
 | ||||||
|  |             opPushInt (code, index); | ||||||
|  | 
 | ||||||
|  |             index = literals.addString (id); | ||||||
|  | 
 | ||||||
|  |             opPushInt (code, index); | ||||||
|  | 
 | ||||||
|  |             std::copy (value.begin(), value.end(), std::back_inserter (code)); | ||||||
|  | 
 | ||||||
|  |             if (localType!=valueType) | ||||||
|  |             { | ||||||
|  |                 if (localType=='f' && (valueType=='l' || valueType=='s')) | ||||||
|  |                 { | ||||||
|  |                     opIntToFloat (code); | ||||||
|  |                 } | ||||||
|  |                 else if ((localType=='l' || localType=='s') && valueType=='f') | ||||||
|  |                 { | ||||||
|  |                     opFloatToInt (code); | ||||||
|  |                 } | ||||||
|  |             } | ||||||
|  | 
 | ||||||
|  |             switch (localType) | ||||||
|  |             { | ||||||
|  |                 case 'f': | ||||||
|  | 
 | ||||||
|  |                     opStoreMemberFloat (code); | ||||||
|  |                     break; | ||||||
|  | 
 | ||||||
|  |                 case 's': | ||||||
|  | 
 | ||||||
|  |                     opStoreMemberShort (code); | ||||||
|  |                     break; | ||||||
|  | 
 | ||||||
|  |                 case 'l': | ||||||
|  | 
 | ||||||
|  |                     opStoreMemberLong (code); | ||||||
|  |                     break; | ||||||
|  | 
 | ||||||
|  |                 default: | ||||||
|  | 
 | ||||||
|  |                     assert (0); | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         void fetchMember (CodeContainer& code, Literals& literals, char localType, | ||||||
|  |             const std::string& name, const std::string& id) | ||||||
|  |         { | ||||||
|  |             int index = literals.addString (name); | ||||||
|  | 
 | ||||||
|  |             opPushInt (code, index); | ||||||
|  | 
 | ||||||
|  |             index = literals.addString (id); | ||||||
|  | 
 | ||||||
|  |             opPushInt (code, index); | ||||||
|  | 
 | ||||||
|  |             switch (localType) | ||||||
|  |             { | ||||||
|  |                 case 'f': | ||||||
|  | 
 | ||||||
|  |                     opFetchMemberFloat (code); | ||||||
|  |                     break; | ||||||
|  | 
 | ||||||
|  |                 case 's': | ||||||
|  | 
 | ||||||
|  |                     opFetchMemberShort (code); | ||||||
|  |                     break; | ||||||
|  | 
 | ||||||
|  |                 case 'l': | ||||||
|  | 
 | ||||||
|  |                     opFetchMemberLong (code); | ||||||
|  |                     break; | ||||||
|  | 
 | ||||||
|  |                 default: | ||||||
|  | 
 | ||||||
|  |                     assert (0); | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|         void random (CodeContainer& code) |         void random (CodeContainer& code) | ||||||
|         { |         { | ||||||
|             opRandom (code); |             opRandom (code); | ||||||
|  |  | ||||||
|  | @ -101,6 +101,12 @@ namespace Compiler | ||||||
|         void fetchGlobal (CodeContainer& code, Literals& literals, char localType, |         void fetchGlobal (CodeContainer& code, Literals& literals, char localType, | ||||||
|             const std::string& name); |             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); | ||||||
|  | 
 | ||||||
|  |         void fetchMember (CodeContainer& code, Literals& literals, char memberType, | ||||||
|  |             const std::string& name, const std::string& id); | ||||||
|  | 
 | ||||||
|         void random (CodeContainer& code); |         void random (CodeContainer& code); | ||||||
| 
 | 
 | ||||||
|         void scriptRunning (CodeContainer& code); |         void scriptRunning (CodeContainer& code); | ||||||
|  |  | ||||||
|  | @ -18,6 +18,9 @@ namespace Compiler | ||||||
|         if (!mExplicit.empty()) |         if (!mExplicit.empty()) | ||||||
|         { |         { | ||||||
|             mExprParser.parseName (mExplicit, loc, scanner); |             mExprParser.parseName (mExplicit, loc, scanner); | ||||||
|  |             if (mState==MemberState) | ||||||
|  |                 mExprParser.parseSpecial (Scanner::S_member, loc, scanner); | ||||||
|  |             else | ||||||
|                 mExprParser.parseSpecial (Scanner::S_ref, loc, scanner); |                 mExprParser.parseSpecial (Scanner::S_ref, loc, scanner); | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|  | @ -110,12 +113,13 @@ namespace Compiler | ||||||
|         if (mState==SetState) |         if (mState==SetState) | ||||||
|         { |         { | ||||||
|             std::string name2 = toLower (name); |             std::string name2 = toLower (name); | ||||||
|  |             mName = name2; | ||||||
| 
 | 
 | ||||||
|             // local variable?
 |             // local variable?
 | ||||||
|             char type = mLocals.getType (name2); |             char type = mLocals.getType (name2); | ||||||
|             if (type!=' ') |             if (type!=' ') | ||||||
|             { |             { | ||||||
|                 mName = name2; |                 mType = type; | ||||||
|                 mState = SetLocalVarState; |                 mState = SetLocalVarState; | ||||||
|                 return true; |                 return true; | ||||||
|             } |             } | ||||||
|  | @ -123,12 +127,27 @@ namespace Compiler | ||||||
|             type = getContext().getGlobalType (name2); |             type = getContext().getGlobalType (name2); | ||||||
|             if (type!=' ') |             if (type!=' ') | ||||||
|             { |             { | ||||||
|                 mName = name2; |  | ||||||
|                 mType = type; |                 mType = type; | ||||||
|                 mState = SetGlobalVarState; |                 mState = SetGlobalVarState; | ||||||
|                 return true; |                 return true; | ||||||
|             } |             } | ||||||
| 
 | 
 | ||||||
|  |             mState = SetPotentialMemberVarState; | ||||||
|  |             return true; | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         if (mState==SetMemberVarState) | ||||||
|  |         { | ||||||
|  |             mMemberName = toLower (name); | ||||||
|  |             char type = getContext().getMemberType (mMemberName, mName); | ||||||
|  | 
 | ||||||
|  |             if (type!=' ') | ||||||
|  |             { | ||||||
|  |                 mState = SetMemberVarState2; | ||||||
|  |                 mType = type; | ||||||
|  |                 return true; | ||||||
|  |             } | ||||||
|  | 
 | ||||||
|             getErrorHandler().error ("unknown variable", loc); |             getErrorHandler().error ("unknown variable", loc); | ||||||
|             SkipParser skip (getErrorHandler(), getContext()); |             SkipParser skip (getErrorHandler(), getContext()); | ||||||
|             scanner.scan (skip); |             scanner.scan (skip); | ||||||
|  | @ -256,6 +275,7 @@ namespace Compiler | ||||||
|                 { |                 { | ||||||
|                     scanner.putbackKeyword (keyword, loc); |                     scanner.putbackKeyword (keyword, loc); | ||||||
|                     parseExpression (scanner, loc); |                     parseExpression (scanner, loc); | ||||||
|  |                     mState = EndState; | ||||||
|                     return true; |                     return true; | ||||||
|                 } |                 } | ||||||
| 
 | 
 | ||||||
|  | @ -269,6 +289,7 @@ namespace Compiler | ||||||
|                     { |                     { | ||||||
|                         scanner.putbackKeyword (keyword, loc); |                         scanner.putbackKeyword (keyword, loc); | ||||||
|                         parseExpression (scanner, loc); |                         parseExpression (scanner, loc); | ||||||
|  |                         mState = EndState; | ||||||
|                         return true; |                         return true; | ||||||
|                     } |                     } | ||||||
|                 } |                 } | ||||||
|  | @ -333,6 +354,19 @@ namespace Compiler | ||||||
|             mState = EndState; |             mState = EndState; | ||||||
|             return true; |             return true; | ||||||
|         } |         } | ||||||
|  |         else if (mState==SetMemberVarState2 && keyword==Scanner::K_to) | ||||||
|  |         { | ||||||
|  |             mExprParser.reset(); | ||||||
|  |             scanner.scan (mExprParser); | ||||||
|  | 
 | ||||||
|  |             std::vector<Interpreter::Type_Code> code; | ||||||
|  |             char type = mExprParser.append (code); | ||||||
|  | 
 | ||||||
|  |             Generator::assignToMember (mCode, mLiterals, mType, mMemberName, mName, code, type); | ||||||
|  | 
 | ||||||
|  |             mState = EndState; | ||||||
|  |             return true; | ||||||
|  |         } | ||||||
| 
 | 
 | ||||||
|         if (mAllowExpression) |         if (mAllowExpression) | ||||||
|         { |         { | ||||||
|  | @ -342,6 +376,7 @@ namespace Compiler | ||||||
|             { |             { | ||||||
|                 scanner.putbackKeyword (keyword, loc); |                 scanner.putbackKeyword (keyword, loc); | ||||||
|                 parseExpression (scanner, loc); |                 parseExpression (scanner, loc); | ||||||
|  |                 mState = EndState; | ||||||
|                 return true; |                 return true; | ||||||
|             } |             } | ||||||
|         } |         } | ||||||
|  | @ -366,6 +401,14 @@ namespace Compiler | ||||||
|             return true; |             return true; | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|  |         if (code==Scanner::S_member && mState==PotentialExplicitState) | ||||||
|  |         { | ||||||
|  |             mState = MemberState; | ||||||
|  |             parseExpression (scanner, loc); | ||||||
|  |             mState = EndState; | ||||||
|  |             return true; | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|         if (code==Scanner::S_newline && mState==MessageButtonState) |         if (code==Scanner::S_newline && mState==MessageButtonState) | ||||||
|         { |         { | ||||||
|             Generator::message (mCode, mLiterals, mName, mButtons); |             Generator::message (mCode, mLiterals, mName, mButtons); | ||||||
|  | @ -378,11 +421,18 @@ namespace Compiler | ||||||
|             return true; |             return true; | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|  |         if (code==Scanner::S_member && mState==SetPotentialMemberVarState) | ||||||
|  |         { | ||||||
|  |             mState = SetMemberVarState; | ||||||
|  |             return true; | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|         if (mAllowExpression && mState==BeginState && |         if (mAllowExpression && mState==BeginState && | ||||||
|             (code==Scanner::S_open || code==Scanner::S_minus)) |             (code==Scanner::S_open || code==Scanner::S_minus)) | ||||||
|         { |         { | ||||||
|             scanner.putbackSpecial (code, loc); |             scanner.putbackSpecial (code, loc); | ||||||
|             parseExpression (scanner, loc); |             parseExpression (scanner, loc); | ||||||
|  |             mState = EndState; | ||||||
|             return true; |             return true; | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -21,10 +21,11 @@ namespace Compiler | ||||||
|             { |             { | ||||||
|                 BeginState, |                 BeginState, | ||||||
|                 ShortState, LongState, FloatState, |                 ShortState, LongState, FloatState, | ||||||
|                 SetState, SetLocalVarState, SetGlobalVarState, |                 SetState, SetLocalVarState, SetGlobalVarState, SetPotentialMemberVarState, | ||||||
|  |                 SetMemberVarState, SetMemberVarState2, | ||||||
|                 MessageState, MessageCommaState, MessageButtonState, MessageButtonCommaState, |                 MessageState, MessageCommaState, MessageButtonState, MessageButtonCommaState, | ||||||
|                 EndState, |                 EndState, | ||||||
|                 PotentialExplicitState, ExplicitState |                 PotentialExplicitState, ExplicitState, MemberState | ||||||
|             }; |             }; | ||||||
| 
 | 
 | ||||||
|             Locals& mLocals; |             Locals& mLocals; | ||||||
|  | @ -32,6 +33,7 @@ namespace Compiler | ||||||
|             std::vector<Interpreter::Type_Code>& mCode; |             std::vector<Interpreter::Type_Code>& mCode; | ||||||
|             State mState; |             State mState; | ||||||
|             std::string mName; |             std::string mName; | ||||||
|  |             std::string mMemberName; | ||||||
|             int mButtons; |             int mButtons; | ||||||
|             std::string mExplicit; |             std::string mExplicit; | ||||||
|             char mType; |             char mType; | ||||||
|  |  | ||||||
|  | @ -360,6 +360,8 @@ namespace Compiler | ||||||
|             special = S_open; |             special = S_open; | ||||||
|         else if (c==')') |         else if (c==')') | ||||||
|             special = S_close; |             special = S_close; | ||||||
|  |         else if (c=='.') | ||||||
|  |             special = S_member; | ||||||
|         else if (c=='=') |         else if (c=='=') | ||||||
|         { |         { | ||||||
|             if (get (c)) |             if (get (c)) | ||||||
|  |  | ||||||
|  | @ -65,7 +65,8 @@ namespace Compiler | ||||||
|                 S_cmpEQ, S_cmpNE, S_cmpLT, S_cmpLE, S_cmpGT, S_cmpGE, |                 S_cmpEQ, S_cmpNE, S_cmpLT, S_cmpLE, S_cmpGT, S_cmpGE, | ||||||
|                 S_plus, S_minus, S_mult, S_div, |                 S_plus, S_minus, S_mult, S_div, | ||||||
|                 S_comma, |                 S_comma, | ||||||
|                 S_ref |                 S_ref, | ||||||
|  |                 S_member | ||||||
|             }; |             }; | ||||||
| 
 | 
 | ||||||
|         private: |         private: | ||||||
|  |  | ||||||
|  | @ -65,6 +65,19 @@ namespace Interpreter | ||||||
|             virtual void enable (const std::string& id = "") = 0; |             virtual void enable (const std::string& id = "") = 0; | ||||||
| 
 | 
 | ||||||
|             virtual void disable (const std::string& id = "") = 0; |             virtual void disable (const std::string& id = "") = 0; | ||||||
|  | 
 | ||||||
|  |             virtual int getMemberShort (const std::string& id, const std::string& name) const = 0; | ||||||
|  | 
 | ||||||
|  |             virtual int getMemberLong (const std::string& id, const std::string& name) const = 0; | ||||||
|  | 
 | ||||||
|  |             virtual float getMemberFloat (const std::string& id, const std::string& name) const = 0; | ||||||
|  | 
 | ||||||
|  |             virtual void setMemberShort (const std::string& id, const std::string& name, int value) = 0; | ||||||
|  | 
 | ||||||
|  |             virtual void setMemberLong (const std::string& id, const std::string& name, int value) = 0; | ||||||
|  | 
 | ||||||
|  |             virtual void setMemberFloat (const std::string& id, const std::string& name, float value) | ||||||
|  |                 = 0; | ||||||
|     }; |     }; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -121,5 +121,11 @@ op  58: report string literal index in stack[0]; | ||||||
|          additional arguments (if any) in stack[n]..stack[1]; |          additional arguments (if any) in stack[n]..stack[1]; | ||||||
|          n is determined according to the message string |          n is determined according to the message string | ||||||
|          all arguments are removed from stack |          all arguments are removed from stack | ||||||
| opcodes 59-33554431 unused | op 59: store stack[0] in member short stack[2] of object with ID stack[1] | ||||||
|  | op 60: store stack[0] in member long stack[2] of object with ID stack[1] | ||||||
|  | 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 | ||||||
| opcodes 33554432-67108863 reserved for extensions | opcodes 33554432-67108863 reserved for extensions | ||||||
|  |  | ||||||
|  | @ -40,6 +40,12 @@ namespace Interpreter | ||||||
|         interpreter.installSegment5 (42, new OpFetchGlobalShort); |         interpreter.installSegment5 (42, new OpFetchGlobalShort); | ||||||
|         interpreter.installSegment5 (43, new OpFetchGlobalLong); |         interpreter.installSegment5 (43, new OpFetchGlobalLong); | ||||||
|         interpreter.installSegment5 (44, new OpFetchGlobalFloat); |         interpreter.installSegment5 (44, new OpFetchGlobalFloat); | ||||||
|  |         interpreter.installSegment5 (59, new OpStoreMemberShort); | ||||||
|  |         interpreter.installSegment5 (60, new OpStoreMemberLong); | ||||||
|  |         interpreter.installSegment5 (61, new OpStoreMemberFloat); | ||||||
|  |         interpreter.installSegment5 (62, new OpFetchMemberShort); | ||||||
|  |         interpreter.installSegment5 (63, new OpFetchMemberLong); | ||||||
|  |         interpreter.installSegment5 (64, new OpFetchMemberFloat); | ||||||
| 
 | 
 | ||||||
|         // math
 |         // math
 | ||||||
|         interpreter.installSegment5 (9, new OpAddInt<Type_Integer>); |         interpreter.installSegment5 (9, new OpAddInt<Type_Integer>); | ||||||
|  |  | ||||||
|  | @ -205,7 +205,117 @@ namespace Interpreter | ||||||
|                 runtime[0].mFloat = value; |                 runtime[0].mFloat = value; | ||||||
|             } |             } | ||||||
|     }; |     }; | ||||||
|  | 
 | ||||||
|  |     class OpStoreMemberShort : public Opcode0 | ||||||
|  |     { | ||||||
|  |         public: | ||||||
|  | 
 | ||||||
|  |             virtual void execute (Runtime& runtime) | ||||||
|  |             { | ||||||
|  |                 Type_Integer data = runtime[0].mInteger; | ||||||
|  |                 Type_Integer index = runtime[1].mInteger; | ||||||
|  |                 std::string id = runtime.getStringLiteral (index); | ||||||
|  |                 index = runtime[2].mInteger; | ||||||
|  |                 std::string variable = runtime.getStringLiteral (index); | ||||||
|  | 
 | ||||||
|  |                 runtime.getContext().setMemberShort (id, variable, data); | ||||||
|  | 
 | ||||||
|  |                 runtime.pop(); | ||||||
|  |                 runtime.pop(); | ||||||
|  |                 runtime.pop(); | ||||||
|  |             } | ||||||
|  |     }; | ||||||
|  | 
 | ||||||
|  |     class OpStoreMemberLong : public Opcode0 | ||||||
|  |     { | ||||||
|  |         public: | ||||||
|  | 
 | ||||||
|  |             virtual void execute (Runtime& runtime) | ||||||
|  |             { | ||||||
|  |                 Type_Integer data = runtime[0].mInteger; | ||||||
|  |                 Type_Integer index = runtime[1].mInteger; | ||||||
|  |                 std::string id = runtime.getStringLiteral (index); | ||||||
|  |                 index = runtime[2].mInteger; | ||||||
|  |                 std::string variable = runtime.getStringLiteral (index); | ||||||
|  | 
 | ||||||
|  |                 runtime.getContext().setMemberLong (id, variable, data); | ||||||
|  | 
 | ||||||
|  |                 runtime.pop(); | ||||||
|  |                 runtime.pop(); | ||||||
|  |                 runtime.pop(); | ||||||
|  |             } | ||||||
|  |     }; | ||||||
|  | 
 | ||||||
|  |     class OpStoreMemberFloat : public Opcode0 | ||||||
|  |     { | ||||||
|  |         public: | ||||||
|  | 
 | ||||||
|  |             virtual void execute (Runtime& runtime) | ||||||
|  |             { | ||||||
|  |                 Type_Float data = runtime[0].mFloat; | ||||||
|  |                 Type_Integer index = runtime[1].mInteger; | ||||||
|  |                 std::string id = runtime.getStringLiteral (index); | ||||||
|  |                 index = runtime[2].mInteger; | ||||||
|  |                 std::string variable = runtime.getStringLiteral (index); | ||||||
|  | 
 | ||||||
|  |                 runtime.getContext().setMemberFloat (id, variable, data); | ||||||
|  | 
 | ||||||
|  |                 runtime.pop(); | ||||||
|  |                 runtime.pop(); | ||||||
|  |                 runtime.pop(); | ||||||
|  |             } | ||||||
|  |     }; | ||||||
|  | 
 | ||||||
|  |     class OpFetchMemberShort : public Opcode0 | ||||||
|  |     { | ||||||
|  |         public: | ||||||
|  | 
 | ||||||
|  |             virtual void execute (Runtime& runtime) | ||||||
|  |             { | ||||||
|  |                 Type_Integer index = runtime[0].mInteger; | ||||||
|  |                 std::string id = runtime.getStringLiteral (index); | ||||||
|  |                 index = runtime[1].mInteger; | ||||||
|  |                 std::string variable = runtime.getStringLiteral (index); | ||||||
|  |                 runtime.pop(); | ||||||
|  | 
 | ||||||
|  |                 int value = runtime.getContext().getMemberShort (id, variable); | ||||||
|  |                 runtime[0].mInteger = value; | ||||||
|  |             } | ||||||
|  |     }; | ||||||
|  | 
 | ||||||
|  |     class OpFetchMemberLong : public Opcode0 | ||||||
|  |     { | ||||||
|  |         public: | ||||||
|  | 
 | ||||||
|  |             virtual void execute (Runtime& runtime) | ||||||
|  |             { | ||||||
|  |                 Type_Integer index = runtime[0].mInteger; | ||||||
|  |                 std::string id = runtime.getStringLiteral (index); | ||||||
|  |                 index = runtime[1].mInteger; | ||||||
|  |                 std::string variable = runtime.getStringLiteral (index); | ||||||
|  |                 runtime.pop(); | ||||||
|  | 
 | ||||||
|  |                 int value = runtime.getContext().getMemberLong (id, variable); | ||||||
|  |                 runtime[0].mInteger = value; | ||||||
|  |             } | ||||||
|  |     }; | ||||||
|  | 
 | ||||||
|  |     class OpFetchMemberFloat : public Opcode0 | ||||||
|  |     { | ||||||
|  |         public: | ||||||
|  | 
 | ||||||
|  |             virtual void execute (Runtime& runtime) | ||||||
|  |             { | ||||||
|  |                 Type_Integer index = runtime[0].mInteger; | ||||||
|  |                 std::string id = runtime.getStringLiteral (index); | ||||||
|  |                 index = runtime[1].mInteger; | ||||||
|  |                 std::string variable = runtime.getStringLiteral (index); | ||||||
|  |                 runtime.pop(); | ||||||
|  | 
 | ||||||
|  |                 float value = runtime.getContext().getMemberFloat (id, variable); | ||||||
|  |                 runtime[0].mFloat = value; | ||||||
|  |             } | ||||||
|  |     }; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| #endif | #endif | ||||||
| 
 |  | ||||||
|  |  | ||||||
		Loading…
	
		Reference in a new issue