// Ryzom - MMORPG Framework // Copyright (C) 2010 Winch Gate Property Limited // // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU Affero General Public License as // published by the Free Software Foundation, either version 3 of the // License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU Affero General Public License for more details. // // You should have received a copy of the GNU Affero General Public License // along with this program. If not, see . #ifndef __SCRIPT_COMPILER__ #define __SCRIPT_COMPILER__ #include "script_vm.h" // Forward declarations class CStateInstance; namespace AICOMP { /****************************************************************************/ /* Compiler classes */ /****************************************************************************/ ////////////////////////////////////////////////////////////////////////////// // Helper classes // ////////////////////////////////////////////////////////////////////////////// struct EScriptError : public NLMISC::Exception { EScriptError(const std::string &text, size_t index); size_t getIndex() const; size_t _Index; }; ////////////////////////////////////////////////////////////////////////////// // Native functions access // ////////////////////////////////////////////////////////////////////////////// typedef void (*FScrptNativeFunc)(CStateInstance* si, AIVM::CScriptStack& stack); class CScriptNativeFuncParams : public NLMISC::CRefCount { public: CScriptNativeFuncParams(const std::string &str, FScrptNativeFunc func); virtual ~CScriptNativeFuncParams() { } size_t _nbInParams; size_t _nbOutParams; bool _va; FScrptNativeFunc _func; }; ////////////////////////////////////////////////////////////////////////////// // Node classes // ////////////////////////////////////////////////////////////////////////////// class CCodeNode : public NLMISC::CRefCount { public: CCodeNode(const std::string &type, const std::string &name, NLMISC::CSmartPtr firstChildNode=NULL); virtual void dump(size_t indent=0); virtual std::string getFullName() const; virtual ~CCodeNode() { } std::string _Type; std::string _Name; NLMISC::CSmartPtr _NextNode; NLMISC::CSmartPtr _FirstChildNode; }; ////////////////////////////////////////////////////////////////////////////// class CCodeTokenNode : public CCodeNode { public: CCodeTokenNode(const std::string &type, const std::string &name, NLMISC::CSmartPtr firstChildNode); virtual ~CCodeTokenNode() { } void dump(size_t indent=0); virtual std::string getFullName() const; }; ////////////////////////////////////////////////////////////////////////////// // Token classes // ////////////////////////////////////////////////////////////////////////////// class CTokenTestResult { public: enum TBasicTokenTestRes { BRULE_INVALID = 0, BRULE_VALID, }; CTokenTestResult(); CTokenTestResult(const NLMISC::CSmartPtr &codeNode); CTokenTestResult(const NLMISC::CSmartPtr &codeNode, TBasicTokenTestRes res); virtual ~CTokenTestResult(); bool isValid() const; CCodeNode *getCode () const; private: TBasicTokenTestRes _res; NLMISC::CSmartPtr _codeNode; }; ////////////////////////////////////////////////////////////////////////////// class CBasicToken : public NLMISC::CRefCount { public: typedef std::map > TBasicTokenList; public: virtual ~CBasicToken() { } typedef std::vector > TTokenList; virtual size_t init (TTokenList &tokenList, const std::string &str, size_t firstIndex, size_t lastIndex) = 0; virtual CBasicToken *createNew () const = 0; virtual void dump(size_t indent) const = 0; virtual CTokenTestResult buildNode(const std::string &code, size_t &index) const = 0; static size_t initTokens(TTokenList &tokenList, const std::string &str, size_t firstIndex, size_t lastIndex); static NLMISC::CSmartPtr getNewToken(char c); static void insertBasicToken(char id, NLMISC::CSmartPtr token); static TBasicTokenList _BasicTokens; }; ////////////////////////////////////////////////////////////////////////////// class CToken : public NLMISC::CRefCount { public: CToken(const std::string &tokenName, const std::string &tokenDesc); typedef std::vector > TTokenContainer; void dump() const; virtual ~CToken() { } CTokenTestResult buildTree(const std::string &code, size_t &index); const std::string &getName() const; std::string _tokenName; std::string _tokenDesc; std::vector > _Tokens; }; ////////////////////////////////////////////////////////////////////////////// // Rule classes // ////////////////////////////////////////////////////////////////////////////// class CSubRule; typedef std::vector > TSubRuleList; class CRule : public NLMISC::CRefCount { public: CRule(const std::string &name, const std::string &decl); virtual ~CRule() { } void setDesc(const std::string &decl); TSubRuleList _subRules; std::string _Name; }; ////////////////////////////////////////////////////////////////////////////// class CSubRule : public NLMISC::CRefCount { public: CSubRule(CRule *parent, const std::string &decl); std::vector _tokens; NLMISC::CSmartPtr _Parent; std::vector _ExecOpCodes; }; ////////////////////////////////////////////////////////////////////////////// class CSubRuleTracer; typedef std::vector > TSubRuleTracerList; class CSubRuleTracer : public NLMISC::CRefCount, public NLMISC::CDbgRefCount { public: CSubRuleTracer(size_t tokenStartIndex, size_t currentTokenIndex, const std::string &name, const std::string &textValue); CSubRuleTracer(NLMISC::CSmartPtr subRule, size_t tokenStartIndex, size_t currentTokenIndex, const std::string &name, const std::string &textValue); CSubRuleTracer(const CSubRuleTracer &otherSRT); virtual ~CSubRuleTracer(); NLMISC::CSmartPtr getValidTracer() const; void updatePreviousNext(); void checkRule(CSubRule *rule, size_t index, size_t currentToken, TSubRuleTracerList &childTracers); void checkRules(size_t currentToken); NLMISC::CSmartPtr codifyTree(); void generateCode(NLMISC::CSmartPtr &cByteCode) const; /// Returns a chain specifying the params this way: ffsf for (float, float, string, float) const CSubRuleTracer *getChildForName(const std::string &name) const; void getSignature(std::string &signature, bool inOtherWiseOut) const; size_t getNbChildNamed(const std::string &name) const; CSubRuleTracer *getHigherParent (); CSubRuleTracer *getNextLower() const; void removePrevious(CSubRuleTracer *tracer); void removeNext (CSubRuleTracer *tracer); void removeParent (CSubRuleTracer *tracer); void removeChild (CSubRuleTracer *tracer); void detachFromEveryBody(); void iterateToMarkValidTracer(); void removeInvalidTracers(); void flushErrors(); void dump(size_t indent) const; std::string _Name; std::string _TextValue; size_t _index; ///< Index in the subrule. size_t _tokenStartIndex; size_t _tokenIndex; bool _Valid; ////////////////////////////////////////////////////////////////////////////// // All Links are Directs. NLMISC::CSmartPtr _subRule; typedef std::set > TTracersSet; typedef std::map TOrderedTracers; static TOrderedTracers _PreviousTracers; static TOrderedTracers _NextTracers; TSubRuleTracerList _parentTracers; TSubRuleTracerList _childTracers; }; ////////////////////////////////////////////////////////////////////////////// class CCompiler { public: typedef std::map > TNativeFuncMap; typedef std::vector > TRuleList; typedef std::map TOpcodeMap; public: CCompiler(); virtual ~CCompiler() { } NLMISC::CSmartPtr compileCode(std::string const& sourceCode, std::string const& fullName) const; NLMISC::CSmartPtr compileCode(std::vector const& sourceCodeLines, std::string const& fullName) const; // New compiler using lex & yacc NLMISC::CSmartPtr compileCodeYacc(std::string const& sourceCode, std::string const& fullName, bool dump, bool win32report) const; // Old compiler NLMISC::CSmartPtr compileCodeOld(std::string const& sourceCode, std::string const& fullName, bool dump) const; // Dump the source and the bytecode for debugging void dumpByteCode(std::string const& sourceCode, std::string const& fullName, NLMISC::CSmartPtr &byteCode, std::string const& directory) const; NLMISC::CSmartPtr buildCodeTree(const std::string &code) const; static void registerNativeFunc (); static void addToken(std::string const& tokenName, std::string const& tokenDesc); static void addRule(std::string const& ruleName, std::string const& ruleDesc); static void addOpcode(std::string const& str, AIVM::CScriptVM::EOpcode const& op); static void addNativeFunc(std::string const& signature, FScrptNativeFunc const& foo); static void addDeprecatedNativeFunc(std::string const& signature); static CToken* getToken (std::string const& tokenName); static NLMISC::CSmartPtr getRule (std::string const& ruleName); static bool getNextToken (std::string const& text, size_t& index, std::string& tokenName, std::string& textValue) throw (EScriptError); static std::string const& getOpcodeName (AIVM::CScriptVM::EOpcode const& op); static AIVM::CScriptVM::EOpcode getOpcodeAndValue (std::string const& str, std::string& value); static CScriptNativeFuncParams* getNativeFunc (std::string const& funcName, std::string const& inparams, std::string const& outparams); static CCompiler& getInstance() { if (!_Instance) _Instance = new CCompiler(); return *_Instance; } static TNativeFuncMap const& getFunctionList() { return _NativeFunctions; } typedef std::vector > TTokenList; static TRuleList _Rules; static TOpcodeMap _Opcodes; private: static TNativeFuncMap _NativeFunctions; static TTokenList _Tokens; static CCompiler* _Instance; }; /****************************************************************************/ /* Inlined functions */ /****************************************************************************/ inline EScriptError::EScriptError(const std::string &text, size_t index) : NLMISC::Exception(text) , _Index(index) { } inline size_t EScriptError::getIndex() const { return _Index; } inline CTokenTestResult::CTokenTestResult() : _res(BRULE_VALID) { } inline CTokenTestResult::CTokenTestResult(const NLMISC::CSmartPtr &codeNode) : _res(BRULE_VALID) , _codeNode(codeNode) { } inline CTokenTestResult::CTokenTestResult(const NLMISC::CSmartPtr &codeNode, TBasicTokenTestRes res) : _res(BRULE_VALID) , _codeNode(codeNode) { } inline CTokenTestResult::~CTokenTestResult() { } inline bool CTokenTestResult::isValid() const { return _res==BRULE_VALID; } inline CCodeNode *CTokenTestResult::getCode () const { return _codeNode; } /****************************************************************************/ /* For LEX & YACC */ /****************************************************************************/ #define AICOMP_MAX_SIGNATURE 32 // Yacc base node struct CBaseYacc { char Signature[AICOMP_MAX_SIGNATURE]; bool isFloat () const { return strcmp (Signature, "f") == 0; } bool isString () const { return strcmp (Signature, "s") == 0; } bool isBool () const { return strcmp (Signature, "b") == 0; } const char *getType () const { return isFloat ()?"float":isBool ()?"bool":isString ()?"string":"void"; } }; // Yacc node for current byte code struct CByteCodeYacc : public CBaseYacc { std::vector *ByteCode; }; // Yacc node for a single opcode struct COpcodeYacc : public CBaseYacc { int Line; size_t Opcode; }; // Yacc node for operators struct COperatorYacc : public COpcodeYacc { const char *Operator; }; // Yacc node for byte code tree node, keeping the tree structure struct CByteCodeListYacc : public CBaseYacc { std::list * > *ByteCodeList; }; // Case structure struct CCase : public CBaseYacc { int Line; size_t Case; std::vector *ByteCode; }; // Yacc node for case struct CCaseYacc : public CBaseYacc { CCase *Case; }; // Yacc node for switch struct CSwitchYacc : public CBaseYacc { std::map *Cases; }; }; // namespace // From Lex&Yacc extern bool aiCompile (std::vector &dest, const char *script, const char *scriptName, bool win32report); #endif