1 // Ryzom - MMORPG Framework <http://dev.ryzom.com/projects/ryzom/>
2 // Copyright (C) 2010 Winch Gate Property Limited
4 // This program is free software: you can redistribute it and/or modify
5 // it under the terms of the GNU Affero General Public License as
6 // published by the Free Software Foundation, either version 3 of the
7 // License, or (at your option) any later version.
9 // This program is distributed in the hope that it will be useful,
10 // but WITHOUT ANY WARRANTY; without even the implied warranty of
11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 // GNU Affero General Public License for more details.
14 // You should have received a copy of the GNU Affero General Public License
15 // along with this program. If not, see <http://www.gnu.org/licenses/>.
17 #ifndef __SCRIPT_COMPILER__
18 #define __SCRIPT_COMPILER__
20 #include "script_vm.h"
23 static std::string
scriptHex_decode(std::string str
)
26 for (size_t i
=0; i
<(str
.length()-1); i
+=2)
28 char c1
= str
[i
], c2
= str
[i
+1];
29 char buffer
[3] = { c1
, c2
, '\0' };
30 char c
= (char)strtol(buffer
, NULL
, 16);
36 // Forward declarations
42 /****************************************************************************/
43 /* Compiler classes */
44 /****************************************************************************/
45 //////////////////////////////////////////////////////////////////////////////
47 //////////////////////////////////////////////////////////////////////////////
49 struct EScriptError
: public NLMISC::Exception
51 EScriptError(const std::string
&text
, size_t index
);
52 size_t getIndex() const;
56 //////////////////////////////////////////////////////////////////////////////
57 // Native functions access //
58 //////////////////////////////////////////////////////////////////////////////
60 typedef void (*FScrptNativeFunc
)(CStateInstance
* si
, AIVM::CScriptStack
& stack
);
62 class CScriptNativeFuncParams
: public NLMISC::CRefCount
65 CScriptNativeFuncParams(const std::string
&str
, FScrptNativeFunc func
);
66 virtual ~CScriptNativeFuncParams() { }
70 FScrptNativeFunc _func
;
73 //////////////////////////////////////////////////////////////////////////////
75 //////////////////////////////////////////////////////////////////////////////
77 class CCodeNode
: public NLMISC::CRefCount
80 CCodeNode(const std::string
&type
, const std::string
&name
, NLMISC::CSmartPtr
<CCodeNode
> firstChildNode
=NULL
);
82 virtual void dump(size_t indent
=0);
83 virtual std::string
getFullName() const;
85 virtual ~CCodeNode() { }
88 NLMISC::CSmartPtr
<CCodeNode
> _NextNode
;
89 NLMISC::CSmartPtr
<CCodeNode
> _FirstChildNode
;
92 //////////////////////////////////////////////////////////////////////////////
94 class CCodeTokenNode
: public CCodeNode
97 CCodeTokenNode(const std::string
&type
, const std::string
&name
, NLMISC::CSmartPtr
<CCodeNode
> firstChildNode
);
98 virtual ~CCodeTokenNode() { }
100 void dump(size_t indent
=0);
101 virtual std::string
getFullName() const;
104 //////////////////////////////////////////////////////////////////////////////
106 //////////////////////////////////////////////////////////////////////////////
108 class CTokenTestResult
111 enum TBasicTokenTestRes
118 CTokenTestResult(const NLMISC::CSmartPtr
<CCodeNode
> &codeNode
);
119 CTokenTestResult(const NLMISC::CSmartPtr
<CCodeNode
> &codeNode
, TBasicTokenTestRes res
);
120 virtual ~CTokenTestResult();
121 bool isValid() const;
122 CCodeNode
*getCode () const;
124 TBasicTokenTestRes _res
;
125 NLMISC::CSmartPtr
<CCodeNode
> _codeNode
;
128 //////////////////////////////////////////////////////////////////////////////
130 class CBasicToken
: public NLMISC::CRefCount
133 typedef std::map
<char,NLMISC::CSmartPtr
<CBasicToken
> > TBasicTokenList
;
135 virtual ~CBasicToken() { }
137 typedef std::vector
<NLMISC::CSmartPtr
<CBasicToken
> > TTokenList
;
139 virtual size_t init (TTokenList
&tokenList
, const std::string
&str
, size_t firstIndex
, size_t lastIndex
) = 0;
140 virtual CBasicToken
*createNew () const = 0;
141 virtual void dump(size_t indent
) const = 0;
142 virtual CTokenTestResult
buildNode(const std::string
&code
, size_t &index
) const = 0;
144 static size_t initTokens(TTokenList
&tokenList
, const std::string
&str
, size_t firstIndex
, size_t lastIndex
);
146 static NLMISC::CSmartPtr
<CBasicToken
> getNewToken(char c
);
147 static void insertBasicToken(char id
, NLMISC::CSmartPtr
<CBasicToken
> token
);
148 static TBasicTokenList _BasicTokens
;
151 //////////////////////////////////////////////////////////////////////////////
153 class CToken
: public NLMISC::CRefCount
156 CToken(const std::string
&tokenName
, const std::string
&tokenDesc
);
158 typedef std::vector
<NLMISC::CSmartPtr
<CBasicToken
> > TTokenContainer
;
162 virtual ~CToken() { }
164 CTokenTestResult
buildTree(const std::string
&code
, size_t &index
);
166 const std::string
&getName() const;
168 std::string _tokenName
;
169 std::string _tokenDesc
;
170 std::vector
<NLMISC::CSmartPtr
<CBasicToken
> > _Tokens
;
173 //////////////////////////////////////////////////////////////////////////////
175 //////////////////////////////////////////////////////////////////////////////
179 typedef std::vector
<NLMISC::CSmartPtr
<CSubRule
> > TSubRuleList
;
181 class CRule
: public NLMISC::CRefCount
184 CRule(const std::string
&name
, const std::string
&decl
);
187 void setDesc(const std::string
&decl
);
189 TSubRuleList _subRules
;
193 //////////////////////////////////////////////////////////////////////////////
195 class CSubRule
: public NLMISC::CRefCount
198 CSubRule(CRule
*parent
, const std::string
&decl
);
200 std::vector
<std::string
> _tokens
;
201 NLMISC::CSmartPtr
<CRule
> _Parent
;
203 std::vector
<std::string
> _ExecOpCodes
;
206 //////////////////////////////////////////////////////////////////////////////
208 class CSubRuleTracer
;
209 typedef std::vector
<NLMISC::CSmartPtr
<CSubRuleTracer
> > TSubRuleTracerList
;
211 class CSubRuleTracer
: public NLMISC::CRefCount
, public NLMISC::CDbgRefCount
<CSubRuleTracer
>
214 CSubRuleTracer(size_t tokenStartIndex
, size_t currentTokenIndex
, const std::string
&name
, const std::string
&textValue
);
215 CSubRuleTracer(NLMISC::CSmartPtr
<CSubRule
> subRule
, size_t tokenStartIndex
, size_t currentTokenIndex
, const std::string
&name
, const std::string
&textValue
);
216 CSubRuleTracer(const CSubRuleTracer
&otherSRT
);
218 virtual ~CSubRuleTracer();
220 NLMISC::CSmartPtr
<CSubRuleTracer
> getValidTracer() const;
222 void updatePreviousNext();
224 void checkRule(CSubRule
*rule
, size_t index
, size_t currentToken
, TSubRuleTracerList
&childTracers
);
225 void checkRules(size_t currentToken
);
227 NLMISC::CSmartPtr
<CSubRuleTracer
> codifyTree();
229 void generateCode(NLMISC::CSmartPtr
<AIVM::CByteCode
> &cByteCode
) const;
231 /// Returns a chain specifying the params this way: ffsf for (float, float, string, float)
232 const CSubRuleTracer
*getChildForName(const std::string
&name
) const;
233 void getSignature(std::string
&signature
, bool inOtherWiseOut
) const;
234 size_t getNbChildNamed(const std::string
&name
) const;
236 CSubRuleTracer
*getHigherParent ();
237 CSubRuleTracer
*getNextLower() const;
239 void removePrevious(CSubRuleTracer
*tracer
);
240 void removeNext (CSubRuleTracer
*tracer
);
241 void removeParent (CSubRuleTracer
*tracer
);
242 void removeChild (CSubRuleTracer
*tracer
);
244 void detachFromEveryBody();
246 void iterateToMarkValidTracer();
247 void removeInvalidTracers();
251 void dump(size_t indent
) const;
255 std::string _TextValue
;
257 size_t _index
; ///< Index in the subrule.
259 size_t _tokenStartIndex
;
264 //////////////////////////////////////////////////////////////////////////////
265 // All Links are Directs.
267 NLMISC::CSmartPtr
<CSubRule
> _subRule
;
269 typedef std::set
<NLMISC::CSmartPtr
<CSubRuleTracer
> > TTracersSet
;
270 typedef std::map
<size_t, TTracersSet
> TOrderedTracers
;
272 static TOrderedTracers _PreviousTracers
;
273 static TOrderedTracers _NextTracers
;
275 TSubRuleTracerList _parentTracers
;
276 TSubRuleTracerList _childTracers
;
279 //////////////////////////////////////////////////////////////////////////////
284 typedef std::map
<NLMISC::TStringId
, NLMISC::CSmartPtr
<CScriptNativeFuncParams
> > TNativeFuncMap
;
285 typedef std::vector
<NLMISC::CSmartPtr
<CRule
> > TRuleList
;
286 typedef std::map
<std::string
, AIVM::CScriptVM::EOpcode
> TOpcodeMap
;
289 virtual ~CCompiler() { }
291 NLMISC::CSmartPtr
<AIVM::CByteCode
const> compileCode(std::string
const& sourceCode
, std::string
const& fullName
) const;
292 NLMISC::CSmartPtr
<AIVM::CByteCode
const> compileCode(std::vector
<std::string
> const& sourceCodeLines
, std::string
const& fullName
) const;
294 // New compiler using lex & yacc
295 NLMISC::CSmartPtr
<AIVM::CByteCode
const> compileCodeYacc(std::string
const& sourceCode
, std::string
const& fullName
, bool dump
, bool win32report
) const;
298 NLMISC::CSmartPtr
<AIVM::CByteCode
const> compileCodeOld(std::string
const& sourceCode
, std::string
const& fullName
, bool dump
) const;
300 // Dump the source and the bytecode for debugging
301 void dumpByteCode(std::string
const& sourceCode
, std::string
const& fullName
, NLMISC::CSmartPtr
<AIVM::CByteCode
const> &byteCode
, std::string
const& directory
) const;
303 NLMISC::CSmartPtr
<CSubRuleTracer
> buildCodeTree(const std::string
&code
) const;
305 static void registerNativeFunc ();
307 static void addToken(std::string
const& tokenName
, std::string
const& tokenDesc
);
308 static void addRule(std::string
const& ruleName
, std::string
const& ruleDesc
);
309 static void addOpcode(std::string
const& str
, AIVM::CScriptVM::EOpcode
const& op
);
310 static void addNativeFunc(std::string
const& signature
, FScrptNativeFunc
const& foo
);
311 static void addDeprecatedNativeFunc(std::string
const& signature
);
313 static CToken
* getToken (std::string
const& tokenName
);
314 static NLMISC::CSmartPtr
<CRule
> getRule (std::string
const& ruleName
);
315 static bool getNextToken (std::string
const& text
, size_t& index
, std::string
& tokenName
, std::string
& textValue
);
316 static std::string
const& getOpcodeName (AIVM::CScriptVM::EOpcode
const& op
);
317 static AIVM::CScriptVM::EOpcode
getOpcodeAndValue (std::string
const& str
, std::string
& value
);
318 static CScriptNativeFuncParams
* getNativeFunc (std::string
const& funcName
, std::string
const& inparams
, std::string
const& outparams
);
320 static CCompiler
& getInstance()
323 _Instance
= new CCompiler();
326 static TNativeFuncMap
const& getFunctionList() { return _NativeFunctions
; }
328 typedef std::vector
<NLMISC::CSmartPtr
<CToken
> > TTokenList
;
330 static TRuleList _Rules
;
331 static TOpcodeMap _Opcodes
;
333 static TNativeFuncMap _NativeFunctions
;
334 static TTokenList _Tokens
;
335 static CCompiler
* _Instance
;
338 /****************************************************************************/
339 /* Inlined functions */
340 /****************************************************************************/
343 EScriptError::EScriptError(const std::string
&text
, size_t index
)
344 : NLMISC::Exception(text
)
349 size_t EScriptError::getIndex() const
355 CTokenTestResult::CTokenTestResult()
360 CTokenTestResult::CTokenTestResult(const NLMISC::CSmartPtr
<CCodeNode
> &codeNode
)
362 , _codeNode(codeNode
)
366 CTokenTestResult::CTokenTestResult(const NLMISC::CSmartPtr
<CCodeNode
> &codeNode
, TBasicTokenTestRes res
)
368 , _codeNode(codeNode
)
372 CTokenTestResult::~CTokenTestResult()
376 bool CTokenTestResult::isValid() const
378 return _res
==BRULE_VALID
;
381 CCodeNode
*CTokenTestResult::getCode () const
386 /****************************************************************************/
388 /****************************************************************************/
390 #define AICOMP_MAX_SIGNATURE 32
395 char Signature
[AICOMP_MAX_SIGNATURE
];
396 bool isFloat () const { return strcmp (Signature
, "f") == 0; }
397 bool isString () const { return strcmp (Signature
, "s") == 0; }
398 bool isBool () const { return strcmp (Signature
, "b") == 0; }
399 const char *getType () const { return isFloat ()?"float":isBool ()?"bool":isString ()?"string":"void"; }
402 // Yacc node for current byte code
403 struct CByteCodeYacc
: public CBaseYacc
405 std::vector
<size_t> *ByteCode
;
408 // Yacc node for a single opcode
409 struct COpcodeYacc
: public CBaseYacc
415 // Yacc node for operators
416 struct COperatorYacc
: public COpcodeYacc
418 const char *Operator
;
421 // Yacc node for byte code tree node, keeping the tree structure
422 struct CByteCodeListYacc
: public CBaseYacc
424 std::list
<std::vector
<size_t> * > *ByteCodeList
;
428 struct CCase
: public CBaseYacc
432 std::vector
<size_t> *ByteCode
;
435 // Yacc node for case
436 struct CCaseYacc
: public CBaseYacc
441 // Yacc node for switch
442 struct CSwitchYacc
: public CBaseYacc
444 std::map
<size_t, CCase
*> *Cases
;
450 extern bool aiCompile (std::vector
<size_t> &dest
, const char *script
, const char *scriptName
, bool win32report
);