mirror of
https://github.com/TES3MP/openmw-tes3mp.git
synced 2025-01-19 21:23:52 +00:00
extended scripting extensions to code segment 3 (instructions and functions with optional arguments)
This commit is contained in:
parent
b3cc3073a3
commit
c18e83d7c0
4 changed files with 160 additions and 80 deletions
|
@ -346,9 +346,10 @@ namespace Compiler
|
|||
start();
|
||||
|
||||
mTokenLoc = loc;
|
||||
parseArguments (argumentType, scanner);
|
||||
int optionals = parseArguments (argumentType, scanner);
|
||||
|
||||
extensions->generateFunctionCode (keyword, mCode, mLiterals, mExplicit);
|
||||
extensions->generateFunctionCode (keyword, mCode, mLiterals, mExplicit,
|
||||
optionals);
|
||||
mOperands.push_back (returnType);
|
||||
mExplicit.clear();
|
||||
mRefOp = false;
|
||||
|
@ -465,9 +466,9 @@ namespace Compiler
|
|||
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;
|
||||
|
|
|
@ -14,119 +14,197 @@ namespace Compiler
|
|||
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, char& returnType, std::string& 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)
|
||||
return false;
|
||||
|
||||
|
||||
returnType = iter->second.mReturn;
|
||||
argumentType = iter->second.mArguments;
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool Extensions::isInstruction (int keyword, std::string& 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)
|
||||
return false;
|
||||
|
||||
|
||||
argumentType = iter->second.mArguments;
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
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;
|
||||
|
||||
mFunctions.insert (std::make_pair (code, function));
|
||||
function.mCode = code;
|
||||
function.mCodeExplicit = codeExplicit;
|
||||
|
||||
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;
|
||||
|
||||
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 = segment5code;
|
||||
instruction.mCodeExplicit = segment5codeExplicit;
|
||||
|
||||
mInstructions.insert (std::make_pair (code, instruction));
|
||||
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)
|
||||
throw std::logic_error ("explicit references not supported");
|
||||
|
||||
|
||||
int index = literals.addString (id);
|
||||
Generator::pushInt (code, literals, index);
|
||||
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");
|
||||
}
|
||||
|
||||
code.push_back (Generator::segment5 (
|
||||
id.empty() ? iter->second.mCode : iter->second.mCodeExplicit));
|
||||
}
|
||||
|
||||
|
||||
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)
|
||||
throw std::logic_error ("explicit references not supported");
|
||||
|
||||
|
||||
int index = literals.addString (id);
|
||||
Generator::pushInt (code, literals, index);
|
||||
Generator::pushInt (code, literals, index);
|
||||
}
|
||||
|
||||
code.push_back (Generator::segment5 (
|
||||
id.empty() ? iter->second.mCode : iter->second.mCodeExplicit));
|
||||
}
|
||||
|
||||
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");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -10,9 +10,9 @@
|
|||
namespace Compiler
|
||||
{
|
||||
class Literals;
|
||||
|
||||
|
||||
/// \brief Collection of compiler extensions
|
||||
|
||||
|
||||
class Extensions
|
||||
{
|
||||
struct Function
|
||||
|
@ -21,29 +21,31 @@ namespace Compiler
|
|||
std::string mArguments;
|
||||
int mCode;
|
||||
int mCodeExplicit;
|
||||
int mSegment;
|
||||
};
|
||||
|
||||
|
||||
struct Instruction
|
||||
{
|
||||
std::string mArguments;
|
||||
int mCode;
|
||||
int mCode;
|
||||
int mCodeExplicit;
|
||||
int mSegment;
|
||||
};
|
||||
|
||||
|
||||
int mNextKeywordIndex;
|
||||
std::map<std::string, int> mKeywords;
|
||||
std::map<int, Function> mFunctions;
|
||||
std::map<int, Instruction> mInstructions;
|
||||
|
||||
|
||||
public:
|
||||
|
||||
|
||||
Extensions();
|
||||
|
||||
|
||||
int searchKeyword (const std::string& keyword) const;
|
||||
///< Return extension keyword code, that is assigned to the string \a keyword.
|
||||
/// - if no match is found 0 is returned.
|
||||
/// - keyword must be all lower case.
|
||||
|
||||
|
||||
bool isFunction (int keyword, char& returnType, std::string& argumentType,
|
||||
bool explicitReference) const;
|
||||
///< Is this keyword registered with a function? If yes, return return and argument
|
||||
|
@ -52,32 +54,31 @@ namespace Compiler
|
|||
bool isInstruction (int keyword, std::string& argumentType,
|
||||
bool explicitReference) const;
|
||||
///< 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;
|
||||
///< Append code for function to \a code.
|
||||
Literals& literals, const std::string& id, int optionalArguments) const;
|
||||
///< Append code for function to \a code.
|
||||
};
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
|
|
|
@ -242,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;
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue