1f8a20caad31c99333dc119e9d4eff07a4f112d9
[supertux.git] / external / squirrel / squirrel / sqcompiler.cpp
1 /*\r
2         see copyright notice in squirrel.h\r
3 */\r
4 #include "sqpcheader.h"\r
5 #ifndef NO_COMPILER\r
6 #include <stdarg.h>\r
7 #include <setjmp.h>\r
8 #include "sqopcodes.h"\r
9 #include "sqstring.h"\r
10 #include "sqfuncproto.h"\r
11 #include "sqcompiler.h"\r
12 #include "sqfuncstate.h"\r
13 #include "sqlexer.h"\r
14 #include "sqvm.h"\r
15 #include "sqtable.h"\r
16 \r
17 #define EXPR   1\r
18 #define OBJECT 2\r
19 #define BASE   3\r
20 #define LOCAL  4\r
21 #define OUTER  5\r
22 \r
23 struct SQExpState {\r
24   SQInteger  etype;       /* expr. type; one of EXPR, OBJECT, BASE, OUTER or LOCAL */\r
25   SQInteger  epos;        /* expr. location on stack; -1 for OBJECT and BASE */\r
26   bool       donot_get;   /* signal not to deref the next value */\r
27 };\r
28 \r
29 #define MAX_COMPILER_ERROR_LEN 256\r
30 \r
31 struct SQScope {\r
32         SQInteger outers;\r
33         SQInteger stacksize;\r
34 };\r
35 \r
36 #define BEGIN_SCOPE() SQScope __oldscope__ = _scope; \\r
37                                          _scope.outers = _fs->_outers; \\r
38                                          _scope.stacksize = _fs->GetStackSize();\r
39 \r
40 #define RESOLVE_OUTERS() if(_fs->GetStackSize() != _scope.stacksize) { \\r
41                                                         if(_fs->CountOuters(_scope.stacksize)) { \\r
42                                                                 _fs->AddInstruction(_OP_CLOSE,0,_scope.stacksize); \\r
43                                                         } \\r
44                                                 }\r
45 \r
46 #define END_SCOPE_NO_CLOSE() {  if(_fs->GetStackSize() != _scope.stacksize) { \\r
47                                                         _fs->SetStackSize(_scope.stacksize); \\r
48                                                 } \\r
49                                                 _scope = __oldscope__; \\r
50                                         }\r
51 \r
52 #define END_SCOPE() {   SQInteger oldouters = _fs->_outers;\\r
53                                                 if(_fs->GetStackSize() != _scope.stacksize) { \\r
54                                                         _fs->SetStackSize(_scope.stacksize); \\r
55                                                         if(oldouters != _fs->_outers) { \\r
56                                                                 _fs->AddInstruction(_OP_CLOSE,0,_scope.stacksize); \\r
57                                                         } \\r
58                                                 } \\r
59                                                 _scope = __oldscope__; \\r
60                                         }\r
61 \r
62 #define BEGIN_BREAKBLE_BLOCK()  SQInteger __nbreaks__=_fs->_unresolvedbreaks.size(); \\r
63                                                         SQInteger __ncontinues__=_fs->_unresolvedcontinues.size(); \\r
64                                                         _fs->_breaktargets.push_back(0);_fs->_continuetargets.push_back(0);\r
65 \r
66 #define END_BREAKBLE_BLOCK(continue_target) {__nbreaks__=_fs->_unresolvedbreaks.size()-__nbreaks__; \\r
67                                         __ncontinues__=_fs->_unresolvedcontinues.size()-__ncontinues__; \\r
68                                         if(__ncontinues__>0)ResolveContinues(_fs,__ncontinues__,continue_target); \\r
69                                         if(__nbreaks__>0)ResolveBreaks(_fs,__nbreaks__); \\r
70                                         _fs->_breaktargets.pop_back();_fs->_continuetargets.pop_back();}\r
71 \r
72 class SQCompiler\r
73 {\r
74 public:\r
75         SQCompiler(SQVM *v, SQLEXREADFUNC rg, SQUserPointer up, const SQChar* sourcename, bool raiseerror, bool lineinfo)\r
76         {\r
77                 _vm=v;\r
78                 _lex.Init(_ss(v), rg, up,ThrowError,this);\r
79                 _sourcename = SQString::Create(_ss(v), sourcename);\r
80                 _lineinfo = lineinfo;_raiseerror = raiseerror;\r
81                 _scope.outers = 0;\r
82                 _scope.stacksize = 0;\r
83                 _compilererror[0] = NULL;\r
84         }\r
85         static void ThrowError(void *ud, const SQChar *s) {\r
86                 SQCompiler *c = (SQCompiler *)ud;\r
87                 c->Error(s);\r
88         }\r
89         void Error(const SQChar *s, ...)\r
90         {\r
91                 va_list vl;\r
92                 va_start(vl, s);\r
93                 scvsprintf(_compilererror, s, vl);\r
94                 va_end(vl);\r
95                 longjmp(_errorjmp,1);\r
96         }\r
97         void Lex(){     _token = _lex.Lex();}\r
98         SQObject Expect(SQInteger tok)\r
99         {\r
100                 \r
101                 if(_token != tok) {\r
102                         if(_token == TK_CONSTRUCTOR && tok == TK_IDENTIFIER) {\r
103                                 //do nothing\r
104                         }\r
105                         else {\r
106                                 const SQChar *etypename;\r
107                                 if(tok > 255) {\r
108                                         switch(tok)\r
109                                         {\r
110                                         case TK_IDENTIFIER:\r
111                                                 etypename = _SC("IDENTIFIER");\r
112                                                 break;\r
113                                         case TK_STRING_LITERAL:\r
114                                                 etypename = _SC("STRING_LITERAL");\r
115                                                 break;\r
116                                         case TK_INTEGER:\r
117                                                 etypename = _SC("INTEGER");\r
118                                                 break;\r
119                                         case TK_FLOAT:\r
120                                                 etypename = _SC("FLOAT");\r
121                                                 break;\r
122                                         default:\r
123                                                 etypename = _lex.Tok2Str(tok);\r
124                                         }\r
125                                         Error(_SC("expected '%s'"), etypename);\r
126                                 }\r
127                                 Error(_SC("expected '%c'"), tok);\r
128                         }\r
129                 }\r
130                 SQObjectPtr ret;\r
131                 switch(tok)\r
132                 {\r
133                 case TK_IDENTIFIER:\r
134                         ret = _fs->CreateString(_lex._svalue);\r
135                         break;\r
136                 case TK_STRING_LITERAL:\r
137                         ret = _fs->CreateString(_lex._svalue,_lex._longstr.size()-1);\r
138                         break;\r
139                 case TK_INTEGER:\r
140                         ret = SQObjectPtr(_lex._nvalue);\r
141                         break;\r
142                 case TK_FLOAT:\r
143                         ret = SQObjectPtr(_lex._fvalue);\r
144                         break;\r
145                 }\r
146                 Lex();\r
147                 return ret;\r
148         }\r
149         bool IsEndOfStatement() { return ((_lex._prevtoken == _SC('\n')) || (_token == SQUIRREL_EOB) || (_token == _SC('}')) || (_token == _SC(';'))); }\r
150         void OptionalSemicolon()\r
151         {\r
152                 if(_token == _SC(';')) { Lex(); return; }\r
153                 if(!IsEndOfStatement()) {\r
154                         Error(_SC("end of statement expected (; or lf)"));\r
155                 }\r
156         }\r
157         void MoveIfCurrentTargetIsLocal() {\r
158                 SQInteger trg = _fs->TopTarget();\r
159                 if(_fs->IsLocal(trg)) {\r
160                         trg = _fs->PopTarget(); //no pops the target and move it\r
161                         _fs->AddInstruction(_OP_MOVE, _fs->PushTarget(), trg);\r
162                 }\r
163         }\r
164         bool Compile(SQObjectPtr &o)\r
165         {\r
166                 _debugline = 1;\r
167                 _debugop = 0;\r
168 \r
169                 SQFuncState funcstate(_ss(_vm), NULL,ThrowError,this);\r
170                 funcstate._name = SQString::Create(_ss(_vm), _SC("main"));\r
171                 _fs = &funcstate;\r
172                 _fs->AddParameter(_fs->CreateString(_SC("this")));\r
173                 _fs->AddParameter(_fs->CreateString(_SC("vargv")));\r
174                 _fs->_varparams = true;\r
175                 _fs->_sourcename = _sourcename;\r
176                 SQInteger stacksize = _fs->GetStackSize();\r
177                 if(setjmp(_errorjmp) == 0) {\r
178                         Lex();\r
179                         while(_token > 0){\r
180                                 Statement();\r
181                                 if(_lex._prevtoken != _SC('}') && _lex._prevtoken != _SC(';')) OptionalSemicolon();\r
182                         }\r
183                         _fs->SetStackSize(stacksize);\r
184                         _fs->AddLineInfos(_lex._currentline, _lineinfo, true);\r
185                         _fs->AddInstruction(_OP_RETURN, 0xFF);\r
186                         _fs->SetStackSize(0);\r
187                         o =_fs->BuildProto();\r
188 #ifdef _DEBUG_DUMP\r
189                         _fs->Dump(_funcproto(o));\r
190 #endif\r
191                 }\r
192                 else {\r
193                         if(_raiseerror && _ss(_vm)->_compilererrorhandler) {\r
194                                 _ss(_vm)->_compilererrorhandler(_vm, _compilererror, type(_sourcename) == OT_STRING?_stringval(_sourcename):_SC("unknown"),\r
195                                         _lex._currentline, _lex._currentcolumn);\r
196                         }\r
197                         _vm->_lasterror = SQString::Create(_ss(_vm), _compilererror, -1);\r
198                         return false;\r
199                 }\r
200                 return true;\r
201         }\r
202         void Statements()\r
203         {\r
204                 while(_token != _SC('}') && _token != TK_DEFAULT && _token != TK_CASE) {\r
205                         Statement();\r
206                         if(_lex._prevtoken != _SC('}') && _lex._prevtoken != _SC(';')) OptionalSemicolon();\r
207                 }\r
208         }\r
209         void Statement(bool closeframe = true)\r
210         {\r
211                 _fs->AddLineInfos(_lex._currentline, _lineinfo);\r
212                 switch(_token){\r
213                 case _SC(';'):  Lex();                                  break;\r
214                 case TK_IF:             IfStatement();                  break;\r
215                 case TK_WHILE:          WhileStatement();               break;\r
216                 case TK_DO:             DoWhileStatement();             break;\r
217                 case TK_FOR:            ForStatement();                 break;\r
218                 case TK_FOREACH:        ForEachStatement();             break;\r
219                 case TK_SWITCH: SwitchStatement();              break;\r
220                 case TK_LOCAL:          LocalDeclStatement();   break;\r
221                 case TK_RETURN:\r
222                 case TK_YIELD: {\r
223                         SQOpcode op;\r
224                         if(_token == TK_RETURN) {\r
225                                 op = _OP_RETURN;\r
226                         }\r
227                         else {\r
228                                 op = _OP_YIELD;\r
229                                 _fs->_bgenerator = true;\r
230                         }\r
231                         Lex();\r
232                         if(!IsEndOfStatement()) {\r
233                                 SQInteger retexp = _fs->GetCurrentPos()+1;\r
234                                 CommaExpr();\r
235                                 if(op == _OP_RETURN && _fs->_traps > 0)\r
236                                         _fs->AddInstruction(_OP_POPTRAP, _fs->_traps, 0);\r
237                                 _fs->_returnexp = retexp;\r
238                                 _fs->AddInstruction(op, 1, _fs->PopTarget(),_fs->GetStackSize());\r
239                         }\r
240                         else{ \r
241                                 if(op == _OP_RETURN && _fs->_traps > 0)\r
242                                         _fs->AddInstruction(_OP_POPTRAP, _fs->_traps ,0);\r
243                                 _fs->_returnexp = -1;\r
244                                 _fs->AddInstruction(op, 0xFF,0,_fs->GetStackSize()); \r
245                         }\r
246                         break;}\r
247                 case TK_BREAK:\r
248                         if(_fs->_breaktargets.size() <= 0)Error(_SC("'break' has to be in a loop block"));\r
249                         if(_fs->_breaktargets.top() > 0){\r
250                                 _fs->AddInstruction(_OP_POPTRAP, _fs->_breaktargets.top(), 0);\r
251                         }\r
252                         RESOLVE_OUTERS();\r
253                         _fs->AddInstruction(_OP_JMP, 0, -1234);\r
254                         _fs->_unresolvedbreaks.push_back(_fs->GetCurrentPos());\r
255                         Lex();\r
256                         break;\r
257                 case TK_CONTINUE:\r
258                         if(_fs->_continuetargets.size() <= 0)Error(_SC("'continue' has to be in a loop block"));\r
259                         if(_fs->_continuetargets.top() > 0) {\r
260                                 _fs->AddInstruction(_OP_POPTRAP, _fs->_continuetargets.top(), 0);\r
261                         }\r
262                         RESOLVE_OUTERS();\r
263                         _fs->AddInstruction(_OP_JMP, 0, -1234);\r
264                         _fs->_unresolvedcontinues.push_back(_fs->GetCurrentPos());\r
265                         Lex();\r
266                         break;\r
267                 case TK_FUNCTION:\r
268                         FunctionStatement();\r
269                         break;\r
270                 case TK_CLASS:\r
271                         ClassStatement();\r
272                         break;\r
273                 case TK_ENUM:\r
274                         EnumStatement();\r
275                         break;\r
276                 case _SC('{'):{\r
277                                 BEGIN_SCOPE();\r
278                                 Lex();\r
279                                 Statements();\r
280                                 Expect(_SC('}'));\r
281                                 if(closeframe) {\r
282                                         END_SCOPE();\r
283                                 }\r
284                                 else {\r
285                                         END_SCOPE_NO_CLOSE();\r
286                                 }\r
287                         }\r
288                         break;\r
289                 case TK_TRY:\r
290                         TryCatchStatement();\r
291                         break;\r
292                 case TK_THROW:\r
293                         Lex();\r
294                         CommaExpr();\r
295                         _fs->AddInstruction(_OP_THROW, _fs->PopTarget());\r
296                         break;\r
297                 case TK_CONST:\r
298                         {\r
299                         Lex();\r
300                         SQObject id = Expect(TK_IDENTIFIER);\r
301                         Expect('=');\r
302                         SQObject val = ExpectScalar();\r
303                         OptionalSemicolon();\r
304                         SQTable *enums = _table(_ss(_vm)->_consts);\r
305                         SQObjectPtr strongid = id; \r
306                         enums->NewSlot(strongid,SQObjectPtr(val));\r
307                         strongid.Null();\r
308                         }\r
309                         break;\r
310                 default:\r
311                         CommaExpr();\r
312                         _fs->DiscardTarget();\r
313                         //_fs->PopTarget();\r
314                         break;\r
315                 }\r
316                 _fs->SnoozeOpt();\r
317         }\r
318         void EmitDerefOp(SQOpcode op)\r
319         {\r
320                 SQInteger val = _fs->PopTarget();\r
321                 SQInteger key = _fs->PopTarget();\r
322                 SQInteger src = _fs->PopTarget();\r
323         _fs->AddInstruction(op,_fs->PushTarget(),src,key,val);\r
324         }\r
325         void Emit2ArgsOP(SQOpcode op, SQInteger p3 = 0)\r
326         {\r
327                 SQInteger p2 = _fs->PopTarget(); //src in OP_GET\r
328                 SQInteger p1 = _fs->PopTarget(); //key in OP_GET\r
329                 _fs->AddInstruction(op,_fs->PushTarget(), p1, p2, p3);\r
330         }\r
331         void EmitCompoundArith(SQInteger tok, SQInteger etype, SQInteger pos)\r
332         {\r
333                 /* Generate code depending on the expression type */\r
334                 switch(etype) {\r
335                 case LOCAL:{\r
336                         SQInteger p2 = _fs->PopTarget(); //src in OP_GET\r
337                         SQInteger p1 = _fs->PopTarget(); //key in OP_GET\r
338                         _fs->PushTarget(p1);\r
339                         //EmitCompArithLocal(tok, p1, p1, p2);\r
340                         _fs->AddInstruction(ChooseArithOpByToken(tok),p1, p2, p1, 0);\r
341                         _fs->SnoozeOpt();\r
342                                    }\r
343                         break;\r
344                 case OBJECT:\r
345                 case BASE:\r
346                         {\r
347                                 SQInteger val = _fs->PopTarget();\r
348                                 SQInteger key = _fs->PopTarget();\r
349                                 SQInteger src = _fs->PopTarget();\r
350                                 /* _OP_COMPARITH mixes dest obj and source val in the arg1 */\r
351                                 _fs->AddInstruction(_OP_COMPARITH, _fs->PushTarget(), (src<<16)|val, key, ChooseCompArithCharByToken(tok));\r
352                         }\r
353                         break;\r
354                 case OUTER:\r
355                         {\r
356                                 SQInteger val = _fs->TopTarget();\r
357                                 SQInteger tmp = _fs->PushTarget();\r
358                                 _fs->AddInstruction(_OP_GETOUTER,   tmp, pos);\r
359                                 _fs->AddInstruction(ChooseArithOpByToken(tok), tmp, val, tmp, 0);\r
360                                 _fs->AddInstruction(_OP_SETOUTER, tmp, pos, tmp);\r
361                         }\r
362                         break;\r
363                 }\r
364         }\r
365         void CommaExpr()\r
366         {\r
367                 for(Expression();_token == ',';_fs->PopTarget(), Lex(), CommaExpr());\r
368         }\r
369         void Expression()\r
370         {\r
371                  SQExpState es = _es;\r
372                 _es.etype     = EXPR;\r
373                 _es.epos      = -1;\r
374                 _es.donot_get = false;\r
375                 LogicalOrExp();\r
376                 switch(_token)  {\r
377                 case _SC('='):\r
378                 case TK_NEWSLOT:\r
379                 case TK_MINUSEQ:\r
380                 case TK_PLUSEQ:\r
381                 case TK_MULEQ:\r
382                 case TK_DIVEQ:\r
383                 case TK_MODEQ:{\r
384                         SQInteger op = _token;\r
385                         SQInteger ds = _es.etype;\r
386                         SQInteger pos = _es.epos;\r
387                         if(ds == EXPR) Error(_SC("can't assign expression"));\r
388                         else if(ds == BASE) Error(_SC("'base' cannot be modified"));\r
389 \r
390                         Lex(); Expression();\r
391 \r
392                         switch(op){\r
393                         case TK_NEWSLOT:\r
394                                 if(ds == OBJECT || ds == BASE)\r
395                                         EmitDerefOp(_OP_NEWSLOT);\r
396                                 else //if _derefstate != DEREF_NO_DEREF && DEREF_FIELD so is the index of a local\r
397                                         Error(_SC("can't 'create' a local slot"));\r
398                                 break;\r
399                         case _SC('='): //ASSIGN\r
400                                 switch(ds) {\r
401                                 case LOCAL:\r
402                                         {\r
403                                                 SQInteger src = _fs->PopTarget();\r
404                                                 SQInteger dst = _fs->TopTarget();\r
405                                                 _fs->AddInstruction(_OP_MOVE, dst, src);\r
406                                         }\r
407                                         break;\r
408                                 case OBJECT:\r
409                                 case BASE:\r
410                                         EmitDerefOp(_OP_SET);\r
411                                         break;\r
412                                 case OUTER:\r
413                                         {\r
414                                                 SQInteger src = _fs->PopTarget();\r
415                                                 SQInteger dst = _fs->PushTarget();\r
416                                                 _fs->AddInstruction(_OP_SETOUTER, dst, pos, src);\r
417                                         }\r
418                                 }\r
419                                 break;\r
420                         case TK_MINUSEQ:\r
421                         case TK_PLUSEQ:\r
422                         case TK_MULEQ:\r
423                         case TK_DIVEQ:\r
424                         case TK_MODEQ:\r
425                                 EmitCompoundArith(op, ds, pos);\r
426                                 break;\r
427                         }\r
428                         }\r
429                         break;\r
430                 case _SC('?'): {\r
431                         Lex();\r
432                         _fs->AddInstruction(_OP_JZ, _fs->PopTarget());\r
433                         SQInteger jzpos = _fs->GetCurrentPos();\r
434                         SQInteger trg = _fs->PushTarget();\r
435                         Expression();\r
436                         SQInteger first_exp = _fs->PopTarget();\r
437                         if(trg != first_exp) _fs->AddInstruction(_OP_MOVE, trg, first_exp);\r
438                         SQInteger endfirstexp = _fs->GetCurrentPos();\r
439                         _fs->AddInstruction(_OP_JMP, 0, 0);\r
440                         Expect(_SC(':'));\r
441                         SQInteger jmppos = _fs->GetCurrentPos();\r
442                         Expression();\r
443                         SQInteger second_exp = _fs->PopTarget();\r
444                         if(trg != second_exp) _fs->AddInstruction(_OP_MOVE, trg, second_exp);\r
445                         _fs->SetIntructionParam(jmppos, 1, _fs->GetCurrentPos() - jmppos);\r
446                         _fs->SetIntructionParam(jzpos, 1, endfirstexp - jzpos + 1);\r
447                         _fs->SnoozeOpt();\r
448                         }\r
449                         break;\r
450                 }\r
451                 _es = es;\r
452         }\r
453         template<typename T> void INVOKE_EXP(T f)\r
454         {\r
455                 SQExpState es = _es;\r
456                 _es.etype     = EXPR;\r
457                 _es.epos      = -1;\r
458                 _es.donot_get = false;\r
459                 (this->*f)();\r
460                 _es = es;\r
461         }\r
462         template<typename T> void BIN_EXP(SQOpcode op, T f,SQInteger op3 = 0)\r
463         {\r
464                 Lex(); \r
465                 INVOKE_EXP(f);\r
466                 SQInteger op1 = _fs->PopTarget();SQInteger op2 = _fs->PopTarget();\r
467                 _fs->AddInstruction(op, _fs->PushTarget(), op1, op2, op3);\r
468         }\r
469         void LogicalOrExp()\r
470         {\r
471                 LogicalAndExp();\r
472                 for(;;) if(_token == TK_OR) {\r
473                         SQInteger first_exp = _fs->PopTarget();\r
474                         SQInteger trg = _fs->PushTarget();\r
475                         _fs->AddInstruction(_OP_OR, trg, 0, first_exp, 0);\r
476                         SQInteger jpos = _fs->GetCurrentPos();\r
477                         if(trg != first_exp) _fs->AddInstruction(_OP_MOVE, trg, first_exp);\r
478                         Lex(); INVOKE_EXP(&SQCompiler::LogicalOrExp);\r
479                         _fs->SnoozeOpt();\r
480                         SQInteger second_exp = _fs->PopTarget();\r
481                         if(trg != second_exp) _fs->AddInstruction(_OP_MOVE, trg, second_exp);\r
482                         _fs->SnoozeOpt();\r
483                         _fs->SetIntructionParam(jpos, 1, (_fs->GetCurrentPos() - jpos));\r
484                         break;\r
485                 }else return;\r
486         }\r
487         void LogicalAndExp()\r
488         {\r
489                 BitwiseOrExp();\r
490                 for(;;) switch(_token) {\r
491                 case TK_AND: {\r
492                         SQInteger first_exp = _fs->PopTarget();\r
493                         SQInteger trg = _fs->PushTarget();\r
494                         _fs->AddInstruction(_OP_AND, trg, 0, first_exp, 0);\r
495                         SQInteger jpos = _fs->GetCurrentPos();\r
496                         if(trg != first_exp) _fs->AddInstruction(_OP_MOVE, trg, first_exp);\r
497                         Lex(); INVOKE_EXP(&SQCompiler::LogicalAndExp);\r
498                         _fs->SnoozeOpt();\r
499                         SQInteger second_exp = _fs->PopTarget();\r
500                         if(trg != second_exp) _fs->AddInstruction(_OP_MOVE, trg, second_exp);\r
501                         _fs->SnoozeOpt();\r
502                         _fs->SetIntructionParam(jpos, 1, (_fs->GetCurrentPos() - jpos));\r
503                         break;\r
504                         }\r
505     \r
506                 default:\r
507                         return;\r
508                 }\r
509         }\r
510         void BitwiseOrExp()\r
511         {\r
512                 BitwiseXorExp();\r
513                 for(;;) if(_token == _SC('|'))\r
514                 {BIN_EXP(_OP_BITW, &SQCompiler::BitwiseXorExp,BW_OR);\r
515                 }else return;\r
516         }\r
517         void BitwiseXorExp()\r
518         {\r
519                 BitwiseAndExp();\r
520                 for(;;) if(_token == _SC('^'))\r
521                 {BIN_EXP(_OP_BITW, &SQCompiler::BitwiseAndExp,BW_XOR);\r
522                 }else return;\r
523         }\r
524         void BitwiseAndExp()\r
525         {\r
526                 EqExp();\r
527                 for(;;) if(_token == _SC('&'))\r
528                 {BIN_EXP(_OP_BITW, &SQCompiler::EqExp,BW_AND);\r
529                 }else return;\r
530         }\r
531         void EqExp()\r
532         {\r
533                 CompExp();\r
534                 for(;;) switch(_token) {\r
535                 case TK_EQ: BIN_EXP(_OP_EQ, &SQCompiler::CompExp); break;\r
536                 case TK_NE: BIN_EXP(_OP_NE, &SQCompiler::CompExp); break;\r
537                 case TK_3WAYSCMP: BIN_EXP(_OP_CMP, &SQCompiler::CompExp,CMP_3W); break;\r
538                 default: return;        \r
539                 }\r
540         }\r
541         void CompExp()\r
542         {\r
543                 ShiftExp();\r
544                 for(;;) switch(_token) {\r
545                 case _SC('>'): BIN_EXP(_OP_CMP, &SQCompiler::ShiftExp,CMP_G); break;\r
546                 case _SC('<'): BIN_EXP(_OP_CMP, &SQCompiler::ShiftExp,CMP_L); break;\r
547                 case TK_GE: BIN_EXP(_OP_CMP, &SQCompiler::ShiftExp,CMP_GE); break;\r
548                 case TK_LE: BIN_EXP(_OP_CMP, &SQCompiler::ShiftExp,CMP_LE); break;\r
549                 case TK_IN: BIN_EXP(_OP_EXISTS, &SQCompiler::ShiftExp); break;\r
550                 case TK_INSTANCEOF: BIN_EXP(_OP_INSTANCEOF, &SQCompiler::ShiftExp); break;\r
551                 default: return;        \r
552                 }\r
553         }\r
554         void ShiftExp()\r
555         {\r
556                 PlusExp();\r
557                 for(;;) switch(_token) {\r
558                 case TK_USHIFTR: BIN_EXP(_OP_BITW, &SQCompiler::PlusExp,BW_USHIFTR); break;\r
559                 case TK_SHIFTL: BIN_EXP(_OP_BITW, &SQCompiler::PlusExp,BW_SHIFTL); break;\r
560                 case TK_SHIFTR: BIN_EXP(_OP_BITW, &SQCompiler::PlusExp,BW_SHIFTR); break;\r
561                 default: return;        \r
562                 }\r
563         }\r
564         SQOpcode ChooseArithOpByToken(SQInteger tok)\r
565         {\r
566                 switch(tok) {\r
567                         case TK_PLUSEQ: case '+': return _OP_ADD;\r
568                         case TK_MINUSEQ: case '-': return _OP_SUB;\r
569                         case TK_MULEQ: case '*': return _OP_MUL;\r
570                         case TK_DIVEQ: case '/': return _OP_DIV;\r
571                         case TK_MODEQ: case '%': return _OP_MOD;\r
572                         default: assert(0);\r
573                 }\r
574                 return _OP_ADD;\r
575         }\r
576         SQInteger ChooseCompArithCharByToken(SQInteger tok)\r
577         {\r
578                 SQInteger oper;\r
579                 switch(tok){\r
580                 case TK_MINUSEQ: oper = '-'; break;\r
581                 case TK_PLUSEQ: oper = '+'; break;\r
582                 case TK_MULEQ: oper = '*'; break;\r
583                 case TK_DIVEQ: oper = '/'; break;\r
584                 case TK_MODEQ: oper = '%'; break;\r
585                 default: oper = 0; //shut up compiler\r
586                         assert(0); break;\r
587                 };\r
588                 return oper;\r
589         }\r
590         void PlusExp()\r
591         {\r
592                 MultExp();\r
593                 for(;;) switch(_token) {\r
594                 case _SC('+'): case _SC('-'):\r
595                         BIN_EXP(ChooseArithOpByToken(_token), &SQCompiler::MultExp); break;\r
596                 default: return;\r
597                 }\r
598         }\r
599         \r
600         void MultExp()\r
601         {\r
602                 PrefixedExpr();\r
603                 for(;;) switch(_token) {\r
604                 case _SC('*'): case _SC('/'): case _SC('%'):\r
605                         BIN_EXP(ChooseArithOpByToken(_token), &SQCompiler::PrefixedExpr); break;\r
606                 default: return;\r
607                 }\r
608         }\r
609         //if 'pos' != -1 the previous variable is a local variable\r
610         void PrefixedExpr()\r
611         {\r
612                 SQInteger pos = Factor();\r
613                 for(;;) {\r
614                         switch(_token) {\r
615                         case _SC('.'):\r
616                                 pos = -1;\r
617                                 Lex(); \r
618 \r
619                                 _fs->AddInstruction(_OP_LOAD, _fs->PushTarget(), _fs->GetConstant(Expect(TK_IDENTIFIER)));\r
620                                 if(_es.etype==BASE) {\r
621                                         Emit2ArgsOP(_OP_GET);\r
622                                         pos = _fs->TopTarget();\r
623                                         _es.etype = EXPR;\r
624                                         _es.epos   = pos;\r
625                                 }\r
626                                 else {\r
627                                         if(NeedGet()) {\r
628                                                 Emit2ArgsOP(_OP_GET);\r
629                                         }\r
630                                         _es.etype = OBJECT;\r
631                                 }\r
632                                 break;\r
633                         case _SC('['):\r
634                                 if(_lex._prevtoken == _SC('\n')) Error(_SC("cannot brake deref/or comma needed after [exp]=exp slot declaration"));\r
635                                 Lex(); Expression(); Expect(_SC(']')); \r
636                                 pos = -1;\r
637                                 if(_es.etype==BASE) {\r
638                                         Emit2ArgsOP(_OP_GET);\r
639                                         pos = _fs->TopTarget();\r
640                                         _es.etype = EXPR;\r
641                                         _es.epos   = pos;\r
642                                 }\r
643                                 else {\r
644                                         if(NeedGet()) {\r
645                                                 Emit2ArgsOP(_OP_GET);\r
646                                         }\r
647                                         _es.etype = OBJECT;\r
648                                 }\r
649                                 break;\r
650                         case TK_MINUSMINUS:\r
651                         case TK_PLUSPLUS:\r
652                                 {\r
653                                         if(IsEndOfStatement()) return;\r
654                                         SQInteger diff = (_token==TK_MINUSMINUS) ? -1 : 1;\r
655                                         Lex();\r
656                                         switch(_es.etype)\r
657                                         {\r
658                                                 case EXPR: Error(_SC("can't '++' or '--' an expression")); break;\r
659                                                 case OBJECT:\r
660                                                 case BASE:\r
661                                                         Emit2ArgsOP(_OP_PINC, diff);\r
662                                                         break;\r
663                                                 case LOCAL: {\r
664                                                         SQInteger src = _fs->PopTarget();\r
665                                                         _fs->AddInstruction(_OP_PINCL, _fs->PushTarget(), src, 0, diff);\r
666                                                                         }\r
667                                                         break;\r
668                                                 case OUTER: {\r
669                                                         SQInteger tmp1 = _fs->PushTarget();\r
670                                                         SQInteger tmp2 = _fs->PushTarget();\r
671                                                         _fs->AddInstruction(_OP_GETOUTER, tmp2, _es.epos);\r
672                                                         _fs->AddInstruction(_OP_PINCL,    tmp1, tmp2, 0, diff);\r
673                                                         _fs->AddInstruction(_OP_SETOUTER, tmp2, _es.epos, tmp2);\r
674                                                         _fs->PopTarget();\r
675                                                 }\r
676                                         }\r
677                                 }\r
678                                 return;\r
679                                 break;  \r
680                         case _SC('('): \r
681                                 switch(_es.etype) {\r
682                                         case OBJECT: {\r
683                                                 SQInteger key     = _fs->PopTarget();  /* location of the key */\r
684                                                 SQInteger table   = _fs->PopTarget();  /* location of the object */\r
685                                                 SQInteger closure = _fs->PushTarget(); /* location for the closure */\r
686                                                 SQInteger ttarget = _fs->PushTarget(); /* location for 'this' pointer */\r
687                                                 _fs->AddInstruction(_OP_PREPCALL, closure, key, table, ttarget);\r
688                                                 }\r
689                                                 break;\r
690                                         case BASE:\r
691                                                 //Emit2ArgsOP(_OP_GET);\r
692                                                 _fs->AddInstruction(_OP_MOVE, _fs->PushTarget(), 0);\r
693                                                 break;\r
694                                         case OUTER:\r
695                                                 _fs->AddInstruction(_OP_GETOUTER, _fs->PushTarget(), _es.epos);\r
696                                                 _fs->AddInstruction(_OP_MOVE,     _fs->PushTarget(), 0);\r
697                                                 break;\r
698                                         default:\r
699                                                 _fs->AddInstruction(_OP_MOVE, _fs->PushTarget(), 0);\r
700                                 }\r
701                                 _es.etype = EXPR;\r
702                                 Lex();\r
703                                 FunctionCallArgs();\r
704                                 break;\r
705                         default: return;\r
706                         }\r
707                 }\r
708         }\r
709         SQInteger Factor()\r
710         {\r
711                 _es.etype = EXPR;\r
712                 switch(_token)\r
713                 {\r
714                 case TK_STRING_LITERAL:\r
715                         _fs->AddInstruction(_OP_LOAD, _fs->PushTarget(), _fs->GetConstant(_fs->CreateString(_lex._svalue,_lex._longstr.size()-1)));\r
716                         Lex(); \r
717                         break;\r
718                 case TK_BASE:\r
719                         Lex();\r
720                         _fs->AddInstruction(_OP_GETBASE, _fs->PushTarget());\r
721                         _es.etype  = BASE;\r
722                         _es.epos   = _fs->TopTarget();\r
723                         return (_es.epos);\r
724                         break;\r
725                 case TK_IDENTIFIER:\r
726                 case TK_CONSTRUCTOR:\r
727                 case TK_THIS:{\r
728                                 SQObject id;\r
729                                 SQObject constant;\r
730 \r
731                                 switch(_token) {\r
732                                         case TK_IDENTIFIER:  id = _fs->CreateString(_lex._svalue);       break;\r
733                                         case TK_THIS:        id = _fs->CreateString(_SC("this"));        break;\r
734                                         case TK_CONSTRUCTOR: id = _fs->CreateString(_SC("constructor")); break;\r
735                                 }\r
736 \r
737                                 SQInteger pos = -1;\r
738                                 Lex();\r
739                                 if((pos = _fs->GetLocalVariable(id)) != -1) {\r
740                                         /* Handle a local variable (includes 'this') */\r
741                                         _fs->PushTarget(pos);\r
742                                         _es.etype  = LOCAL;\r
743                                         _es.epos   = pos;\r
744                                 }\r
745 \r
746                                 else if((pos = _fs->GetOuterVariable(id)) != -1) {\r
747                                         /* Handle a free var */\r
748                                         if(NeedGet()) {\r
749                                                 _es.epos  = _fs->PushTarget();\r
750                                                 _fs->AddInstruction(_OP_GETOUTER, _es.epos, pos);       \r
751                                                 /* _es.etype = EXPR; already default value */\r
752                                         }\r
753                                         else {\r
754                                                 _es.etype = OUTER;\r
755                                                 _es.epos  = pos;\r
756                                         }\r
757                                 }\r
758 \r
759                                 else if(_fs->IsConstant(id, constant)) {\r
760                                         /* Handle named constant */\r
761                                         SQObjectPtr constval;\r
762                                         SQObject    constid;\r
763                                         if(type(constant) == OT_TABLE) {\r
764                                                 Expect('.');\r
765                                                 constid = Expect(TK_IDENTIFIER);\r
766                                                 if(!_table(constant)->Get(constid, constval)) {\r
767                                                         constval.Null();\r
768                                                         Error(_SC("invalid constant [%s.%s]"), _stringval(id), _stringval(constid));\r
769                                                 }\r
770                                         }\r
771                                         else {\r
772                                                 constval = constant;\r
773                                         }\r
774                                         _es.epos = _fs->PushTarget();\r
775 \r
776                                         /* generate direct or literal function depending on size */\r
777                                         SQObjectType ctype = type(constval);\r
778                                         switch(ctype) {\r
779                                                 case OT_INTEGER: EmitLoadConstInt(_integer(constval),_es.epos); break;\r
780                                                 case OT_FLOAT: EmitLoadConstFloat(_float(constval),_es.epos); break;\r
781                                                 default: _fs->AddInstruction(_OP_LOAD,_es.epos,_fs->GetConstant(constval)); break;\r
782                                         }\r
783                                         _es.etype = EXPR;\r
784                                 }\r
785                                 else {\r
786                                         /* Handle a non-local variable, aka a field. Push the 'this' pointer on\r
787                                         * the virtual stack (always found in offset 0, so no instruction needs to\r
788                                         * be generated), and push the key next. Generate an _OP_LOAD instruction\r
789                                         * for the latter. If we are not using the variable as a dref expr, generate\r
790                                         * the _OP_GET instruction.\r
791                                         */\r
792                                         _fs->PushTarget(0);\r
793                                         _fs->AddInstruction(_OP_LOAD, _fs->PushTarget(), _fs->GetConstant(id));\r
794                                         if(NeedGet()) {\r
795                                                 Emit2ArgsOP(_OP_GET);\r
796                                         }\r
797                                         _es.etype = OBJECT;\r
798                                 }\r
799                                 return _es.epos;\r
800                         }\r
801                         break;\r
802                 case TK_DOUBLE_COLON:  // "::"\r
803                         _fs->AddInstruction(_OP_LOADROOT, _fs->PushTarget());\r
804                         _es.etype = OBJECT;\r
805                         _token = _SC('.'); /* hack: drop into PrefixExpr, case '.'*/\r
806                         _es.epos = -1;\r
807                         return _es.epos;\r
808                         break;\r
809                 case TK_NULL: \r
810                         _fs->AddInstruction(_OP_LOADNULLS, _fs->PushTarget(),1);\r
811                         Lex();\r
812                         break;\r
813                 case TK_INTEGER: EmitLoadConstInt(_lex._nvalue,-1); Lex();      break;\r
814                 case TK_FLOAT: EmitLoadConstFloat(_lex._fvalue,-1); Lex(); break;\r
815                 case TK_TRUE: case TK_FALSE:\r
816                         _fs->AddInstruction(_OP_LOADBOOL, _fs->PushTarget(),_token == TK_TRUE?1:0);\r
817                         Lex();\r
818                         break;\r
819                 case _SC('['): {\r
820                                 _fs->AddInstruction(_OP_NEWOBJ, _fs->PushTarget(),0,0,NOT_ARRAY);\r
821                                 SQInteger apos = _fs->GetCurrentPos(),key = 0;\r
822                                 Lex();\r
823                                 while(_token != _SC(']')) {\r
824                     Expression(); \r
825                                         if(_token == _SC(',')) Lex();\r
826                                         SQInteger val = _fs->PopTarget();\r
827                                         SQInteger array = _fs->TopTarget();\r
828                                         _fs->AddInstruction(_OP_APPENDARRAY, array, val, AAT_STACK);\r
829                                         key++;\r
830                                 }\r
831                                 _fs->SetIntructionParam(apos, 1, key);\r
832                                 Lex();\r
833                         }\r
834                         break;\r
835                 case _SC('{'):\r
836                         _fs->AddInstruction(_OP_NEWOBJ, _fs->PushTarget(),0,NOT_TABLE);\r
837                         Lex();ParseTableOrClass(_SC(','),_SC('}'));\r
838                         break;\r
839                 case TK_FUNCTION: FunctionExp(_token);break;\r
840                 case _SC('@'): FunctionExp(_token,true);break;\r
841                 case TK_CLASS: Lex(); ClassExp();break;\r
842                 case _SC('-'): \r
843                         Lex(); \r
844                         switch(_token) {\r
845                         case TK_INTEGER: EmitLoadConstInt(-_lex._nvalue,-1); Lex(); break;\r
846                         case TK_FLOAT: EmitLoadConstFloat(-_lex._fvalue,-1); Lex(); break;\r
847                         default: UnaryOP(_OP_NEG);\r
848                         }\r
849                         break;\r
850                 case _SC('!'): Lex(); UnaryOP(_OP_NOT); break;\r
851                 case _SC('~'): \r
852                         Lex(); \r
853                         if(_token == TK_INTEGER)  { EmitLoadConstInt(~_lex._nvalue,-1); Lex(); break; }\r
854                         UnaryOP(_OP_BWNOT); \r
855                         break;\r
856                 case TK_TYPEOF : Lex() ;UnaryOP(_OP_TYPEOF); break;\r
857                 case TK_RESUME : Lex(); UnaryOP(_OP_RESUME); break;\r
858                 case TK_CLONE : Lex(); UnaryOP(_OP_CLONE); break;\r
859                 case TK_MINUSMINUS : \r
860                 case TK_PLUSPLUS :PrefixIncDec(_token); break;\r
861                 case TK_DELETE : DeleteExpr(); break;\r
862                 case _SC('('): Lex(); CommaExpr(); Expect(_SC(')'));\r
863                         break;\r
864                 default: Error(_SC("expression expected"));\r
865                 }\r
866                 return -1;\r
867         }\r
868         void EmitLoadConstInt(SQInteger value,SQInteger target)\r
869         {\r
870                 if(target < 0) {\r
871                         target = _fs->PushTarget();\r
872                 }\r
873                 if((value & (~((SQInteger)0xFFFFFFFF))) == 0) { //does it fit in 32 bits?\r
874                         _fs->AddInstruction(_OP_LOADINT, target,value);\r
875                 }\r
876                 else {\r
877                         _fs->AddInstruction(_OP_LOAD, target, _fs->GetNumericConstant(value));\r
878                 }\r
879         }\r
880         void EmitLoadConstFloat(SQFloat value,SQInteger target)\r
881         {\r
882                 if(target < 0) {\r
883                         target = _fs->PushTarget();\r
884                 }\r
885                 if(sizeof(SQFloat) == sizeof(SQInt32)) {\r
886                         _fs->AddInstruction(_OP_LOADFLOAT, target,*((SQInt32 *)&value));\r
887                 }\r
888                 else {\r
889                         _fs->AddInstruction(_OP_LOAD, target, _fs->GetNumericConstant(value));\r
890                 }\r
891         }\r
892         void UnaryOP(SQOpcode op)\r
893         {\r
894                 PrefixedExpr();\r
895                 SQInteger src = _fs->PopTarget();\r
896                 _fs->AddInstruction(op, _fs->PushTarget(), src);\r
897         }\r
898         bool NeedGet()\r
899         {\r
900                 switch(_token) {\r
901                 case _SC('='): case _SC('('): case TK_NEWSLOT: case TK_MODEQ: case TK_MULEQ:\r
902             case TK_DIVEQ: case TK_MINUSEQ: case TK_PLUSEQ: case TK_PLUSPLUS: case TK_MINUSMINUS:\r
903                         return false;\r
904                 }\r
905                 return (!_es.donot_get || ( _es.donot_get && (_token == _SC('.') || _token == _SC('['))));\r
906         }\r
907         void FunctionCallArgs()\r
908         {\r
909                 SQInteger nargs = 1;//this\r
910                  while(_token != _SC(')')) {\r
911                          Expression();\r
912                          MoveIfCurrentTargetIsLocal();\r
913                          nargs++; \r
914                          if(_token == _SC(',')){ \r
915                                  Lex(); \r
916                                  if(_token == ')') Error(_SC("expression expected, found ')'"));\r
917                          }\r
918                  }\r
919                  Lex();\r
920                  for(SQInteger i = 0; i < (nargs - 1); i++) _fs->PopTarget();\r
921                  SQInteger stackbase = _fs->PopTarget();\r
922                  SQInteger closure = _fs->PopTarget();\r
923          _fs->AddInstruction(_OP_CALL, _fs->PushTarget(), closure, stackbase, nargs);\r
924         }\r
925         void ParseTableOrClass(SQInteger separator,SQInteger terminator)\r
926         {\r
927                 SQInteger tpos = _fs->GetCurrentPos(),nkeys = 0;\r
928                 while(_token != terminator) {\r
929                         bool hasattrs = false;\r
930                         bool isstatic = false;\r
931                         //check if is an attribute\r
932                         if(separator == ';') {\r
933                                 if(_token == TK_ATTR_OPEN) {\r
934                                         _fs->AddInstruction(_OP_NEWOBJ, _fs->PushTarget(),0,NOT_TABLE); Lex();\r
935                                         ParseTableOrClass(',',TK_ATTR_CLOSE);\r
936                                         hasattrs = true;\r
937                                 }\r
938                                 if(_token == TK_STATIC) {\r
939                                         isstatic = true;\r
940                                         Lex();\r
941                                 }\r
942                         }\r
943                         switch(_token) {\r
944                         case TK_FUNCTION:\r
945                         case TK_CONSTRUCTOR:{\r
946                                 SQInteger tk = _token;\r
947                                 Lex();\r
948                                 SQObject id = tk == TK_FUNCTION ? Expect(TK_IDENTIFIER) : _fs->CreateString(_SC("constructor"));\r
949                                 Expect(_SC('('));\r
950                                 _fs->AddInstruction(_OP_LOAD, _fs->PushTarget(), _fs->GetConstant(id));\r
951                                 CreateFunction(id);\r
952                                 _fs->AddInstruction(_OP_CLOSURE, _fs->PushTarget(), _fs->_functions.size() - 1, 0);\r
953                                                                 }\r
954                                                                 break;\r
955                         case _SC('['):\r
956                                 Lex(); CommaExpr(); Expect(_SC(']'));\r
957                                 Expect(_SC('=')); Expression();\r
958                                 break;\r
959                         case TK_STRING_LITERAL: //JSON\r
960                                 if(separator == ',') { //only works for tables\r
961                                         _fs->AddInstruction(_OP_LOAD, _fs->PushTarget(), _fs->GetConstant(Expect(TK_STRING_LITERAL)));\r
962                                         Expect(_SC(':')); Expression();\r
963                                         break;\r
964                                 }\r
965                         default :\r
966                                 _fs->AddInstruction(_OP_LOAD, _fs->PushTarget(), _fs->GetConstant(Expect(TK_IDENTIFIER)));\r
967                                 Expect(_SC('=')); Expression();\r
968                         }\r
969                         if(_token == separator) Lex();//optional comma/semicolon\r
970                         nkeys++;\r
971                         SQInteger val = _fs->PopTarget();\r
972                         SQInteger key = _fs->PopTarget();\r
973                         SQInteger attrs = hasattrs ? _fs->PopTarget():-1;\r
974                         assert((hasattrs && (attrs == key-1)) || !hasattrs);\r
975                         unsigned char flags = (hasattrs?NEW_SLOT_ATTRIBUTES_FLAG:0)|(isstatic?NEW_SLOT_STATIC_FLAG:0);\r
976                         SQInteger table = _fs->TopTarget(); //<<BECAUSE OF THIS NO COMMON EMIT FUNC IS POSSIBLE\r
977                         if(separator == _SC(',')) { //hack recognizes a table from the separator\r
978                                 _fs->AddInstruction(_OP_NEWSLOT, 0xFF, table, key, val);\r
979                         }\r
980                         else {\r
981                                 _fs->AddInstruction(_OP_NEWSLOTA, flags, table, key, val); //this for classes only as it invokes _newmember\r
982                         }\r
983                 }\r
984                 if(separator == _SC(',')) //hack recognizes a table from the separator\r
985                         _fs->SetIntructionParam(tpos, 1, nkeys);\r
986                 Lex();\r
987         }\r
988         void LocalDeclStatement()\r
989         {\r
990                 SQObject varname;\r
991                 Lex();\r
992                 if( _token == TK_FUNCTION) {\r
993                         Lex();\r
994                         varname = Expect(TK_IDENTIFIER);\r
995                         Expect(_SC('('));\r
996                         CreateFunction(varname,false);\r
997                         _fs->AddInstruction(_OP_CLOSURE, _fs->PushTarget(), _fs->_functions.size() - 1, 0);\r
998                         _fs->PopTarget();\r
999                         _fs->PushLocalVariable(varname);\r
1000                         return;\r
1001                 }\r
1002 \r
1003                 do {\r
1004                         varname = Expect(TK_IDENTIFIER);\r
1005                         if(_token == _SC('=')) {\r
1006                                 Lex(); Expression();\r
1007                                 SQInteger src = _fs->PopTarget();\r
1008                                 SQInteger dest = _fs->PushTarget();\r
1009                                 if(dest != src) _fs->AddInstruction(_OP_MOVE, dest, src);\r
1010                         }\r
1011                         else{\r
1012                                 _fs->AddInstruction(_OP_LOADNULLS, _fs->PushTarget(),1);\r
1013                         }\r
1014                         _fs->PopTarget();\r
1015                         _fs->PushLocalVariable(varname);\r
1016                         if(_token == _SC(',')) Lex(); else break;\r
1017                 } while(1);\r
1018         }\r
1019         void IfStatement()\r
1020     {\r
1021         SQInteger jmppos;\r
1022         bool haselse = false;\r
1023         Lex(); Expect(_SC('(')); CommaExpr(); Expect(_SC(')'));\r
1024         _fs->AddInstruction(_OP_JZ, _fs->PopTarget());\r
1025         SQInteger jnepos = _fs->GetCurrentPos();\r
1026         BEGIN_SCOPE();\r
1027         \r
1028         Statement();\r
1029         //\r
1030         if(_token != _SC('}') && _token != TK_ELSE) OptionalSemicolon();\r
1031         \r
1032         END_SCOPE();\r
1033         SQInteger endifblock = _fs->GetCurrentPos();\r
1034         if(_token == TK_ELSE){\r
1035             haselse = true;\r
1036             BEGIN_SCOPE();\r
1037             _fs->AddInstruction(_OP_JMP);\r
1038             jmppos = _fs->GetCurrentPos();\r
1039             Lex();\r
1040             Statement(); if(_lex._prevtoken != _SC('}')) OptionalSemicolon();\r
1041             END_SCOPE();\r
1042             _fs->SetIntructionParam(jmppos, 1, _fs->GetCurrentPos() - jmppos);\r
1043         }\r
1044         _fs->SetIntructionParam(jnepos, 1, endifblock - jnepos + (haselse?1:0));\r
1045     }\r
1046         void WhileStatement()\r
1047         {\r
1048                 SQInteger jzpos, jmppos;\r
1049                 jmppos = _fs->GetCurrentPos();\r
1050                 Lex(); Expect(_SC('(')); CommaExpr(); Expect(_SC(')'));\r
1051                 \r
1052                 BEGIN_BREAKBLE_BLOCK();\r
1053                 _fs->AddInstruction(_OP_JZ, _fs->PopTarget());\r
1054                 jzpos = _fs->GetCurrentPos();\r
1055                 BEGIN_SCOPE();\r
1056                 \r
1057                 Statement();\r
1058                 \r
1059                 END_SCOPE();\r
1060                 _fs->AddInstruction(_OP_JMP, 0, jmppos - _fs->GetCurrentPos() - 1);\r
1061                 _fs->SetIntructionParam(jzpos, 1, _fs->GetCurrentPos() - jzpos);\r
1062                 \r
1063                 END_BREAKBLE_BLOCK(jmppos);\r
1064         }\r
1065         void DoWhileStatement()\r
1066         {\r
1067                 Lex();\r
1068                 SQInteger jmptrg = _fs->GetCurrentPos();\r
1069                 BEGIN_BREAKBLE_BLOCK()\r
1070                 BEGIN_SCOPE();\r
1071                 Statement();\r
1072                 END_SCOPE();\r
1073                 Expect(TK_WHILE);\r
1074                 SQInteger continuetrg = _fs->GetCurrentPos();\r
1075                 Expect(_SC('(')); CommaExpr(); Expect(_SC(')'));\r
1076                 _fs->AddInstruction(_OP_JZ, _fs->PopTarget(), 1);\r
1077                 _fs->AddInstruction(_OP_JMP, 0, jmptrg - _fs->GetCurrentPos() - 1);\r
1078                 END_BREAKBLE_BLOCK(continuetrg);\r
1079         }\r
1080         void ForStatement()\r
1081         {\r
1082                 Lex();\r
1083                 BEGIN_SCOPE();\r
1084                 Expect(_SC('('));\r
1085                 if(_token == TK_LOCAL) LocalDeclStatement();\r
1086                 else if(_token != _SC(';')){\r
1087                         CommaExpr();\r
1088                         _fs->PopTarget();\r
1089                 }\r
1090                 Expect(_SC(';'));\r
1091                 _fs->SnoozeOpt();\r
1092                 SQInteger jmppos = _fs->GetCurrentPos();\r
1093                 SQInteger jzpos = -1;\r
1094                 if(_token != _SC(';')) { CommaExpr(); _fs->AddInstruction(_OP_JZ, _fs->PopTarget()); jzpos = _fs->GetCurrentPos(); }\r
1095                 Expect(_SC(';'));\r
1096                 _fs->SnoozeOpt();\r
1097                 SQInteger expstart = _fs->GetCurrentPos() + 1;\r
1098                 if(_token != _SC(')')) {\r
1099                         CommaExpr();\r
1100                         _fs->PopTarget();\r
1101                 }\r
1102                 Expect(_SC(')'));\r
1103                 _fs->SnoozeOpt();\r
1104                 SQInteger expend = _fs->GetCurrentPos();\r
1105                 SQInteger expsize = (expend - expstart) + 1;\r
1106                 SQInstructionVec exp;\r
1107                 if(expsize > 0) {\r
1108                         for(SQInteger i = 0; i < expsize; i++)\r
1109                                 exp.push_back(_fs->GetInstruction(expstart + i));\r
1110                         _fs->PopInstructions(expsize);\r
1111                 }\r
1112                 BEGIN_BREAKBLE_BLOCK()\r
1113                 Statement();\r
1114                 SQInteger continuetrg = _fs->GetCurrentPos();\r
1115                 if(expsize > 0) {\r
1116                         for(SQInteger i = 0; i < expsize; i++)\r
1117                                 _fs->AddInstruction(exp[i]);\r
1118                 }\r
1119                 _fs->AddInstruction(_OP_JMP, 0, jmppos - _fs->GetCurrentPos() - 1, 0);\r
1120                 if(jzpos>  0) _fs->SetIntructionParam(jzpos, 1, _fs->GetCurrentPos() - jzpos);\r
1121                 END_SCOPE();\r
1122                 \r
1123                 END_BREAKBLE_BLOCK(continuetrg);\r
1124         }\r
1125         void ForEachStatement()\r
1126         {\r
1127                 SQObject idxname, valname;\r
1128                 Lex(); Expect(_SC('(')); valname = Expect(TK_IDENTIFIER);\r
1129                 if(_token == _SC(',')) {\r
1130                         idxname = valname;\r
1131                         Lex(); valname = Expect(TK_IDENTIFIER);\r
1132                 }\r
1133                 else{\r
1134                         idxname = _fs->CreateString(_SC("@INDEX@"));\r
1135                 }\r
1136                 Expect(TK_IN);\r
1137                 \r
1138                 //save the stack size\r
1139                 BEGIN_SCOPE();\r
1140                 //put the table in the stack(evaluate the table expression)\r
1141                 Expression(); Expect(_SC(')'));\r
1142                 SQInteger container = _fs->TopTarget();\r
1143                 //push the index local var\r
1144                 SQInteger indexpos = _fs->PushLocalVariable(idxname);\r
1145                 _fs->AddInstruction(_OP_LOADNULLS, indexpos,1);\r
1146                 //push the value local var\r
1147                 SQInteger valuepos = _fs->PushLocalVariable(valname);\r
1148                 _fs->AddInstruction(_OP_LOADNULLS, valuepos,1);\r
1149                 //push reference index\r
1150                 SQInteger itrpos = _fs->PushLocalVariable(_fs->CreateString(_SC("@ITERATOR@"))); //use invalid id to make it inaccessible\r
1151                 _fs->AddInstruction(_OP_LOADNULLS, itrpos,1);\r
1152                 SQInteger jmppos = _fs->GetCurrentPos();\r
1153                 _fs->AddInstruction(_OP_FOREACH, container, 0, indexpos);\r
1154                 SQInteger foreachpos = _fs->GetCurrentPos();\r
1155                 _fs->AddInstruction(_OP_POSTFOREACH, container, 0, indexpos);\r
1156                 //generate the statement code\r
1157                 BEGIN_BREAKBLE_BLOCK()\r
1158                 Statement();\r
1159                 _fs->AddInstruction(_OP_JMP, 0, jmppos - _fs->GetCurrentPos() - 1);\r
1160                 _fs->SetIntructionParam(foreachpos, 1, _fs->GetCurrentPos() - foreachpos);\r
1161                 _fs->SetIntructionParam(foreachpos + 1, 1, _fs->GetCurrentPos() - foreachpos);\r
1162                 END_BREAKBLE_BLOCK(foreachpos - 1);\r
1163                 //restore the local variable stack(remove index,val and ref idx)\r
1164                 _fs->PopTarget();\r
1165                 END_SCOPE();\r
1166         }\r
1167         void SwitchStatement()\r
1168         {\r
1169                 Lex(); Expect(_SC('(')); CommaExpr(); Expect(_SC(')'));\r
1170                 Expect(_SC('{'));\r
1171                 SQInteger expr = _fs->TopTarget();\r
1172                 bool bfirst = true;\r
1173                 SQInteger tonextcondjmp = -1;\r
1174                 SQInteger skipcondjmp = -1;\r
1175                 SQInteger __nbreaks__ = _fs->_unresolvedbreaks.size();\r
1176                 _fs->_breaktargets.push_back(0);\r
1177                 while(_token == TK_CASE) {\r
1178                         if(!bfirst) {\r
1179                                 _fs->AddInstruction(_OP_JMP, 0, 0);\r
1180                                 skipcondjmp = _fs->GetCurrentPos();\r
1181                                 _fs->SetIntructionParam(tonextcondjmp, 1, _fs->GetCurrentPos() - tonextcondjmp);\r
1182                         }\r
1183                         //condition\r
1184                         Lex(); Expression(); Expect(_SC(':'));\r
1185                         SQInteger trg = _fs->PopTarget();\r
1186                         SQInteger eqtarget = trg;\r
1187                         bool local = _fs->IsLocal(trg);\r
1188                         if(local) {\r
1189                                 eqtarget = _fs->PushTarget(); //we need to allocate a extra reg\r
1190                         }\r
1191                         _fs->AddInstruction(_OP_EQ, eqtarget, trg, expr);\r
1192                         _fs->AddInstruction(_OP_JZ, eqtarget, 0);\r
1193                         if(local) {\r
1194                                 _fs->PopTarget();\r
1195                         }\r
1196                         \r
1197                         //end condition\r
1198                         if(skipcondjmp != -1) {\r
1199                                 _fs->SetIntructionParam(skipcondjmp, 1, (_fs->GetCurrentPos() - skipcondjmp));\r
1200                         }\r
1201                         tonextcondjmp = _fs->GetCurrentPos();\r
1202                         BEGIN_SCOPE();\r
1203                         Statements();\r
1204                         END_SCOPE();\r
1205                         bfirst = false;\r
1206                 }\r
1207                 if(tonextcondjmp != -1)\r
1208                         _fs->SetIntructionParam(tonextcondjmp, 1, _fs->GetCurrentPos() - tonextcondjmp);\r
1209                 if(_token == TK_DEFAULT) {\r
1210                         Lex(); Expect(_SC(':'));\r
1211                         BEGIN_SCOPE();\r
1212                         Statements();\r
1213                         END_SCOPE();\r
1214                 }\r
1215                 Expect(_SC('}'));\r
1216                 _fs->PopTarget();\r
1217                 __nbreaks__ = _fs->_unresolvedbreaks.size() - __nbreaks__;\r
1218                 if(__nbreaks__ > 0)ResolveBreaks(_fs, __nbreaks__);\r
1219                 _fs->_breaktargets.pop_back();\r
1220         }\r
1221         void FunctionStatement()\r
1222         {\r
1223                 SQObject id;\r
1224                 Lex(); id = Expect(TK_IDENTIFIER);\r
1225                 _fs->PushTarget(0);\r
1226                 _fs->AddInstruction(_OP_LOAD, _fs->PushTarget(), _fs->GetConstant(id));\r
1227                 if(_token == TK_DOUBLE_COLON) Emit2ArgsOP(_OP_GET);\r
1228                 \r
1229                 while(_token == TK_DOUBLE_COLON) {\r
1230                         Lex();\r
1231                         id = Expect(TK_IDENTIFIER);\r
1232                         _fs->AddInstruction(_OP_LOAD, _fs->PushTarget(), _fs->GetConstant(id));\r
1233                         if(_token == TK_DOUBLE_COLON) Emit2ArgsOP(_OP_GET);\r
1234                 }\r
1235                 Expect(_SC('('));\r
1236                 CreateFunction(id);\r
1237                 _fs->AddInstruction(_OP_CLOSURE, _fs->PushTarget(), _fs->_functions.size() - 1, 0);\r
1238                 EmitDerefOp(_OP_NEWSLOT);\r
1239                 _fs->PopTarget();\r
1240         }\r
1241         void ClassStatement()\r
1242         {\r
1243                 SQExpState es;\r
1244                 Lex();\r
1245                 es = _es;\r
1246                 _es.donot_get = true;\r
1247                 PrefixedExpr();\r
1248                 if(_es.etype == EXPR) {\r
1249                         Error(_SC("invalid class name"));\r
1250                 }\r
1251                 else if(_es.etype == OBJECT || _es.etype == BASE) {\r
1252                         ClassExp();\r
1253                         EmitDerefOp(_OP_NEWSLOT);\r
1254                         _fs->PopTarget();\r
1255                 }\r
1256                 else {\r
1257                         Error(_SC("cannot create a class in a local with the syntax(class <local>)"));\r
1258                 }\r
1259                 _es = es;\r
1260         }\r
1261         SQObject ExpectScalar()\r
1262         {\r
1263                 SQObject val;\r
1264                 val._type = OT_NULL; val._unVal.nInteger = 0; //shut up GCC 4.x\r
1265                 switch(_token) {\r
1266                         case TK_INTEGER:\r
1267                                 val._type = OT_INTEGER;\r
1268                                 val._unVal.nInteger = _lex._nvalue;\r
1269                                 break;\r
1270                         case TK_FLOAT:\r
1271                                 val._type = OT_FLOAT;\r
1272                                 val._unVal.fFloat = _lex._fvalue;\r
1273                                 break;\r
1274                         case TK_STRING_LITERAL:\r
1275                                 val = _fs->CreateString(_lex._svalue,_lex._longstr.size()-1);\r
1276                                 break;\r
1277                         case TK_TRUE:\r
1278                         case TK_FALSE:\r
1279                                 val._type = OT_BOOL;\r
1280                                 val._unVal.nInteger = _token == TK_TRUE ? 1 : 0;\r
1281                                 break;\r
1282                         case '-':\r
1283                                 Lex();\r
1284                                 switch(_token)\r
1285                                 {\r
1286                                 case TK_INTEGER:\r
1287                                         val._type = OT_INTEGER;\r
1288                                         val._unVal.nInteger = -_lex._nvalue;\r
1289                                 break;\r
1290                                 case TK_FLOAT:\r
1291                                         val._type = OT_FLOAT;\r
1292                                         val._unVal.fFloat = -_lex._fvalue;\r
1293                                 break;\r
1294                                 default:\r
1295                                         Error(_SC("scalar expected : integer,float"));\r
1296                                 }\r
1297                                 break;\r
1298                         default:\r
1299                                 Error(_SC("scalar expected : integer,float or string"));\r
1300                 }\r
1301                 Lex();\r
1302                 return val;\r
1303         }\r
1304         void EnumStatement()\r
1305         {\r
1306                 Lex(); \r
1307                 SQObject id = Expect(TK_IDENTIFIER);\r
1308                 Expect(_SC('{'));\r
1309                 \r
1310                 SQObject table = _fs->CreateTable();\r
1311                 SQInteger nval = 0;\r
1312                 while(_token != _SC('}')) {\r
1313                         SQObject key = Expect(TK_IDENTIFIER);\r
1314                         SQObject val;\r
1315                         if(_token == _SC('=')) {\r
1316                                 Lex();\r
1317                                 val = ExpectScalar();\r
1318                         }\r
1319                         else {\r
1320                                 val._type = OT_INTEGER;\r
1321                                 val._unVal.nInteger = nval++;\r
1322                         }\r
1323                         _table(table)->NewSlot(SQObjectPtr(key),SQObjectPtr(val));\r
1324                         if(_token == ',') Lex();\r
1325                 }\r
1326                 SQTable *enums = _table(_ss(_vm)->_consts);\r
1327                 SQObjectPtr strongid = id; \r
1328                 enums->NewSlot(SQObjectPtr(strongid),SQObjectPtr(table));\r
1329                 strongid.Null();\r
1330                 Lex();\r
1331         }\r
1332         void TryCatchStatement()\r
1333         {\r
1334                 SQObject exid;\r
1335                 Lex();\r
1336                 _fs->AddInstruction(_OP_PUSHTRAP,0,0);\r
1337                 _fs->_traps++;\r
1338                 if(_fs->_breaktargets.size()) _fs->_breaktargets.top()++;\r
1339                 if(_fs->_continuetargets.size()) _fs->_continuetargets.top()++;\r
1340                 SQInteger trappos = _fs->GetCurrentPos();\r
1341                 {\r
1342                         BEGIN_SCOPE();\r
1343                         Statement();\r
1344                         END_SCOPE();\r
1345                 }\r
1346                 _fs->_traps--;\r
1347                 _fs->AddInstruction(_OP_POPTRAP, 1, 0);\r
1348                 if(_fs->_breaktargets.size()) _fs->_breaktargets.top()--;\r
1349                 if(_fs->_continuetargets.size()) _fs->_continuetargets.top()--;\r
1350                 _fs->AddInstruction(_OP_JMP, 0, 0);\r
1351                 SQInteger jmppos = _fs->GetCurrentPos();\r
1352                 _fs->SetIntructionParam(trappos, 1, (_fs->GetCurrentPos() - trappos));\r
1353                 Expect(TK_CATCH); Expect(_SC('(')); exid = Expect(TK_IDENTIFIER); Expect(_SC(')'));\r
1354                 {\r
1355                         BEGIN_SCOPE();\r
1356                         SQInteger ex_target = _fs->PushLocalVariable(exid);\r
1357                         _fs->SetIntructionParam(trappos, 0, ex_target);\r
1358                         Statement();\r
1359                         _fs->SetIntructionParams(jmppos, 0, (_fs->GetCurrentPos() - jmppos), 0);\r
1360                         END_SCOPE();\r
1361                 }\r
1362         }\r
1363         void FunctionExp(SQInteger ftype,bool lambda = false)\r
1364         {\r
1365                 Lex(); Expect(_SC('('));\r
1366                 SQObjectPtr dummy;\r
1367                 CreateFunction(dummy,lambda);\r
1368                 _fs->AddInstruction(_OP_CLOSURE, _fs->PushTarget(), _fs->_functions.size() - 1, ftype == TK_FUNCTION?0:1);\r
1369         }\r
1370         void ClassExp()\r
1371         {\r
1372                 SQInteger base = -1;\r
1373                 SQInteger attrs = -1;\r
1374                 if(_token == TK_EXTENDS) {\r
1375                         Lex(); Expression();\r
1376                         base = _fs->TopTarget();\r
1377                 }\r
1378                 if(_token == TK_ATTR_OPEN) {\r
1379                         Lex();\r
1380                         _fs->AddInstruction(_OP_NEWOBJ, _fs->PushTarget(),0,NOT_TABLE);\r
1381                         ParseTableOrClass(_SC(','),TK_ATTR_CLOSE);\r
1382                         attrs = _fs->TopTarget();\r
1383                 }\r
1384                 Expect(_SC('{'));\r
1385                 if(attrs != -1) _fs->PopTarget();\r
1386                 if(base != -1) _fs->PopTarget();\r
1387                 _fs->AddInstruction(_OP_NEWOBJ, _fs->PushTarget(), base, attrs,NOT_CLASS);\r
1388                 ParseTableOrClass(_SC(';'),_SC('}'));\r
1389         }\r
1390         void DeleteExpr()\r
1391         {\r
1392                 SQExpState es;\r
1393                 Lex();\r
1394                 es = _es;\r
1395                 _es.donot_get = true;\r
1396                 PrefixedExpr();\r
1397                 if(_es.etype==EXPR) Error(_SC("can't delete an expression"));\r
1398                 if(_es.etype==OBJECT || _es.etype==BASE) {\r
1399                         Emit2ArgsOP(_OP_DELETE);\r
1400                 }\r
1401                 else {\r
1402                         Error(_SC("cannot delete an (outer) local"));\r
1403                 }\r
1404                 _es = es;\r
1405         }\r
1406         void PrefixIncDec(SQInteger token)\r
1407         {\r
1408                 SQExpState  es;\r
1409                 SQInteger diff = (token==TK_MINUSMINUS) ? -1 : 1;\r
1410                 Lex();\r
1411                 es = _es;\r
1412                 _es.donot_get = true;\r
1413                 PrefixedExpr();\r
1414                 if(_es.etype==EXPR) {\r
1415                         Error(_SC("can't '++' or '--' an expression"));\r
1416                 }\r
1417                 else if(_es.etype==OBJECT || _es.etype==BASE) {\r
1418                         Emit2ArgsOP(_OP_INC, diff);\r
1419                 }\r
1420                 else if(_es.etype==LOCAL) {\r
1421                         SQInteger src = _fs->TopTarget();\r
1422                         _fs->AddInstruction(_OP_INCL, src, src, 0, diff);\r
1423                         \r
1424                 }\r
1425                 else if(_es.etype==OUTER) {\r
1426                         SQInteger tmp = _fs->PushTarget();\r
1427                         _fs->AddInstruction(_OP_GETOUTER, tmp, _es.epos);\r
1428                         _fs->AddInstruction(_OP_INCL,     tmp, tmp, 0, diff);\r
1429                         _fs->AddInstruction(_OP_SETOUTER, tmp, _es.epos, tmp);\r
1430                 }\r
1431                 _es = es;\r
1432         }\r
1433         void CreateFunction(SQObject &name,bool lambda = false)\r
1434         {\r
1435                 SQFuncState *funcstate = _fs->PushChildState(_ss(_vm));\r
1436                 funcstate->_name = name;\r
1437                 SQObject paramname;\r
1438                 funcstate->AddParameter(_fs->CreateString(_SC("this")));\r
1439                 funcstate->_sourcename = _sourcename;\r
1440                 SQInteger defparams = 0;\r
1441                 while(_token!=_SC(')')) {\r
1442                         if(_token == TK_VARPARAMS) {\r
1443                                 if(defparams > 0) Error(_SC("function with default parameters cannot have variable number of parameters"));\r
1444                                 funcstate->AddParameter(_fs->CreateString(_SC("vargv")));\r
1445                                 funcstate->_varparams = true;\r
1446                                 Lex();\r
1447                                 if(_token != _SC(')')) Error(_SC("expected ')'"));\r
1448                                 break;\r
1449                         }\r
1450                         else {\r
1451                                 paramname = Expect(TK_IDENTIFIER);\r
1452                                 funcstate->AddParameter(paramname);\r
1453                                 if(_token == _SC('=')) { \r
1454                                         Lex();\r
1455                                         Expression();\r
1456                                         funcstate->AddDefaultParam(_fs->TopTarget());\r
1457                                         defparams++;\r
1458                                 }\r
1459                                 else {\r
1460                                         if(defparams > 0) Error(_SC("expected '='"));\r
1461                                 }\r
1462                                 if(_token == _SC(',')) Lex();\r
1463                                 else if(_token != _SC(')')) Error(_SC("expected ')' or ','"));\r
1464                         }\r
1465                 }\r
1466                 Expect(_SC(')'));\r
1467                 for(SQInteger n = 0; n < defparams; n++) {\r
1468                         _fs->PopTarget();\r
1469                 }\r
1470                                 \r
1471                 SQFuncState *currchunk = _fs;\r
1472                 _fs = funcstate;\r
1473                 if(lambda) { \r
1474                         Expression(); \r
1475                         _fs->AddInstruction(_OP_RETURN, 1, _fs->PopTarget());}\r
1476                 else { \r
1477                         Statement(false); \r
1478                 }\r
1479                 funcstate->AddLineInfos(_lex._prevtoken == _SC('\n')?_lex._lasttokenline:_lex._currentline, _lineinfo, true);\r
1480         funcstate->AddInstruction(_OP_RETURN, -1);\r
1481                 funcstate->SetStackSize(0);\r
1482 \r
1483                 SQFunctionProto *func = funcstate->BuildProto();\r
1484 #ifdef _DEBUG_DUMP\r
1485                 funcstate->Dump(func);\r
1486 #endif\r
1487                 _fs = currchunk;\r
1488                 _fs->_functions.push_back(func);\r
1489                 _fs->PopChildState();\r
1490         }\r
1491         void ResolveBreaks(SQFuncState *funcstate, SQInteger ntoresolve)\r
1492         {\r
1493                 while(ntoresolve > 0) {\r
1494                         SQInteger pos = funcstate->_unresolvedbreaks.back();\r
1495                         funcstate->_unresolvedbreaks.pop_back();\r
1496                         //set the jmp instruction\r
1497                         funcstate->SetIntructionParams(pos, 0, funcstate->GetCurrentPos() - pos, 0);\r
1498                         ntoresolve--;\r
1499                 }\r
1500         }\r
1501         void ResolveContinues(SQFuncState *funcstate, SQInteger ntoresolve, SQInteger targetpos)\r
1502         {\r
1503                 while(ntoresolve > 0) {\r
1504                         SQInteger pos = funcstate->_unresolvedcontinues.back();\r
1505                         funcstate->_unresolvedcontinues.pop_back();\r
1506                         //set the jmp instruction\r
1507                         funcstate->SetIntructionParams(pos, 0, targetpos - pos, 0);\r
1508                         ntoresolve--;\r
1509                 }\r
1510         }\r
1511 private:\r
1512         SQInteger _token;\r
1513         SQFuncState *_fs;\r
1514         SQObjectPtr _sourcename;\r
1515         SQLexer _lex;\r
1516         bool _lineinfo;\r
1517         bool _raiseerror;\r
1518         SQInteger _debugline;\r
1519         SQInteger _debugop;\r
1520         SQExpState   _es;\r
1521         SQScope _scope;\r
1522         SQChar _compilererror[MAX_COMPILER_ERROR_LEN];\r
1523         jmp_buf _errorjmp;\r
1524         SQVM *_vm;\r
1525 };\r
1526 \r
1527 bool Compile(SQVM *vm,SQLEXREADFUNC rg, SQUserPointer up, const SQChar *sourcename, SQObjectPtr &out, bool raiseerror, bool lineinfo)\r
1528 {\r
1529         SQCompiler p(vm, rg, up, sourcename, raiseerror, lineinfo);\r
1530         return p.Compile(out);\r
1531 }\r
1532 \r
1533 #endif\r