khanat-opennel-code/code/ryzom/server/src/ai_service/script_compiler.h

438 lines
14 KiB
C++

// Ryzom - MMORPG Framework <http://dev.ryzom.com/projects/ryzom/>
// 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 <http://www.gnu.org/licenses/>.
#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<CCodeNode> firstChildNode=NULL);
virtual void dump(size_t indent=0);
virtual std::string getFullName() const;
virtual ~CCodeNode() { }
std::string _Type;
std::string _Name;
NLMISC::CSmartPtr<CCodeNode> _NextNode;
NLMISC::CSmartPtr<CCodeNode> _FirstChildNode;
};
//////////////////////////////////////////////////////////////////////////////
class CCodeTokenNode : public CCodeNode
{
public:
CCodeTokenNode(const std::string &type, const std::string &name, NLMISC::CSmartPtr<CCodeNode> 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<CCodeNode> &codeNode);
CTokenTestResult(const NLMISC::CSmartPtr<CCodeNode> &codeNode, TBasicTokenTestRes res);
virtual ~CTokenTestResult();
bool isValid() const;
CCodeNode *getCode () const;
private:
TBasicTokenTestRes _res;
NLMISC::CSmartPtr<CCodeNode> _codeNode;
};
//////////////////////////////////////////////////////////////////////////////
class CBasicToken : public NLMISC::CRefCount
{
public:
typedef std::map<char,NLMISC::CSmartPtr<CBasicToken> > TBasicTokenList;
public:
virtual ~CBasicToken() { }
typedef std::vector<NLMISC::CSmartPtr<CBasicToken> > 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<CBasicToken> getNewToken(char c);
static void insertBasicToken(char id, NLMISC::CSmartPtr<CBasicToken> token);
static TBasicTokenList _BasicTokens;
};
//////////////////////////////////////////////////////////////////////////////
class CToken : public NLMISC::CRefCount
{
public:
CToken(const std::string &tokenName, const std::string &tokenDesc);
typedef std::vector<NLMISC::CSmartPtr<CBasicToken> > 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<NLMISC::CSmartPtr<CBasicToken> > _Tokens;
};
//////////////////////////////////////////////////////////////////////////////
// Rule classes //
//////////////////////////////////////////////////////////////////////////////
class CSubRule;
typedef std::vector<NLMISC::CSmartPtr<CSubRule> > 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<std::string> _tokens;
NLMISC::CSmartPtr<CRule> _Parent;
std::vector<std::string> _ExecOpCodes;
};
//////////////////////////////////////////////////////////////////////////////
class CSubRuleTracer;
typedef std::vector<NLMISC::CSmartPtr<CSubRuleTracer> > TSubRuleTracerList;
class CSubRuleTracer : public NLMISC::CRefCount, public NLMISC::CDbgRefCount<CSubRuleTracer>
{
public:
CSubRuleTracer(size_t tokenStartIndex, size_t currentTokenIndex, const std::string &name, const std::string &textValue);
CSubRuleTracer(NLMISC::CSmartPtr<CSubRule> subRule, size_t tokenStartIndex, size_t currentTokenIndex, const std::string &name, const std::string &textValue);
CSubRuleTracer(const CSubRuleTracer &otherSRT);
virtual ~CSubRuleTracer();
NLMISC::CSmartPtr<CSubRuleTracer> getValidTracer() const;
void updatePreviousNext();
void checkRule(CSubRule *rule, size_t index, size_t currentToken, TSubRuleTracerList &childTracers);
void checkRules(size_t currentToken);
NLMISC::CSmartPtr<CSubRuleTracer> codifyTree();
void generateCode(NLMISC::CSmartPtr<AIVM::CByteCode> &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<CSubRule> _subRule;
typedef std::set<NLMISC::CSmartPtr<CSubRuleTracer> > TTracersSet;
typedef std::map<size_t, TTracersSet> TOrderedTracers;
static TOrderedTracers _PreviousTracers;
static TOrderedTracers _NextTracers;
TSubRuleTracerList _parentTracers;
TSubRuleTracerList _childTracers;
};
//////////////////////////////////////////////////////////////////////////////
class CCompiler
{
public:
typedef std::map<NLMISC::TStringId, NLMISC::CSmartPtr<CScriptNativeFuncParams> > TNativeFuncMap;
typedef std::vector<NLMISC::CSmartPtr<CRule> > TRuleList;
typedef std::map<std::string, AIVM::CScriptVM::EOpcode> TOpcodeMap;
public:
CCompiler();
virtual ~CCompiler() { }
NLMISC::CSmartPtr<AIVM::CByteCode const> compileCode(std::string const& sourceCode, std::string const& fullName) const;
NLMISC::CSmartPtr<AIVM::CByteCode const> compileCode(std::vector<std::string> const& sourceCodeLines, std::string const& fullName) const;
// New compiler using lex & yacc
NLMISC::CSmartPtr<AIVM::CByteCode const> compileCodeYacc(std::string const& sourceCode, std::string const& fullName, bool dump, bool win32report) const;
// Old compiler
NLMISC::CSmartPtr<AIVM::CByteCode const> 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<AIVM::CByteCode const> &byteCode, std::string const& directory) const;
NLMISC::CSmartPtr<CSubRuleTracer> 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<CRule> 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<NLMISC::CSmartPtr<CToken> > 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<CCodeNode> &codeNode)
: _res(BRULE_VALID)
, _codeNode(codeNode)
{
}
inline
CTokenTestResult::CTokenTestResult(const NLMISC::CSmartPtr<CCodeNode> &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<size_t> *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<std::vector<size_t> * > *ByteCodeList;
};
// Case structure
struct CCase : public CBaseYacc
{
int Line;
size_t Case;
std::vector<size_t> *ByteCode;
};
// Yacc node for case
struct CCaseYacc : public CBaseYacc
{
CCase *Case;
};
// Yacc node for switch
struct CSwitchYacc : public CBaseYacc
{
std::map<size_t, CCase *> *Cases;
};
}; // namespace
// From Lex&Yacc
extern bool aiCompile (std::vector<size_t> &dest, const char *script, const char *scriptName, bool win32report);
#endif