2 see copyright notice in squirrel.h
\r
4 #include "sqpcheader.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
15 #include "sqtable.h"
\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
29 #define MAX_COMPILER_ERROR_LEN 256
\r
33 SQInteger stacksize;
\r
36 #define BEGIN_SCOPE() SQScope __oldscope__ = _scope; \
\r
37 _scope.outers = _fs->_outers; \
\r
38 _scope.stacksize = _fs->GetStackSize();
\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
46 #define END_SCOPE_NO_CLOSE() { if(_fs->GetStackSize() != _scope.stacksize) { \
\r
47 _fs->SetStackSize(_scope.stacksize); \
\r
49 _scope = __oldscope__; \
\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
59 _scope = __oldscope__; \
\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
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
75 SQCompiler(SQVM *v, SQLEXREADFUNC rg, SQUserPointer up, const SQChar* sourcename, bool raiseerror, bool lineinfo)
\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
82 _scope.stacksize = 0;
\r
83 _compilererror[0] = _SC('\0');
\r
85 static void ThrowError(void *ud, const SQChar *s) {
\r
86 SQCompiler *c = (SQCompiler *)ud;
\r
89 void Error(const SQChar *s, ...)
\r
93 scvsprintf(_compilererror, MAX_COMPILER_ERROR_LEN, s, vl);
\r
95 longjmp(_errorjmp,1);
\r
97 void Lex(){ _token = _lex.Lex();}
\r
98 SQObject Expect(SQInteger tok)
\r
101 if(_token != tok) {
\r
102 if(_token == TK_CONSTRUCTOR && tok == TK_IDENTIFIER) {
\r
106 const SQChar *etypename;
\r
110 case TK_IDENTIFIER:
\r
111 etypename = _SC("IDENTIFIER");
\r
113 case TK_STRING_LITERAL:
\r
114 etypename = _SC("STRING_LITERAL");
\r
117 etypename = _SC("INTEGER");
\r
120 etypename = _SC("FLOAT");
\r
123 etypename = _lex.Tok2Str(tok);
\r
125 Error(_SC("expected '%s'"), etypename);
\r
127 Error(_SC("expected '%c'"), tok);
\r
133 case TK_IDENTIFIER:
\r
134 ret = _fs->CreateString(_lex._svalue);
\r
136 case TK_STRING_LITERAL:
\r
137 ret = _fs->CreateString(_lex._svalue,_lex._longstr.size()-1);
\r
140 ret = SQObjectPtr(_lex._nvalue);
\r
143 ret = SQObjectPtr(_lex._fvalue);
\r
149 bool IsEndOfStatement() { return ((_lex._prevtoken == _SC('\n')) || (_token == SQUIRREL_EOB) || (_token == _SC('}')) || (_token == _SC(';'))); }
\r
150 void OptionalSemicolon()
\r
152 if(_token == _SC(';')) { Lex(); return; }
\r
153 if(!IsEndOfStatement()) {
\r
154 Error(_SC("end of statement expected (; or lf)"));
\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
164 bool Compile(SQObjectPtr &o)
\r
169 SQFuncState funcstate(_ss(_vm), NULL,ThrowError,this);
\r
170 funcstate._name = SQString::Create(_ss(_vm), _SC("main"));
\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
181 if(_lex._prevtoken != _SC('}') && _lex._prevtoken != _SC(';')) OptionalSemicolon();
\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
189 _fs->Dump(_funcproto(o));
\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
197 _vm->_lasterror = SQString::Create(_ss(_vm), _compilererror, -1);
\r
204 while(_token != _SC('}') && _token != TK_DEFAULT && _token != TK_CASE) {
\r
206 if(_lex._prevtoken != _SC('}') && _lex._prevtoken != _SC(';')) OptionalSemicolon();
\r
209 void Statement(bool closeframe = true)
\r
211 _fs->AddLineInfos(_lex._currentline, _lineinfo);
\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
224 if(_token == TK_RETURN) {
\r
229 _fs->_bgenerator = true;
\r
232 if(!IsEndOfStatement()) {
\r
233 SQInteger retexp = _fs->GetCurrentPos()+1;
\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
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
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
253 _fs->AddInstruction(_OP_JMP, 0, -1234);
\r
254 _fs->_unresolvedbreaks.push_back(_fs->GetCurrentPos());
\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
263 _fs->AddInstruction(_OP_JMP, 0, -1234);
\r
264 _fs->_unresolvedcontinues.push_back(_fs->GetCurrentPos());
\r
268 FunctionStatement();
\r
285 END_SCOPE_NO_CLOSE();
\r
290 TryCatchStatement();
\r
295 _fs->AddInstruction(_OP_THROW, _fs->PopTarget());
\r
300 SQObject id = Expect(TK_IDENTIFIER);
\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
312 _fs->DiscardTarget();
\r
313 //_fs->PopTarget();
\r
318 void EmitDerefOp(SQOpcode op)
\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
325 void Emit2ArgsOP(SQOpcode op, SQInteger p3 = 0)
\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
331 void EmitCompoundArith(SQInteger tok, SQInteger etype, SQInteger pos)
\r
333 /* Generate code depending on the expression type */
\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
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
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
367 for(Expression();_token == ',';_fs->PopTarget(), Lex(), CommaExpr());
\r
371 SQExpState es = _es;
\r
374 _es.donot_get = false;
\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
390 Lex(); Expression();
\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
399 case _SC('='): //ASSIGN
\r
403 SQInteger src = _fs->PopTarget();
\r
404 SQInteger dst = _fs->TopTarget();
\r
405 _fs->AddInstruction(_OP_MOVE, dst, src);
\r
410 EmitDerefOp(_OP_SET);
\r
414 SQInteger src = _fs->PopTarget();
\r
415 SQInteger dst = _fs->PushTarget();
\r
416 _fs->AddInstruction(_OP_SETOUTER, dst, pos, src);
\r
425 EmitCompoundArith(op, ds, pos);
\r
432 _fs->AddInstruction(_OP_JZ, _fs->PopTarget());
\r
433 SQInteger jzpos = _fs->GetCurrentPos();
\r
434 SQInteger trg = _fs->PushTarget();
\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
441 SQInteger jmppos = _fs->GetCurrentPos();
\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
453 template<typename T> void INVOKE_EXP(T f)
\r
455 SQExpState es = _es;
\r
458 _es.donot_get = false;
\r
462 template<typename T> void BIN_EXP(SQOpcode op, T f,SQInteger op3 = 0)
\r
466 SQInteger op1 = _fs->PopTarget();SQInteger op2 = _fs->PopTarget();
\r
467 _fs->AddInstruction(op, _fs->PushTarget(), op1, op2, op3);
\r
469 void LogicalOrExp()
\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
480 SQInteger second_exp = _fs->PopTarget();
\r
481 if(trg != second_exp) _fs->AddInstruction(_OP_MOVE, trg, second_exp);
\r
483 _fs->SetIntructionParam(jpos, 1, (_fs->GetCurrentPos() - jpos));
\r
487 void LogicalAndExp()
\r
490 for(;;) switch(_token) {
\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
499 SQInteger second_exp = _fs->PopTarget();
\r
500 if(trg != second_exp) _fs->AddInstruction(_OP_MOVE, trg, second_exp);
\r
502 _fs->SetIntructionParam(jpos, 1, (_fs->GetCurrentPos() - jpos));
\r
510 void BitwiseOrExp()
\r
513 for(;;) if(_token == _SC('|'))
\r
514 {BIN_EXP(_OP_BITW, &SQCompiler::BitwiseXorExp,BW_OR);
\r
517 void BitwiseXorExp()
\r
520 for(;;) if(_token == _SC('^'))
\r
521 {BIN_EXP(_OP_BITW, &SQCompiler::BitwiseAndExp,BW_XOR);
\r
524 void BitwiseAndExp()
\r
527 for(;;) if(_token == _SC('&'))
\r
528 {BIN_EXP(_OP_BITW, &SQCompiler::EqExp,BW_AND);
\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
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
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
564 SQOpcode ChooseArithOpByToken(SQInteger 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
576 SQInteger ChooseCompArithCharByToken(SQInteger 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
593 for(;;) switch(_token) {
\r
594 case _SC('+'): case _SC('-'):
\r
595 BIN_EXP(ChooseArithOpByToken(_token), &SQCompiler::MultExp); break;
\r
603 for(;;) switch(_token) {
\r
604 case _SC('*'): case _SC('/'): case _SC('%'):
\r
605 BIN_EXP(ChooseArithOpByToken(_token), &SQCompiler::PrefixedExpr); break;
\r
609 //if 'pos' != -1 the previous variable is a local variable
\r
610 void PrefixedExpr()
\r
612 SQInteger pos = Factor();
\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
628 Emit2ArgsOP(_OP_GET);
\r
630 _es.etype = OBJECT;
\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
637 if(_es.etype==BASE) {
\r
638 Emit2ArgsOP(_OP_GET);
\r
639 pos = _fs->TopTarget();
\r
645 Emit2ArgsOP(_OP_GET);
\r
647 _es.etype = OBJECT;
\r
650 case TK_MINUSMINUS:
\r
653 if(IsEndOfStatement()) return;
\r
654 SQInteger diff = (_token==TK_MINUSMINUS) ? -1 : 1;
\r
658 case EXPR: Error(_SC("can't '++' or '--' an expression")); break;
\r
661 Emit2ArgsOP(_OP_PINC, diff);
\r
664 SQInteger src = _fs->PopTarget();
\r
665 _fs->AddInstruction(_OP_PINCL, _fs->PushTarget(), src, 0, diff);
\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
681 switch(_es.etype) {
\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
691 //Emit2ArgsOP(_OP_GET);
\r
692 _fs->AddInstruction(_OP_MOVE, _fs->PushTarget(), 0);
\r
695 _fs->AddInstruction(_OP_GETOUTER, _fs->PushTarget(), _es.epos);
\r
696 _fs->AddInstruction(_OP_MOVE, _fs->PushTarget(), 0);
\r
699 _fs->AddInstruction(_OP_MOVE, _fs->PushTarget(), 0);
\r
703 FunctionCallArgs();
\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
720 _fs->AddInstruction(_OP_GETBASE, _fs->PushTarget());
\r
722 _es.epos = _fs->TopTarget();
\r
725 case TK_IDENTIFIER:
\r
726 case TK_CONSTRUCTOR:
\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
737 SQInteger pos = -1;
\r
739 if((pos = _fs->GetLocalVariable(id)) != -1) {
\r
740 /* Handle a local variable (includes 'this') */
\r
741 _fs->PushTarget(pos);
\r
746 else if((pos = _fs->GetOuterVariable(id)) != -1) {
\r
747 /* Handle a free var */
\r
749 _es.epos = _fs->PushTarget();
\r
750 _fs->AddInstruction(_OP_GETOUTER, _es.epos, pos);
\r
751 /* _es.etype = EXPR; already default value */
\r
759 else if(_fs->IsConstant(id, constant)) {
\r
760 /* Handle named constant */
\r
761 SQObjectPtr constval;
\r
763 if(type(constant) == OT_TABLE) {
\r
765 constid = Expect(TK_IDENTIFIER);
\r
766 if(!_table(constant)->Get(constid, constval)) {
\r
768 Error(_SC("invalid constant [%s.%s]"), _stringval(id), _stringval(constid));
\r
772 constval = constant;
\r
774 _es.epos = _fs->PushTarget();
\r
776 /* generate direct or literal function depending on size */
\r
777 SQObjectType ctype = type(constval);
\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
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
792 _fs->PushTarget(0);
\r
793 _fs->AddInstruction(_OP_LOAD, _fs->PushTarget(), _fs->GetConstant(id));
\r
795 Emit2ArgsOP(_OP_GET);
\r
797 _es.etype = OBJECT;
\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
810 _fs->AddInstruction(_OP_LOADNULLS, _fs->PushTarget(),1);
\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
820 _fs->AddInstruction(_OP_NEWOBJ, _fs->PushTarget(),0,0,NOT_ARRAY);
\r
821 SQInteger apos = _fs->GetCurrentPos(),key = 0;
\r
823 while(_token != _SC(']')) {
\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
831 _fs->SetIntructionParam(apos, 1, key);
\r
836 _fs->AddInstruction(_OP_NEWOBJ, _fs->PushTarget(),0,NOT_TABLE);
\r
837 Lex();ParseTableOrClass(_SC(','),_SC('}'));
\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
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
850 case _SC('!'): Lex(); UnaryOP(_OP_NOT); break;
\r
853 if(_token == TK_INTEGER) { EmitLoadConstInt(~_lex._nvalue,-1); Lex(); break; }
\r
854 UnaryOP(_OP_BWNOT);
\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
864 default: Error(_SC("expression expected"));
\r
868 void EmitLoadConstInt(SQInteger value,SQInteger target)
\r
871 target = _fs->PushTarget();
\r
873 if((value & (~((SQInteger)0xFFFFFFFF))) == 0) { //does it fit in 32 bits?
\r
874 _fs->AddInstruction(_OP_LOADINT, target,value);
\r
877 _fs->AddInstruction(_OP_LOAD, target, _fs->GetNumericConstant(value));
\r
880 void EmitLoadConstFloat(SQFloat value,SQInteger target)
\r
883 target = _fs->PushTarget();
\r
885 if(sizeof(SQFloat) == sizeof(SQInt32)) {
\r
886 _fs->AddInstruction(_OP_LOADFLOAT, target,*((SQInt32 *)&value));
\r
889 _fs->AddInstruction(_OP_LOAD, target, _fs->GetNumericConstant(value));
\r
892 void UnaryOP(SQOpcode op)
\r
895 SQInteger src = _fs->PopTarget();
\r
896 _fs->AddInstruction(op, _fs->PushTarget(), src);
\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
905 return (!_es.donot_get || ( _es.donot_get && (_token == _SC('.') || _token == _SC('['))));
\r
907 void FunctionCallArgs()
\r
909 SQInteger nargs = 1;//this
\r
910 while(_token != _SC(')')) {
\r
912 MoveIfCurrentTargetIsLocal();
\r
914 if(_token == _SC(',')){
\r
916 if(_token == ')') Error(_SC("expression expected, found ')'"));
\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
925 void ParseTableOrClass(SQInteger separator,SQInteger terminator)
\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
938 if(_token == TK_STATIC) {
\r
945 case TK_CONSTRUCTOR:{
\r
946 SQInteger tk = _token;
\r
948 SQObject id = tk == TK_FUNCTION ? Expect(TK_IDENTIFIER) : _fs->CreateString(_SC("constructor"));
\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
956 Lex(); CommaExpr(); Expect(_SC(']'));
\r
957 Expect(_SC('=')); Expression();
\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
966 _fs->AddInstruction(_OP_LOAD, _fs->PushTarget(), _fs->GetConstant(Expect(TK_IDENTIFIER)));
\r
967 Expect(_SC('=')); Expression();
\r
969 if(_token == separator) Lex();//optional comma/semicolon
\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
981 _fs->AddInstruction(_OP_NEWSLOTA, flags, table, key, val); //this for classes only as it invokes _newmember
\r
984 if(separator == _SC(',')) //hack recognizes a table from the separator
\r
985 _fs->SetIntructionParam(tpos, 1, nkeys);
\r
988 void LocalDeclStatement()
\r
992 if( _token == TK_FUNCTION) {
\r
994 varname = Expect(TK_IDENTIFIER);
\r
996 CreateFunction(varname,false);
\r
997 _fs->AddInstruction(_OP_CLOSURE, _fs->PushTarget(), _fs->_functions.size() - 1, 0);
\r
999 _fs->PushLocalVariable(varname);
\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
1012 _fs->AddInstruction(_OP_LOADNULLS, _fs->PushTarget(),1);
\r
1015 _fs->PushLocalVariable(varname);
\r
1016 if(_token == _SC(',')) Lex(); else break;
\r
1019 void IfStatement()
\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
1030 if(_token != _SC('}') && _token != TK_ELSE) OptionalSemicolon();
\r
1033 SQInteger endifblock = _fs->GetCurrentPos();
\r
1034 if(_token == TK_ELSE){
\r
1037 _fs->AddInstruction(_OP_JMP);
\r
1038 jmppos = _fs->GetCurrentPos();
\r
1040 Statement(); if(_lex._prevtoken != _SC('}')) OptionalSemicolon();
\r
1042 _fs->SetIntructionParam(jmppos, 1, _fs->GetCurrentPos() - jmppos);
\r
1044 _fs->SetIntructionParam(jnepos, 1, endifblock - jnepos + (haselse?1:0));
\r
1046 void WhileStatement()
\r
1048 SQInteger jzpos, jmppos;
\r
1049 jmppos = _fs->GetCurrentPos();
\r
1050 Lex(); Expect(_SC('(')); CommaExpr(); Expect(_SC(')'));
\r
1052 BEGIN_BREAKBLE_BLOCK();
\r
1053 _fs->AddInstruction(_OP_JZ, _fs->PopTarget());
\r
1054 jzpos = _fs->GetCurrentPos();
\r
1060 _fs->AddInstruction(_OP_JMP, 0, jmppos - _fs->GetCurrentPos() - 1);
\r
1061 _fs->SetIntructionParam(jzpos, 1, _fs->GetCurrentPos() - jzpos);
\r
1063 END_BREAKBLE_BLOCK(jmppos);
\r
1065 void DoWhileStatement()
\r
1068 SQInteger jmptrg = _fs->GetCurrentPos();
\r
1069 BEGIN_BREAKBLE_BLOCK()
\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
1080 void ForStatement()
\r
1085 if(_token == TK_LOCAL) LocalDeclStatement();
\r
1086 else if(_token != _SC(';')){
\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
1097 SQInteger expstart = _fs->GetCurrentPos() + 1;
\r
1098 if(_token != _SC(')')) {
\r
1104 SQInteger expend = _fs->GetCurrentPos();
\r
1105 SQInteger expsize = (expend - expstart) + 1;
\r
1106 SQInstructionVec exp;
\r
1108 for(SQInteger i = 0; i < expsize; i++)
\r
1109 exp.push_back(_fs->GetInstruction(expstart + i));
\r
1110 _fs->PopInstructions(expsize);
\r
1112 BEGIN_BREAKBLE_BLOCK()
\r
1114 SQInteger continuetrg = _fs->GetCurrentPos();
\r
1116 for(SQInteger i = 0; i < expsize; i++)
\r
1117 _fs->AddInstruction(exp[i]);
\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
1123 END_BREAKBLE_BLOCK(continuetrg);
\r
1125 void ForEachStatement()
\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
1134 idxname = _fs->CreateString(_SC("@INDEX@"));
\r
1138 //save the stack size
\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
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
1167 void SwitchStatement()
\r
1169 Lex(); Expect(_SC('(')); CommaExpr(); 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
1179 _fs->AddInstruction(_OP_JMP, 0, 0);
\r
1180 skipcondjmp = _fs->GetCurrentPos();
\r
1181 _fs->SetIntructionParam(tonextcondjmp, 1, _fs->GetCurrentPos() - tonextcondjmp);
\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
1189 eqtarget = _fs->PushTarget(); //we need to allocate a extra reg
\r
1191 _fs->AddInstruction(_OP_EQ, eqtarget, trg, expr);
\r
1192 _fs->AddInstruction(_OP_JZ, eqtarget, 0);
\r
1198 if(skipcondjmp != -1) {
\r
1199 _fs->SetIntructionParam(skipcondjmp, 1, (_fs->GetCurrentPos() - skipcondjmp));
\r
1201 tonextcondjmp = _fs->GetCurrentPos();
\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
1217 __nbreaks__ = _fs->_unresolvedbreaks.size() - __nbreaks__;
\r
1218 if(__nbreaks__ > 0)ResolveBreaks(_fs, __nbreaks__);
\r
1219 _fs->_breaktargets.pop_back();
\r
1221 void FunctionStatement()
\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
1229 while(_token == TK_DOUBLE_COLON) {
\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
1236 CreateFunction(id);
\r
1237 _fs->AddInstruction(_OP_CLOSURE, _fs->PushTarget(), _fs->_functions.size() - 1, 0);
\r
1238 EmitDerefOp(_OP_NEWSLOT);
\r
1241 void ClassStatement()
\r
1246 _es.donot_get = true;
\r
1248 if(_es.etype == EXPR) {
\r
1249 Error(_SC("invalid class name"));
\r
1251 else if(_es.etype == OBJECT || _es.etype == BASE) {
\r
1253 EmitDerefOp(_OP_NEWSLOT);
\r
1257 Error(_SC("cannot create a class in a local with the syntax(class <local>)"));
\r
1261 SQObject ExpectScalar()
\r
1264 val._type = OT_NULL; val._unVal.nInteger = 0; //shut up GCC 4.x
\r
1267 val._type = OT_INTEGER;
\r
1268 val._unVal.nInteger = _lex._nvalue;
\r
1271 val._type = OT_FLOAT;
\r
1272 val._unVal.fFloat = _lex._fvalue;
\r
1274 case TK_STRING_LITERAL:
\r
1275 val = _fs->CreateString(_lex._svalue,_lex._longstr.size()-1);
\r
1279 val._type = OT_BOOL;
\r
1280 val._unVal.nInteger = _token == TK_TRUE ? 1 : 0;
\r
1287 val._type = OT_INTEGER;
\r
1288 val._unVal.nInteger = -_lex._nvalue;
\r
1291 val._type = OT_FLOAT;
\r
1292 val._unVal.fFloat = -_lex._fvalue;
\r
1295 Error(_SC("scalar expected : integer,float"));
\r
1299 Error(_SC("scalar expected : integer,float or string"));
\r
1304 void EnumStatement()
\r
1307 SQObject id = Expect(TK_IDENTIFIER);
\r
1310 SQObject table = _fs->CreateTable();
\r
1311 SQInteger nval = 0;
\r
1312 while(_token != _SC('}')) {
\r
1313 SQObject key = Expect(TK_IDENTIFIER);
\r
1315 if(_token == _SC('=')) {
\r
1317 val = ExpectScalar();
\r
1320 val._type = OT_INTEGER;
\r
1321 val._unVal.nInteger = nval++;
\r
1323 _table(table)->NewSlot(SQObjectPtr(key),SQObjectPtr(val));
\r
1324 if(_token == ',') Lex();
\r
1326 SQTable *enums = _table(_ss(_vm)->_consts);
\r
1327 SQObjectPtr strongid = id;
\r
1328 enums->NewSlot(SQObjectPtr(strongid),SQObjectPtr(table));
\r
1332 void TryCatchStatement()
\r
1336 _fs->AddInstruction(_OP_PUSHTRAP,0,0);
\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
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
1356 SQInteger ex_target = _fs->PushLocalVariable(exid);
\r
1357 _fs->SetIntructionParam(trappos, 0, ex_target);
\r
1359 _fs->SetIntructionParams(jmppos, 0, (_fs->GetCurrentPos() - jmppos), 0);
\r
1363 void FunctionExp(SQInteger ftype,bool lambda = false)
\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
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
1378 if(_token == TK_ATTR_OPEN) {
\r
1380 _fs->AddInstruction(_OP_NEWOBJ, _fs->PushTarget(),0,NOT_TABLE);
\r
1381 ParseTableOrClass(_SC(','),TK_ATTR_CLOSE);
\r
1382 attrs = _fs->TopTarget();
\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
1395 _es.donot_get = true;
\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
1402 Error(_SC("cannot delete an (outer) local"));
\r
1406 void PrefixIncDec(SQInteger token)
\r
1409 SQInteger diff = (token==TK_MINUSMINUS) ? -1 : 1;
\r
1412 _es.donot_get = true;
\r
1414 if(_es.etype==EXPR) {
\r
1415 Error(_SC("can't '++' or '--' an expression"));
\r
1417 else if(_es.etype==OBJECT || _es.etype==BASE) {
\r
1418 Emit2ArgsOP(_OP_INC, diff);
\r
1420 else if(_es.etype==LOCAL) {
\r
1421 SQInteger src = _fs->TopTarget();
\r
1422 _fs->AddInstruction(_OP_INCL, src, src, 0, diff);
\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
1433 void CreateFunction(SQObject &name,bool lambda = false)
\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
1447 if(_token != _SC(')')) Error(_SC("expected ')'"));
\r
1451 paramname = Expect(TK_IDENTIFIER);
\r
1452 funcstate->AddParameter(paramname);
\r
1453 if(_token == _SC('=')) {
\r
1456 funcstate->AddDefaultParam(_fs->TopTarget());
\r
1460 if(defparams > 0) Error(_SC("expected '='"));
\r
1462 if(_token == _SC(',')) Lex();
\r
1463 else if(_token != _SC(')')) Error(_SC("expected ')' or ','"));
\r
1467 for(SQInteger n = 0; n < defparams; n++) {
\r
1471 SQFuncState *currchunk = _fs;
\r
1475 _fs->AddInstruction(_OP_RETURN, 1, _fs->PopTarget());}
\r
1477 Statement(false);
\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
1483 SQFunctionProto *func = funcstate->BuildProto();
\r
1484 #ifdef _DEBUG_DUMP
\r
1485 funcstate->Dump(func);
\r
1488 _fs->_functions.push_back(func);
\r
1489 _fs->PopChildState();
\r
1491 void ResolveBreaks(SQFuncState *funcstate, SQInteger ntoresolve)
\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
1501 void ResolveContinues(SQFuncState *funcstate, SQInteger ntoresolve, SQInteger targetpos)
\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
1514 SQObjectPtr _sourcename;
\r
1518 SQInteger _debugline;
\r
1519 SQInteger _debugop;
\r
1522 SQChar _compilererror[MAX_COMPILER_ERROR_LEN];
\r
1523 jmp_buf _errorjmp;
\r
1527 bool Compile(SQVM *vm,SQLEXREADFUNC rg, SQUserPointer up, const SQChar *sourcename, SQObjectPtr &out, bool raiseerror, bool lineinfo)
\r
1529 SQCompiler p(vm, rg, up, sourcename, raiseerror, lineinfo);
\r
1530 return p.Compile(out);
\r