From c18e83d7c00ae68fd6bfc717e962dfb5110f6c8f Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Sun, 22 Aug 2010 14:00:30 +0200 Subject: [PATCH] extended scripting extensions to code segment 3 (instructions and functions with optional arguments) --- components/compiler/exprparser.cpp | 9 +- components/compiler/extensions.cpp | 184 ++++++++++++++++++++--------- components/compiler/extensions.hpp | 43 +++---- components/compiler/lineparser.cpp | 4 +- 4 files changed, 160 insertions(+), 80 deletions(-) diff --git a/components/compiler/exprparser.cpp b/components/compiler/exprparser.cpp index 484aea878..06c3207e2 100644 --- a/components/compiler/exprparser.cpp +++ b/components/compiler/exprparser.cpp @@ -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; diff --git a/components/compiler/extensions.cpp b/components/compiler/extensions.cpp index 78ae0fdfd..3b1d180b1 100644 --- a/components/compiler/extensions.cpp +++ b/components/compiler/extensions.cpp @@ -14,119 +14,197 @@ namespace Compiler int Extensions::searchKeyword (const std::string& keyword) const { std::map::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::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::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& code, - Literals& literals, const std::string& id) const + Literals& literals, const std::string& id, int optionalArguments) const { + assert (optionalArguments>=0); + std::map::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& code, Literals& literals, const std::string& id) - const + std::vector& code, Literals& literals, const std::string& id, + int optionalArguments) const { + assert (optionalArguments>=0); + std::map::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); + } + + 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)); - } + } } diff --git a/components/compiler/extensions.hpp b/components/compiler/extensions.hpp index 85a761951..960cac157 100644 --- a/components/compiler/extensions.hpp +++ b/components/compiler/extensions.hpp @@ -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 mKeywords; std::map mFunctions; std::map 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& 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& 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 - diff --git a/components/compiler/lineparser.cpp b/components/compiler/lineparser.cpp index b4c79c972..3f80d671e 100644 --- a/components/compiler/lineparser.cpp +++ b/components/compiler/lineparser.cpp @@ -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; }