mirror of
				https://github.com/OpenMW/openmw.git
				synced 2025-10-27 00:56:39 +00:00 
			
		
		
		
	
		
			
				
	
	
		
			216 lines
		
	
	
	
		
			6.7 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
			
		
		
	
	
			216 lines
		
	
	
	
		
			6.7 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
| #include "extensions.hpp"
 | |
| 
 | |
| #include <cassert>
 | |
| #include <stdexcept>
 | |
| 
 | |
| #include "generator.hpp"
 | |
| #include "literals.hpp"
 | |
| 
 | |
| namespace Compiler
 | |
| {
 | |
|     Extensions::Extensions() : mNextKeywordIndex (-1) {}
 | |
| 
 | |
|     int Extensions::searchKeyword (const std::string& keyword) const
 | |
|     {
 | |
|         std::map<std::string, int>::const_iterator iter = mKeywords.find (keyword);
 | |
| 
 | |
|         if (iter==mKeywords.end())
 | |
|             return 0;
 | |
| 
 | |
|         return iter->second;
 | |
|     }
 | |
| 
 | |
|     bool Extensions::isFunction (int keyword, ScriptReturn& returnType, ScriptArgs& argumentType,
 | |
|         bool& explicitReference) const
 | |
|     {
 | |
|         std::map<int, Function>::const_iterator iter = mFunctions.find (keyword);
 | |
| 
 | |
|         if (iter==mFunctions.end())
 | |
|             return false;
 | |
| 
 | |
|         if (explicitReference && iter->second.mCodeExplicit==-1)
 | |
|             explicitReference = false;
 | |
| 
 | |
|         returnType = iter->second.mReturn;
 | |
|         argumentType = iter->second.mArguments;
 | |
|         return true;
 | |
|     }
 | |
| 
 | |
|     bool Extensions::isInstruction (int keyword, ScriptArgs& argumentType,
 | |
|         bool& explicitReference) const
 | |
|     {
 | |
|         std::map<int, Instruction>::const_iterator iter = mInstructions.find (keyword);
 | |
| 
 | |
|         if (iter==mInstructions.end())
 | |
|             return false;
 | |
| 
 | |
|         if (explicitReference && iter->second.mCodeExplicit==-1)
 | |
|             explicitReference = false;
 | |
| 
 | |
|         argumentType = iter->second.mArguments;
 | |
|         return true;
 | |
|     }
 | |
| 
 | |
|     void Extensions::registerFunction (const std::string& keyword, ScriptReturn returnType,
 | |
|         const ScriptArgs& argumentType, int code, int codeExplicit)
 | |
|     {
 | |
|         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 = code;
 | |
|         function.mCodeExplicit = codeExplicit;
 | |
| 
 | |
|         mFunctions.insert (std::make_pair (keywordIndex, function));
 | |
|     }
 | |
| 
 | |
|     void Extensions::registerInstruction (const std::string& keyword,
 | |
|         const ScriptArgs& argumentType, int code, int codeExplicit)
 | |
|     {
 | |
|         Instruction 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, 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)
 | |
|                 throw std::logic_error ("explicit references not supported");
 | |
| 
 | |
|             int index = literals.addString (id);
 | |
|             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,
 | |
|         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)
 | |
|                 throw std::logic_error ("explicit references not supported");
 | |
| 
 | |
|             int index = literals.addString (id);
 | |
|             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::listKeywords (std::vector<std::string>& keywords) const
 | |
|     {
 | |
|         for (std::map<std::string, int>::const_iterator iter (mKeywords.begin());
 | |
|             iter!=mKeywords.end(); ++iter)
 | |
|             keywords.push_back (iter->first);
 | |
|     }
 | |
| }
 |