Johan Wikman / SQUIRREL3

Dependents:   Squirrel

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers sqcompiler.cpp Source File

sqcompiler.cpp

00001 /*
00002     see copyright notice in squirrel.h
00003 */
00004 #include "sqpcheader.h"
00005 #ifndef NO_COMPILER
00006 #include <stdarg.h>
00007 #include <setjmp.h>
00008 #include "sqopcodes.h"
00009 #include "sqstring.h"
00010 #include "sqfuncproto.h"
00011 #include "sqcompiler.h"
00012 #include "sqfuncstate.h"
00013 #include "sqlexer.h"
00014 #include "sqvm.h"
00015 #include "sqtable.h"
00016 
00017 #define EXPR   1
00018 #define OBJECT 2
00019 #define BASE   3
00020 #define LOCAL  4
00021 #define OUTER  5
00022 
00023 struct SQExpState {
00024   SQInteger  etype;       /* expr. type; one of EXPR, OBJECT, BASE, OUTER or LOCAL */
00025   SQInteger  epos;        /* expr. location on stack; -1 for OBJECT and BASE */
00026   bool       donot_get;   /* signal not to deref the next value */
00027 };
00028 
00029 #define MAX_COMPILER_ERROR_LEN 256
00030 
00031 struct SQScope {
00032     SQInteger outers;
00033     SQInteger stacksize;
00034 };
00035 
00036 #define BEGIN_SCOPE() SQScope __oldscope__ = _scope; \
00037                      _scope.outers = _fs->_outers; \
00038                      _scope.stacksize = _fs->GetStackSize();
00039 
00040 #define RESOLVE_OUTERS() if(_fs->GetStackSize() != _scope.stacksize) { \
00041                             if(_fs->CountOuters(_scope.stacksize)) { \
00042                                 _fs->AddInstruction(_OP_CLOSE,0,_scope.stacksize); \
00043                             } \
00044                         }
00045 
00046 #define END_SCOPE_NO_CLOSE() {  if(_fs->GetStackSize() != _scope.stacksize) { \
00047                             _fs->SetStackSize(_scope.stacksize); \
00048                         } \
00049                         _scope = __oldscope__; \
00050                     }
00051 
00052 #define END_SCOPE() {   SQInteger oldouters = _fs->_outers;\
00053                         if(_fs->GetStackSize() != _scope.stacksize) { \
00054                             _fs->SetStackSize(_scope.stacksize); \
00055                             if(oldouters != _fs->_outers) { \
00056                                 _fs->AddInstruction(_OP_CLOSE,0,_scope.stacksize); \
00057                             } \
00058                         } \
00059                         _scope = __oldscope__; \
00060                     }
00061 
00062 #define BEGIN_BREAKBLE_BLOCK()  SQInteger __nbreaks__=_fs->_unresolvedbreaks.size(); \
00063                             SQInteger __ncontinues__=_fs->_unresolvedcontinues.size(); \
00064                             _fs->_breaktargets.push_back(0);_fs->_continuetargets.push_back(0);
00065 
00066 #define END_BREAKBLE_BLOCK(continue_target) {__nbreaks__=_fs->_unresolvedbreaks.size()-__nbreaks__; \
00067                     __ncontinues__=_fs->_unresolvedcontinues.size()-__ncontinues__; \
00068                     if(__ncontinues__>0)ResolveContinues(_fs,__ncontinues__,continue_target); \
00069                     if(__nbreaks__>0)ResolveBreaks(_fs,__nbreaks__); \
00070                     _fs->_breaktargets.pop_back();_fs->_continuetargets.pop_back();}
00071 
00072 class SQCompiler
00073 {
00074 public:
00075     SQCompiler(SQVM *v, SQLEXREADFUNC rg, SQUserPointer up, const SQChar* sourcename, bool raiseerror, bool lineinfo)
00076     {
00077         _vm=v;
00078         _lex.Init(_ss(v), rg, up,ThrowError,this);
00079         _sourcename = SQString::Create(_ss(v), sourcename);
00080         _lineinfo = lineinfo;_raiseerror = raiseerror;
00081         _scope.outers = 0;
00082         _scope.stacksize = 0;
00083         _compilererror[0] = NULL;
00084     }
00085     static void ThrowError(void *ud, const SQChar *s) {
00086         SQCompiler *c = (SQCompiler *)ud;
00087         c->Error(s);
00088     }
00089     void Error(const SQChar *s, ...)
00090     {
00091         va_list vl;
00092         va_start(vl, s);
00093         scvsprintf(_compilererror, s, vl);
00094         va_end(vl);
00095         longjmp(_errorjmp,1);
00096     }
00097     void Lex(){ _token = _lex.Lex();}
00098     SQObject Expect(SQInteger tok)
00099     {
00100         
00101         if(_token != tok) {
00102             if(_token == TK_CONSTRUCTOR && tok == TK_IDENTIFIER) {
00103                 //do nothing
00104             }
00105             else {
00106                 const SQChar *etypename;
00107                 if(tok > 255) {
00108                     switch(tok)
00109                     {
00110                     case TK_IDENTIFIER:
00111                         etypename = _SC("IDENTIFIER");
00112                         break;
00113                     case TK_STRING_LITERAL:
00114                         etypename = _SC("STRING_LITERAL");
00115                         break;
00116                     case TK_INTEGER:
00117                         etypename = _SC("INTEGER");
00118                         break;
00119                     case TK_FLOAT:
00120                         etypename = _SC("FLOAT");
00121                         break;
00122                     default:
00123                         etypename = _lex.Tok2Str(tok);
00124                     }
00125                     Error(_SC("expected '%s'"), etypename);
00126                 }
00127                 Error(_SC("expected '%c'"), tok);
00128             }
00129         }
00130         SQObjectPtr ret;
00131         switch(tok)
00132         {
00133         case TK_IDENTIFIER:
00134             ret = _fs->CreateString(_lex._svalue);
00135             break;
00136         case TK_STRING_LITERAL:
00137             ret = _fs->CreateString(_lex._svalue,_lex._longstr.size()-1);
00138             break;
00139         case TK_INTEGER:
00140             ret = SQObjectPtr(_lex._nvalue);
00141             break;
00142         case TK_FLOAT:
00143             ret = SQObjectPtr(_lex._fvalue);
00144             break;
00145         }
00146         Lex();
00147         return ret;
00148     }
00149     bool IsEndOfStatement() { return ((_lex._prevtoken == _SC('\n')) || (_token == SQUIRREL_EOB) || (_token == _SC('}')) || (_token == _SC(';'))); }
00150     void OptionalSemicolon()
00151     {
00152         if(_token == _SC(';')) { Lex(); return; }
00153         if(!IsEndOfStatement()) {
00154             Error(_SC("end of statement expected (; or lf)"));
00155         }
00156     }
00157     void MoveIfCurrentTargetIsLocal() {
00158         SQInteger trg = _fs->TopTarget();
00159         if(_fs->IsLocal(trg)) {
00160             trg = _fs->PopTarget(); //no pops the target and move it
00161             _fs->AddInstruction(_OP_MOVE, _fs->PushTarget(), trg);
00162         }
00163     }
00164     bool Compile(SQObjectPtr &o)
00165     {
00166         _debugline = 1;
00167         _debugop = 0;
00168 
00169         SQFuncState funcstate(_ss(_vm), NULL,ThrowError,this);
00170         funcstate._name = SQString::Create(_ss(_vm), _SC("main"));
00171         _fs = &funcstate;
00172         _fs->AddParameter(_fs->CreateString(_SC("this")));
00173         _fs->AddParameter(_fs->CreateString(_SC("vargv")));
00174         _fs->_varparams = true;
00175         _fs->_sourcename = _sourcename;
00176         SQInteger stacksize = _fs->GetStackSize();
00177         if(setjmp(_errorjmp) == 0) {
00178             Lex();
00179             while(_token > 0){
00180                 Statement();
00181                 if(_lex._prevtoken != _SC('}') && _lex._prevtoken != _SC(';')) OptionalSemicolon();
00182             }
00183             _fs->SetStackSize(stacksize);
00184             _fs->AddLineInfos(_lex._currentline, _lineinfo, true);
00185             _fs->AddInstruction(_OP_RETURN, 0xFF);
00186             _fs->SetStackSize(0);
00187             o =_fs->BuildProto();
00188 #ifdef _DEBUG_DUMP
00189             _fs->Dump(_funcproto(o));
00190 #endif
00191         }
00192         else {
00193             if(_raiseerror && _ss(_vm)->_compilererrorhandler) {
00194                 _ss(_vm)->_compilererrorhandler(_vm, _compilererror, type(_sourcename) == OT_STRING?_stringval(_sourcename):_SC("unknown"),
00195                     _lex._currentline, _lex._currentcolumn);
00196             }
00197             _vm->_lasterror = SQString::Create(_ss(_vm), _compilererror, -1);
00198             return false;
00199         }
00200         return true;
00201     }
00202     void Statements()
00203     {
00204         while(_token != _SC('}') && _token != TK_DEFAULT && _token != TK_CASE) {
00205             Statement();
00206             if(_lex._prevtoken != _SC('}') && _lex._prevtoken != _SC(';')) OptionalSemicolon();
00207         }
00208     }
00209     void Statement(bool closeframe = true)
00210     {
00211         _fs->AddLineInfos(_lex._currentline, _lineinfo);
00212         switch(_token){
00213         case _SC(';'):  Lex();                  break;
00214         case TK_IF:     IfStatement();          break;
00215         case TK_WHILE:      WhileStatement();       break;
00216         case TK_DO:     DoWhileStatement();     break;
00217         case TK_FOR:        ForStatement();         break;
00218         case TK_FOREACH:    ForEachStatement();     break;
00219         case TK_SWITCH: SwitchStatement();      break;
00220         case TK_LOCAL:      LocalDeclStatement();   break;
00221         case TK_RETURN:
00222         case TK_YIELD: {
00223             SQOpcode op;
00224             if(_token == TK_RETURN) {
00225                 op = _OP_RETURN;
00226             }
00227             else {
00228                 op = _OP_YIELD;
00229                 _fs->_bgenerator = true;
00230             }
00231             Lex();
00232             if(!IsEndOfStatement()) {
00233                 SQInteger retexp = _fs->GetCurrentPos()+1;
00234                 CommaExpr();
00235                 if(op == _OP_RETURN && _fs->_traps > 0)
00236                     _fs->AddInstruction(_OP_POPTRAP, _fs->_traps, 0);
00237                 _fs->_returnexp = retexp;
00238                 _fs->AddInstruction(op, 1, _fs->PopTarget(),_fs->GetStackSize());
00239             }
00240             else{ 
00241                 if(op == _OP_RETURN && _fs->_traps > 0)
00242                     _fs->AddInstruction(_OP_POPTRAP, _fs->_traps ,0);
00243                 _fs->_returnexp = -1;
00244                 _fs->AddInstruction(op, 0xFF,0,_fs->GetStackSize()); 
00245             }
00246             break;}
00247         case TK_BREAK:
00248             if(_fs->_breaktargets.size() <= 0)Error(_SC("'break' has to be in a loop block"));
00249             if(_fs->_breaktargets.top() > 0){
00250                 _fs->AddInstruction(_OP_POPTRAP, _fs->_breaktargets.top(), 0);
00251             }
00252             RESOLVE_OUTERS();
00253             _fs->AddInstruction(_OP_JMP, 0, -1234);
00254             _fs->_unresolvedbreaks.push_back(_fs->GetCurrentPos());
00255             Lex();
00256             break;
00257         case TK_CONTINUE:
00258             if(_fs->_continuetargets.size() <= 0)Error(_SC("'continue' has to be in a loop block"));
00259             if(_fs->_continuetargets.top() > 0) {
00260                 _fs->AddInstruction(_OP_POPTRAP, _fs->_continuetargets.top(), 0);
00261             }
00262             RESOLVE_OUTERS();
00263             _fs->AddInstruction(_OP_JMP, 0, -1234);
00264             _fs->_unresolvedcontinues.push_back(_fs->GetCurrentPos());
00265             Lex();
00266             break;
00267         case TK_FUNCTION:
00268             FunctionStatement();
00269             break;
00270         case TK_CLASS:
00271             ClassStatement();
00272             break;
00273         case TK_ENUM:
00274             EnumStatement();
00275             break;
00276         case _SC('{'):{
00277                 BEGIN_SCOPE();
00278                 Lex();
00279                 Statements();
00280                 Expect(_SC('}'));
00281                 if(closeframe) {
00282                     END_SCOPE();
00283                 }
00284                 else {
00285                     END_SCOPE_NO_CLOSE();
00286                 }
00287             }
00288             break;
00289         case TK_TRY:
00290             TryCatchStatement();
00291             break;
00292         case TK_THROW:
00293             Lex();
00294             CommaExpr();
00295             _fs->AddInstruction(_OP_THROW, _fs->PopTarget());
00296             break;
00297         case TK_CONST:
00298             {
00299             Lex();
00300             SQObject id = Expect(TK_IDENTIFIER);
00301             Expect('=');
00302             SQObject val = ExpectScalar();
00303             OptionalSemicolon();
00304             SQTable *enums = _table(_ss(_vm)->_consts);
00305             SQObjectPtr strongid = id; 
00306             enums->NewSlot(strongid,SQObjectPtr(val));
00307             strongid.Null();
00308             }
00309             break;
00310         default:
00311             CommaExpr();
00312             _fs->DiscardTarget();
00313             //_fs->PopTarget();
00314             break;
00315         }
00316         _fs->SnoozeOpt();
00317     }
00318     void EmitDerefOp(SQOpcode op)
00319     {
00320         SQInteger val = _fs->PopTarget();
00321         SQInteger key = _fs->PopTarget();
00322         SQInteger src = _fs->PopTarget();
00323         _fs->AddInstruction(op,_fs->PushTarget(),src,key,val);
00324     }
00325     void Emit2ArgsOP(SQOpcode op, SQInteger p3 = 0)
00326     {
00327         SQInteger p2 = _fs->PopTarget(); //src in OP_GET
00328         SQInteger p1 = _fs->PopTarget(); //key in OP_GET
00329         _fs->AddInstruction(op,_fs->PushTarget(), p1, p2, p3);
00330     }
00331     void EmitCompoundArith(SQInteger tok, SQInteger etype, SQInteger pos)
00332     {
00333         /* Generate code depending on the expression type */
00334         switch(etype) {
00335         case LOCAL:{
00336             SQInteger p2 = _fs->PopTarget(); //src in OP_GET
00337             SQInteger p1 = _fs->PopTarget(); //key in OP_GET
00338             _fs->PushTarget(p1);
00339             //EmitCompArithLocal(tok, p1, p1, p2);
00340             _fs->AddInstruction(ChooseArithOpByToken(tok),p1, p2, p1, 0);
00341             _fs->SnoozeOpt();
00342                    }
00343             break;
00344         case OBJECT:
00345         case BASE:
00346             {
00347                 SQInteger val = _fs->PopTarget();
00348                 SQInteger key = _fs->PopTarget();
00349                 SQInteger src = _fs->PopTarget();
00350                 /* _OP_COMPARITH mixes dest obj and source val in the arg1 */
00351                 _fs->AddInstruction(_OP_COMPARITH, _fs->PushTarget(), (src<<16)|val, key, ChooseCompArithCharByToken(tok));
00352             }
00353             break;
00354         case OUTER:
00355             {
00356                 SQInteger val = _fs->TopTarget();
00357                 SQInteger tmp = _fs->PushTarget();
00358                 _fs->AddInstruction(_OP_GETOUTER,   tmp, pos);
00359                 _fs->AddInstruction(ChooseArithOpByToken(tok), tmp, val, tmp, 0);
00360                 _fs->AddInstruction(_OP_SETOUTER, tmp, pos, tmp);
00361             }
00362             break;
00363         }
00364     }
00365     void CommaExpr()
00366     {
00367         for(Expression();_token == ',';_fs->PopTarget(), Lex(), CommaExpr());
00368     }
00369     void Expression()
00370     {
00371          SQExpState es = _es;
00372         _es.etype     = EXPR;
00373         _es.epos      = -1;
00374         _es.donot_get = false;
00375         LogicalOrExp();
00376         switch(_token)  {
00377         case _SC('='):
00378         case TK_NEWSLOT:
00379         case TK_MINUSEQ:
00380         case TK_PLUSEQ:
00381         case TK_MULEQ:
00382         case TK_DIVEQ:
00383         case TK_MODEQ:{
00384             SQInteger op = _token;
00385             SQInteger ds = _es.etype;
00386             SQInteger pos = _es.epos;
00387             if(ds == EXPR) Error(_SC("can't assign expression"));
00388             else if(ds == BASE) Error(_SC("'base' cannot be modified"));
00389 
00390             Lex(); Expression();
00391 
00392             switch(op){
00393             case TK_NEWSLOT:
00394                 if(ds == OBJECT || ds == BASE)
00395                     EmitDerefOp(_OP_NEWSLOT);
00396                 else //if _derefstate != DEREF_NO_DEREF && DEREF_FIELD so is the index of a local
00397                     Error(_SC("can't 'create' a local slot"));
00398                 break;
00399             case _SC('='): //ASSIGN
00400                 switch(ds) {
00401                 case LOCAL:
00402                     {
00403                         SQInteger src = _fs->PopTarget();
00404                         SQInteger dst = _fs->TopTarget();
00405                         _fs->AddInstruction(_OP_MOVE, dst, src);
00406                     }
00407                     break;
00408                 case OBJECT:
00409                 case BASE:
00410                     EmitDerefOp(_OP_SET);
00411                     break;
00412                 case OUTER:
00413                     {
00414                         SQInteger src = _fs->PopTarget();
00415                         SQInteger dst = _fs->PushTarget();
00416                         _fs->AddInstruction(_OP_SETOUTER, dst, pos, src);
00417                     }
00418                 }
00419                 break;
00420             case TK_MINUSEQ:
00421             case TK_PLUSEQ:
00422             case TK_MULEQ:
00423             case TK_DIVEQ:
00424             case TK_MODEQ:
00425                 EmitCompoundArith(op, ds, pos);
00426                 break;
00427             }
00428             }
00429             break;
00430         case _SC('?'): {
00431             Lex();
00432             _fs->AddInstruction(_OP_JZ, _fs->PopTarget());
00433             SQInteger jzpos = _fs->GetCurrentPos();
00434             SQInteger trg = _fs->PushTarget();
00435             Expression();
00436             SQInteger first_exp = _fs->PopTarget();
00437             if(trg != first_exp) _fs->AddInstruction(_OP_MOVE, trg, first_exp);
00438             SQInteger endfirstexp = _fs->GetCurrentPos();
00439             _fs->AddInstruction(_OP_JMP, 0, 0);
00440             Expect(_SC(':'));
00441             SQInteger jmppos = _fs->GetCurrentPos();
00442             Expression();
00443             SQInteger second_exp = _fs->PopTarget();
00444             if(trg != second_exp) _fs->AddInstruction(_OP_MOVE, trg, second_exp);
00445             _fs->SetIntructionParam(jmppos, 1, _fs->GetCurrentPos() - jmppos);
00446             _fs->SetIntructionParam(jzpos, 1, endfirstexp - jzpos + 1);
00447             _fs->SnoozeOpt();
00448             }
00449             break;
00450         }
00451         _es = es;
00452     }
00453     template<typename T> void INVOKE_EXP(T f)
00454     {
00455         SQExpState es = _es;
00456         _es.etype     = EXPR;
00457         _es.epos      = -1;
00458         _es.donot_get = false;
00459         (this->*f)();
00460         _es = es;
00461     }
00462     template<typename T> void BIN_EXP(SQOpcode op, T f,SQInteger op3 = 0)
00463     {
00464         Lex(); 
00465         INVOKE_EXP(f);
00466         SQInteger op1 = _fs->PopTarget();SQInteger op2 = _fs->PopTarget();
00467         _fs->AddInstruction(op, _fs->PushTarget(), op1, op2, op3);
00468     }
00469     void LogicalOrExp()
00470     {
00471         LogicalAndExp();
00472         for(;;) if(_token == TK_OR) {
00473             SQInteger first_exp = _fs->PopTarget();
00474             SQInteger trg = _fs->PushTarget();
00475             _fs->AddInstruction(_OP_OR, trg, 0, first_exp, 0);
00476             SQInteger jpos = _fs->GetCurrentPos();
00477             if(trg != first_exp) _fs->AddInstruction(_OP_MOVE, trg, first_exp);
00478             Lex(); INVOKE_EXP(&SQCompiler::LogicalOrExp);
00479             _fs->SnoozeOpt();
00480             SQInteger second_exp = _fs->PopTarget();
00481             if(trg != second_exp) _fs->AddInstruction(_OP_MOVE, trg, second_exp);
00482             _fs->SnoozeOpt();
00483             _fs->SetIntructionParam(jpos, 1, (_fs->GetCurrentPos() - jpos));
00484             break;
00485         }else return;
00486     }
00487     void LogicalAndExp()
00488     {
00489         BitwiseOrExp();
00490         for(;;) switch(_token) {
00491         case TK_AND: {
00492             SQInteger first_exp = _fs->PopTarget();
00493             SQInteger trg = _fs->PushTarget();
00494             _fs->AddInstruction(_OP_AND, trg, 0, first_exp, 0);
00495             SQInteger jpos = _fs->GetCurrentPos();
00496             if(trg != first_exp) _fs->AddInstruction(_OP_MOVE, trg, first_exp);
00497             Lex(); INVOKE_EXP(&SQCompiler::LogicalAndExp);
00498             _fs->SnoozeOpt();
00499             SQInteger second_exp = _fs->PopTarget();
00500             if(trg != second_exp) _fs->AddInstruction(_OP_MOVE, trg, second_exp);
00501             _fs->SnoozeOpt();
00502             _fs->SetIntructionParam(jpos, 1, (_fs->GetCurrentPos() - jpos));
00503             break;
00504             }
00505     
00506         default:
00507             return;
00508         }
00509     }
00510     void BitwiseOrExp()
00511     {
00512         BitwiseXorExp();
00513         for(;;) if(_token == _SC('|'))
00514         {BIN_EXP(_OP_BITW, &SQCompiler::BitwiseXorExp,BW_OR);
00515         }else return;
00516     }
00517     void BitwiseXorExp()
00518     {
00519         BitwiseAndExp();
00520         for(;;) if(_token == _SC('^'))
00521         {BIN_EXP(_OP_BITW, &SQCompiler::BitwiseAndExp,BW_XOR);
00522         }else return;
00523     }
00524     void BitwiseAndExp()
00525     {
00526         EqExp();
00527         for(;;) if(_token == _SC('&'))
00528         {BIN_EXP(_OP_BITW, &SQCompiler::EqExp,BW_AND);
00529         }else return;
00530     }
00531     void EqExp()
00532     {
00533         CompExp();
00534         for(;;) switch(_token) {
00535         case TK_EQ: BIN_EXP(_OP_EQ, &SQCompiler::CompExp); break;
00536         case TK_NE: BIN_EXP(_OP_NE, &SQCompiler::CompExp); break;
00537         case TK_3WAYSCMP: BIN_EXP(_OP_CMP, &SQCompiler::CompExp,CMP_3W); break;
00538         default: return;    
00539         }
00540     }
00541     void CompExp()
00542     {
00543         ShiftExp();
00544         for(;;) switch(_token) {
00545         case _SC('>'): BIN_EXP(_OP_CMP, &SQCompiler::ShiftExp,CMP_G); break;
00546         case _SC('<'): BIN_EXP(_OP_CMP, &SQCompiler::ShiftExp,CMP_L); break;
00547         case TK_GE: BIN_EXP(_OP_CMP, &SQCompiler::ShiftExp,CMP_GE); break;
00548         case TK_LE: BIN_EXP(_OP_CMP, &SQCompiler::ShiftExp,CMP_LE); break;
00549         case TK_IN: BIN_EXP(_OP_EXISTS, &SQCompiler::ShiftExp); break;
00550         case TK_INSTANCEOF: BIN_EXP(_OP_INSTANCEOF, &SQCompiler::ShiftExp); break;
00551         default: return;    
00552         }
00553     }
00554     void ShiftExp()
00555     {
00556         PlusExp();
00557         for(;;) switch(_token) {
00558         case TK_USHIFTR: BIN_EXP(_OP_BITW, &SQCompiler::PlusExp,BW_USHIFTR); break;
00559         case TK_SHIFTL: BIN_EXP(_OP_BITW, &SQCompiler::PlusExp,BW_SHIFTL); break;
00560         case TK_SHIFTR: BIN_EXP(_OP_BITW, &SQCompiler::PlusExp,BW_SHIFTR); break;
00561         default: return;    
00562         }
00563     }
00564     SQOpcode ChooseArithOpByToken(SQInteger tok)
00565     {
00566         switch(tok) {
00567             case TK_PLUSEQ: case '+': return _OP_ADD;
00568             case TK_MINUSEQ: case '-': return _OP_SUB;
00569             case TK_MULEQ: case '*': return _OP_MUL;
00570             case TK_DIVEQ: case '/': return _OP_DIV;
00571             case TK_MODEQ: case '%': return _OP_MOD;
00572             default: assert(0);
00573         }
00574         return _OP_ADD;
00575     }
00576     SQInteger ChooseCompArithCharByToken(SQInteger tok)
00577     {
00578         SQInteger oper;
00579         switch(tok){
00580         case TK_MINUSEQ: oper = '-'; break;
00581         case TK_PLUSEQ: oper = '+'; break;
00582         case TK_MULEQ: oper = '*'; break;
00583         case TK_DIVEQ: oper = '/'; break;
00584         case TK_MODEQ: oper = '%'; break;
00585         default: oper = 0; //shut up compiler
00586             assert(0); break;
00587         };
00588         return oper;
00589     }
00590     void PlusExp()
00591     {
00592         MultExp();
00593         for(;;) switch(_token) {
00594         case _SC('+'): case _SC('-'):
00595             BIN_EXP(ChooseArithOpByToken(_token), &SQCompiler::MultExp); break;
00596         default: return;
00597         }
00598     }
00599     
00600     void MultExp()
00601     {
00602         PrefixedExpr();
00603         for(;;) switch(_token) {
00604         case _SC('*'): case _SC('/'): case _SC('%'):
00605             BIN_EXP(ChooseArithOpByToken(_token), &SQCompiler::PrefixedExpr); break;
00606         default: return;
00607         }
00608     }
00609     //if 'pos' != -1 the previous variable is a local variable
00610     void PrefixedExpr()
00611     {
00612         SQInteger pos = Factor();
00613         for(;;) {
00614             switch(_token) {
00615             case _SC('.'):
00616                 pos = -1;
00617                 Lex(); 
00618 
00619                 _fs->AddInstruction(_OP_LOAD, _fs->PushTarget(), _fs->GetConstant(Expect(TK_IDENTIFIER)));
00620                 if(_es.etype==BASE) {
00621                     Emit2ArgsOP(_OP_GET);
00622                     pos = _fs->TopTarget();
00623                     _es.etype = EXPR;
00624                     _es.epos   = pos;
00625                 }
00626                 else {
00627                     if(NeedGet()) {
00628                         Emit2ArgsOP(_OP_GET);
00629                     }
00630                     _es.etype = OBJECT;
00631                 }
00632                 break;
00633             case _SC('['):
00634                 if(_lex._prevtoken == _SC('\n')) Error(_SC("cannot brake deref/or comma needed after [exp]=exp slot declaration"));
00635                 Lex(); Expression(); Expect(_SC(']')); 
00636                 pos = -1;
00637                 if(_es.etype==BASE) {
00638                     Emit2ArgsOP(_OP_GET);
00639                     pos = _fs->TopTarget();
00640                     _es.etype = EXPR;
00641                     _es.epos   = pos;
00642                 }
00643                 else {
00644                     if(NeedGet()) {
00645                         Emit2ArgsOP(_OP_GET);
00646                     }
00647                     _es.etype = OBJECT;
00648                 }
00649                 break;
00650             case TK_MINUSMINUS:
00651             case TK_PLUSPLUS:
00652                 {
00653                     if(IsEndOfStatement()) return;
00654                     SQInteger diff = (_token==TK_MINUSMINUS) ? -1 : 1;
00655                     Lex();
00656                     switch(_es.etype)
00657                     {
00658                         case EXPR: Error(_SC("can't '++' or '--' an expression")); break;
00659                         case OBJECT:
00660                         case BASE:
00661                             Emit2ArgsOP(_OP_PINC, diff);
00662                             break;
00663                         case LOCAL: {
00664                             SQInteger src = _fs->PopTarget();
00665                             _fs->AddInstruction(_OP_PINCL, _fs->PushTarget(), src, 0, diff);
00666                                     }
00667                             break;
00668                         case OUTER: {
00669                             SQInteger tmp1 = _fs->PushTarget();
00670                             SQInteger tmp2 = _fs->PushTarget();
00671                             _fs->AddInstruction(_OP_GETOUTER, tmp2, _es.epos);
00672                             _fs->AddInstruction(_OP_PINCL,    tmp1, tmp2, 0, diff);
00673                             _fs->AddInstruction(_OP_SETOUTER, tmp2, _es.epos, tmp2);
00674                             _fs->PopTarget();
00675                         }
00676                     }
00677                 }
00678                 return;
00679                 break;  
00680             case _SC('('): 
00681                 switch(_es.etype) {
00682                     case OBJECT: {
00683                         SQInteger key     = _fs->PopTarget();  /* location of the key */
00684                         SQInteger table   = _fs->PopTarget();  /* location of the object */
00685                         SQInteger closure = _fs->PushTarget(); /* location for the closure */
00686                         SQInteger ttarget = _fs->PushTarget(); /* location for 'this' pointer */
00687                         _fs->AddInstruction(_OP_PREPCALL, closure, key, table, ttarget);
00688                         }
00689                         break;
00690                     case BASE:
00691                         //Emit2ArgsOP(_OP_GET);
00692                         _fs->AddInstruction(_OP_MOVE, _fs->PushTarget(), 0);
00693                         break;
00694                     case OUTER:
00695                         _fs->AddInstruction(_OP_GETOUTER, _fs->PushTarget(), _es.epos);
00696                         _fs->AddInstruction(_OP_MOVE,     _fs->PushTarget(), 0);
00697                         break;
00698                     default:
00699                         _fs->AddInstruction(_OP_MOVE, _fs->PushTarget(), 0);
00700                 }
00701                 _es.etype = EXPR;
00702                 Lex();
00703                 FunctionCallArgs();
00704                 break;
00705             default: return;
00706             }
00707         }
00708     }
00709     SQInteger Factor()
00710     {
00711         _es.etype = EXPR;
00712         switch(_token)
00713         {
00714         case TK_STRING_LITERAL:
00715             _fs->AddInstruction(_OP_LOAD, _fs->PushTarget(), _fs->GetConstant(_fs->CreateString(_lex._svalue,_lex._longstr.size()-1)));
00716             Lex(); 
00717             break;
00718         case TK_BASE:
00719             Lex();
00720             _fs->AddInstruction(_OP_GETBASE, _fs->PushTarget());
00721             _es.etype  = BASE;
00722             _es.epos   = _fs->TopTarget();
00723             return (_es.epos);
00724             break;
00725         case TK_IDENTIFIER:
00726         case TK_CONSTRUCTOR:
00727         case TK_THIS:{
00728                 SQObject id;
00729                 SQObject constant;
00730 
00731                 switch(_token) {
00732                     case TK_IDENTIFIER:  id = _fs->CreateString(_lex._svalue);       break;
00733                     case TK_THIS:        id = _fs->CreateString(_SC("this"));        break;
00734                     case TK_CONSTRUCTOR: id = _fs->CreateString(_SC("constructor")); break;
00735                 }
00736 
00737                 SQInteger pos = -1;
00738                 Lex();
00739                 if((pos = _fs->GetLocalVariable(id)) != -1) {
00740                     /* Handle a local variable (includes 'this') */
00741                     _fs->PushTarget(pos);
00742                     _es.etype  = LOCAL;
00743                     _es.epos   = pos;
00744                 }
00745 
00746                 else if((pos = _fs->GetOuterVariable(id)) != -1) {
00747                     /* Handle a free var */
00748                     if(NeedGet()) {
00749                         _es.epos  = _fs->PushTarget();
00750                         _fs->AddInstruction(_OP_GETOUTER, _es.epos, pos);   
00751                         /* _es.etype = EXPR; already default value */
00752                     }
00753                     else {
00754                         _es.etype = OUTER;
00755                         _es.epos  = pos;
00756                     }
00757                 }
00758 
00759                 else if(_fs->IsConstant(id, constant)) {
00760                     /* Handle named constant */
00761                     SQObjectPtr constval;
00762                     SQObject    constid;
00763                     if(type(constant) == OT_TABLE) {
00764                         Expect('.');
00765                         constid = Expect(TK_IDENTIFIER);
00766                         if(!_table(constant)->Get(constid, constval)) {
00767                             constval.Null();
00768                             Error(_SC("invalid constant [%s.%s]"), _stringval(id), _stringval(constid));
00769                         }
00770                     }
00771                     else {
00772                         constval = constant;
00773                     }
00774                     _es.epos = _fs->PushTarget();
00775 
00776                     /* generate direct or literal function depending on size */
00777                     SQObjectType ctype = type(constval);
00778                     switch(ctype) {
00779                         case OT_INTEGER: EmitLoadConstInt(_integer(constval),_es.epos); break;
00780                         case OT_FLOAT: EmitLoadConstFloat(_float(constval),_es.epos); break;
00781                         default: _fs->AddInstruction(_OP_LOAD,_es.epos,_fs->GetConstant(constval)); break;
00782                     }
00783                     _es.etype = EXPR;
00784                 }
00785                 else {
00786                     /* Handle a non-local variable, aka a field. Push the 'this' pointer on
00787                     * the virtual stack (always found in offset 0, so no instruction needs to
00788                     * be generated), and push the key next. Generate an _OP_LOAD instruction
00789                     * for the latter. If we are not using the variable as a dref expr, generate
00790                     * the _OP_GET instruction.
00791                     */
00792                     _fs->PushTarget(0);
00793                     _fs->AddInstruction(_OP_LOAD, _fs->PushTarget(), _fs->GetConstant(id));
00794                     if(NeedGet()) {
00795                         Emit2ArgsOP(_OP_GET);
00796                     }
00797                     _es.etype = OBJECT;
00798                 }
00799                 return _es.epos;
00800             }
00801             break;
00802         case TK_DOUBLE_COLON:  // "::"
00803             _fs->AddInstruction(_OP_LOADROOT, _fs->PushTarget());
00804             _es.etype = OBJECT;
00805             _token = _SC('.'); /* hack: drop into PrefixExpr, case '.'*/
00806             _es.epos = -1;
00807             return _es.epos;
00808             break;
00809         case TK_NULL: 
00810             _fs->AddInstruction(_OP_LOADNULLS, _fs->PushTarget(),1);
00811             Lex();
00812             break;
00813         case TK_INTEGER: EmitLoadConstInt(_lex._nvalue,-1); Lex();  break;
00814         case TK_FLOAT: EmitLoadConstFloat(_lex._fvalue,-1); Lex(); break;
00815         case TK_TRUE: case TK_FALSE:
00816             _fs->AddInstruction(_OP_LOADBOOL, _fs->PushTarget(),_token == TK_TRUE?1:0);
00817             Lex();
00818             break;
00819         case _SC('['): {
00820                 _fs->AddInstruction(_OP_NEWOBJ, _fs->PushTarget(),0,0,NOT_ARRAY);
00821                 SQInteger apos = _fs->GetCurrentPos(),key = 0;
00822                 Lex();
00823                 while(_token != _SC(']')) {
00824                     Expression(); 
00825                     if(_token == _SC(',')) Lex();
00826                     SQInteger val = _fs->PopTarget();
00827                     SQInteger array = _fs->TopTarget();
00828                     _fs->AddInstruction(_OP_APPENDARRAY, array, val, AAT_STACK);
00829                     key++;
00830                 }
00831                 _fs->SetIntructionParam(apos, 1, key);
00832                 Lex();
00833             }
00834             break;
00835         case _SC('{'):
00836             _fs->AddInstruction(_OP_NEWOBJ, _fs->PushTarget(),0,NOT_TABLE);
00837             Lex();ParseTableOrClass(_SC(','),_SC('}'));
00838             break;
00839         case TK_FUNCTION: FunctionExp(_token);break;
00840         case _SC('@'): FunctionExp(_token,true);break;
00841         case TK_CLASS: Lex(); ClassExp();break;
00842         case _SC('-'): 
00843             Lex(); 
00844             switch(_token) {
00845             case TK_INTEGER: EmitLoadConstInt(-_lex._nvalue,-1); Lex(); break;
00846             case TK_FLOAT: EmitLoadConstFloat(-_lex._fvalue,-1); Lex(); break;
00847             default: UnaryOP(_OP_NEG);
00848             }
00849             break;
00850         case _SC('!'): Lex(); UnaryOP(_OP_NOT); break;
00851         case _SC('~'): 
00852             Lex(); 
00853             if(_token == TK_INTEGER)  { EmitLoadConstInt(~_lex._nvalue,-1); Lex(); break; }
00854             UnaryOP(_OP_BWNOT); 
00855             break;
00856         case TK_TYPEOF : Lex() ;UnaryOP(_OP_TYPEOF); break;
00857         case TK_RESUME : Lex(); UnaryOP(_OP_RESUME); break;
00858         case TK_CLONE : Lex(); UnaryOP(_OP_CLONE); break;
00859         case TK_MINUSMINUS : 
00860         case TK_PLUSPLUS :PrefixIncDec(_token); break;
00861         case TK_DELETE : DeleteExpr(); break;
00862         case _SC('('): Lex(); CommaExpr(); Expect(_SC(')'));
00863             break;
00864         default: Error(_SC("expression expected"));
00865         }
00866         return -1;
00867     }
00868     void EmitLoadConstInt(SQInteger value,SQInteger target)
00869     {
00870         if(target < 0) {
00871             target = _fs->PushTarget();
00872         }
00873         if((value & (~((SQInteger)0xFFFFFFFF))) == 0) { //does it fit in 32 bits?
00874             _fs->AddInstruction(_OP_LOADINT, target,value);
00875         }
00876         else {
00877             _fs->AddInstruction(_OP_LOAD, target, _fs->GetNumericConstant(value));
00878         }
00879     }
00880     void EmitLoadConstFloat(SQFloat value,SQInteger target)
00881     {
00882         if(target < 0) {
00883             target = _fs->PushTarget();
00884         }
00885         if(sizeof(SQFloat) == sizeof(SQInt32)) {
00886             _fs->AddInstruction(_OP_LOADFLOAT, target,*((SQInt32 *)&value));
00887         }
00888         else {
00889             _fs->AddInstruction(_OP_LOAD, target, _fs->GetNumericConstant(value));
00890         }
00891     }
00892     void UnaryOP(SQOpcode op)
00893     {
00894         PrefixedExpr();
00895         SQInteger src = _fs->PopTarget();
00896         _fs->AddInstruction(op, _fs->PushTarget(), src);
00897     }
00898     bool NeedGet()
00899     {
00900         switch(_token) {
00901         case _SC('='): case _SC('('): case TK_NEWSLOT: case TK_MODEQ: case TK_MULEQ:
00902         case TK_DIVEQ: case TK_MINUSEQ: case TK_PLUSEQ: case TK_PLUSPLUS: case TK_MINUSMINUS:
00903             return false;
00904         }
00905         return (!_es.donot_get || ( _es.donot_get && (_token == _SC('.') || _token == _SC('['))));
00906     }
00907     void FunctionCallArgs()
00908     {
00909         SQInteger nargs = 1;//this
00910          while(_token != _SC(')')) {
00911              Expression();
00912              MoveIfCurrentTargetIsLocal();
00913              nargs++; 
00914              if(_token == _SC(',')){ 
00915                  Lex(); 
00916                  if(_token == ')') Error(_SC("expression expected, found ')'"));
00917              }
00918          }
00919          Lex();
00920          for(SQInteger i = 0; i < (nargs - 1); i++) _fs->PopTarget();
00921          SQInteger stackbase = _fs->PopTarget();
00922          SQInteger closure = _fs->PopTarget();
00923          _fs->AddInstruction(_OP_CALL, _fs->PushTarget(), closure, stackbase, nargs);
00924     }
00925     void ParseTableOrClass(SQInteger separator,SQInteger terminator)
00926     {
00927         SQInteger tpos = _fs->GetCurrentPos(),nkeys = 0;
00928         while(_token != terminator) {
00929             bool hasattrs = false;
00930             bool isstatic = false;
00931             //check if is an attribute
00932             if(separator == ';') {
00933                 if(_token == TK_ATTR_OPEN) {
00934                     _fs->AddInstruction(_OP_NEWOBJ, _fs->PushTarget(),0,NOT_TABLE); Lex();
00935                     ParseTableOrClass(',',TK_ATTR_CLOSE);
00936                     hasattrs = true;
00937                 }
00938                 if(_token == TK_STATIC) {
00939                     isstatic = true;
00940                     Lex();
00941                 }
00942             }
00943             switch(_token) {
00944             case TK_FUNCTION:
00945             case TK_CONSTRUCTOR:{
00946                 SQInteger tk = _token;
00947                 Lex();
00948                 SQObject id = tk == TK_FUNCTION ? Expect(TK_IDENTIFIER) : _fs->CreateString(_SC("constructor"));
00949                 Expect(_SC('('));
00950                 _fs->AddInstruction(_OP_LOAD, _fs->PushTarget(), _fs->GetConstant(id));
00951                 CreateFunction(id);
00952                 _fs->AddInstruction(_OP_CLOSURE, _fs->PushTarget(), _fs->_functions.size() - 1, 0);
00953                                 }
00954                                 break;
00955             case _SC('['):
00956                 Lex(); CommaExpr(); Expect(_SC(']'));
00957                 Expect(_SC('=')); Expression();
00958                 break;
00959             case TK_STRING_LITERAL: //JSON
00960                 if(separator == ',') { //only works for tables
00961                     _fs->AddInstruction(_OP_LOAD, _fs->PushTarget(), _fs->GetConstant(Expect(TK_STRING_LITERAL)));
00962                     Expect(_SC(':')); Expression();
00963                     break;
00964                 }
00965             default :
00966                 _fs->AddInstruction(_OP_LOAD, _fs->PushTarget(), _fs->GetConstant(Expect(TK_IDENTIFIER)));
00967                 Expect(_SC('=')); Expression();
00968             }
00969             if(_token == separator) Lex();//optional comma/semicolon
00970             nkeys++;
00971             SQInteger val = _fs->PopTarget();
00972             SQInteger key = _fs->PopTarget();
00973             SQInteger attrs = hasattrs ? _fs->PopTarget():-1;
00974             assert((hasattrs && (attrs == key-1)) || !hasattrs);
00975             unsigned char flags = (hasattrs?NEW_SLOT_ATTRIBUTES_FLAG:0)|(isstatic?NEW_SLOT_STATIC_FLAG:0);
00976             SQInteger table = _fs->TopTarget(); //<<BECAUSE OF THIS NO COMMON EMIT FUNC IS POSSIBLE
00977             if(separator == _SC(',')) { //hack recognizes a table from the separator
00978                 _fs->AddInstruction(_OP_NEWSLOT, 0xFF, table, key, val);
00979             }
00980             else {
00981                 _fs->AddInstruction(_OP_NEWSLOTA, flags, table, key, val); //this for classes only as it invokes _newmember
00982             }
00983         }
00984         if(separator == _SC(',')) //hack recognizes a table from the separator
00985             _fs->SetIntructionParam(tpos, 1, nkeys);
00986         Lex();
00987     }
00988     void LocalDeclStatement()
00989     {
00990         SQObject varname;
00991         Lex();
00992         if( _token == TK_FUNCTION) {
00993             Lex();
00994             varname = Expect(TK_IDENTIFIER);
00995             Expect(_SC('('));
00996             CreateFunction(varname,false);
00997             _fs->AddInstruction(_OP_CLOSURE, _fs->PushTarget(), _fs->_functions.size() - 1, 0);
00998             _fs->PopTarget();
00999             _fs->PushLocalVariable(varname);
01000             return;
01001         }
01002 
01003         do {
01004             varname = Expect(TK_IDENTIFIER);
01005             if(_token == _SC('=')) {
01006                 Lex(); Expression();
01007                 SQInteger src = _fs->PopTarget();
01008                 SQInteger dest = _fs->PushTarget();
01009                 if(dest != src) _fs->AddInstruction(_OP_MOVE, dest, src);
01010             }
01011             else{
01012                 _fs->AddInstruction(_OP_LOADNULLS, _fs->PushTarget(),1);
01013             }
01014             _fs->PopTarget();
01015             _fs->PushLocalVariable(varname);
01016             if(_token == _SC(',')) Lex(); else break;
01017         } while(1);
01018     }
01019     void IfStatement()
01020     {
01021         SQInteger jmppos;
01022         bool haselse = false;
01023         Lex(); Expect(_SC('(')); CommaExpr(); Expect(_SC(')'));
01024         _fs->AddInstruction(_OP_JZ, _fs->PopTarget());
01025         SQInteger jnepos = _fs->GetCurrentPos();
01026         BEGIN_SCOPE();
01027         
01028         Statement();
01029         //
01030         if(_token != _SC('}') && _token != TK_ELSE) OptionalSemicolon();
01031         
01032         END_SCOPE();
01033         SQInteger endifblock = _fs->GetCurrentPos();
01034         if(_token == TK_ELSE){
01035             haselse = true;
01036             BEGIN_SCOPE();
01037             _fs->AddInstruction(_OP_JMP);
01038             jmppos = _fs->GetCurrentPos();
01039             Lex();
01040             Statement(); if(_lex._prevtoken != _SC('}')) OptionalSemicolon();
01041             END_SCOPE();
01042             _fs->SetIntructionParam(jmppos, 1, _fs->GetCurrentPos() - jmppos);
01043         }
01044         _fs->SetIntructionParam(jnepos, 1, endifblock - jnepos + (haselse?1:0));
01045     }
01046     void WhileStatement()
01047     {
01048         SQInteger jzpos, jmppos;
01049         jmppos = _fs->GetCurrentPos();
01050         Lex(); Expect(_SC('(')); CommaExpr(); Expect(_SC(')'));
01051         
01052         BEGIN_BREAKBLE_BLOCK();
01053         _fs->AddInstruction(_OP_JZ, _fs->PopTarget());
01054         jzpos = _fs->GetCurrentPos();
01055         BEGIN_SCOPE();
01056         
01057         Statement();
01058         
01059         END_SCOPE();
01060         _fs->AddInstruction(_OP_JMP, 0, jmppos - _fs->GetCurrentPos() - 1);
01061         _fs->SetIntructionParam(jzpos, 1, _fs->GetCurrentPos() - jzpos);
01062         
01063         END_BREAKBLE_BLOCK(jmppos);
01064     }
01065     void DoWhileStatement()
01066     {
01067         Lex();
01068         SQInteger jmptrg = _fs->GetCurrentPos();
01069         BEGIN_BREAKBLE_BLOCK()
01070         BEGIN_SCOPE();
01071         Statement();
01072         END_SCOPE();
01073         Expect(TK_WHILE);
01074         SQInteger continuetrg = _fs->GetCurrentPos();
01075         Expect(_SC('(')); CommaExpr(); Expect(_SC(')'));
01076         _fs->AddInstruction(_OP_JZ, _fs->PopTarget(), 1);
01077         _fs->AddInstruction(_OP_JMP, 0, jmptrg - _fs->GetCurrentPos() - 1);
01078         END_BREAKBLE_BLOCK(continuetrg);
01079     }
01080     void ForStatement()
01081     {
01082         Lex();
01083         BEGIN_SCOPE();
01084         Expect(_SC('('));
01085         if(_token == TK_LOCAL) LocalDeclStatement();
01086         else if(_token != _SC(';')){
01087             CommaExpr();
01088             _fs->PopTarget();
01089         }
01090         Expect(_SC(';'));
01091         _fs->SnoozeOpt();
01092         SQInteger jmppos = _fs->GetCurrentPos();
01093         SQInteger jzpos = -1;
01094         if(_token != _SC(';')) { CommaExpr(); _fs->AddInstruction(_OP_JZ, _fs->PopTarget()); jzpos = _fs->GetCurrentPos(); }
01095         Expect(_SC(';'));
01096         _fs->SnoozeOpt();
01097         SQInteger expstart = _fs->GetCurrentPos() + 1;
01098         if(_token != _SC(')')) {
01099             CommaExpr();
01100             _fs->PopTarget();
01101         }
01102         Expect(_SC(')'));
01103         _fs->SnoozeOpt();
01104         SQInteger expend = _fs->GetCurrentPos();
01105         SQInteger expsize = (expend - expstart) + 1;
01106         SQInstructionVec exp;
01107         if(expsize > 0) {
01108             for(SQInteger i = 0; i < expsize; i++)
01109                 exp.push_back(_fs->GetInstruction(expstart + i));
01110             _fs->PopInstructions(expsize);
01111         }
01112         BEGIN_BREAKBLE_BLOCK()
01113         Statement();
01114         SQInteger continuetrg = _fs->GetCurrentPos();
01115         if(expsize > 0) {
01116             for(SQInteger i = 0; i < expsize; i++)
01117                 _fs->AddInstruction(exp[i]);
01118         }
01119         _fs->AddInstruction(_OP_JMP, 0, jmppos - _fs->GetCurrentPos() - 1, 0);
01120         if(jzpos>  0) _fs->SetIntructionParam(jzpos, 1, _fs->GetCurrentPos() - jzpos);
01121         END_SCOPE();
01122         
01123         END_BREAKBLE_BLOCK(continuetrg);
01124     }
01125     void ForEachStatement()
01126     {
01127         SQObject idxname, valname;
01128         Lex(); Expect(_SC('(')); valname = Expect(TK_IDENTIFIER);
01129         if(_token == _SC(',')) {
01130             idxname = valname;
01131             Lex(); valname = Expect(TK_IDENTIFIER);
01132         }
01133         else{
01134             idxname = _fs->CreateString(_SC("@INDEX@"));
01135         }
01136         Expect(TK_IN);
01137         
01138         //save the stack size
01139         BEGIN_SCOPE();
01140         //put the table in the stack(evaluate the table expression)
01141         Expression(); Expect(_SC(')'));
01142         SQInteger container = _fs->TopTarget();
01143         //push the index local var
01144         SQInteger indexpos = _fs->PushLocalVariable(idxname);
01145         _fs->AddInstruction(_OP_LOADNULLS, indexpos,1);
01146         //push the value local var
01147         SQInteger valuepos = _fs->PushLocalVariable(valname);
01148         _fs->AddInstruction(_OP_LOADNULLS, valuepos,1);
01149         //push reference index
01150         SQInteger itrpos = _fs->PushLocalVariable(_fs->CreateString(_SC("@ITERATOR@"))); //use invalid id to make it inaccessible
01151         _fs->AddInstruction(_OP_LOADNULLS, itrpos,1);
01152         SQInteger jmppos = _fs->GetCurrentPos();
01153         _fs->AddInstruction(_OP_FOREACH, container, 0, indexpos);
01154         SQInteger foreachpos = _fs->GetCurrentPos();
01155         _fs->AddInstruction(_OP_POSTFOREACH, container, 0, indexpos);
01156         //generate the statement code
01157         BEGIN_BREAKBLE_BLOCK()
01158         Statement();
01159         _fs->AddInstruction(_OP_JMP, 0, jmppos - _fs->GetCurrentPos() - 1);
01160         _fs->SetIntructionParam(foreachpos, 1, _fs->GetCurrentPos() - foreachpos);
01161         _fs->SetIntructionParam(foreachpos + 1, 1, _fs->GetCurrentPos() - foreachpos);
01162         END_BREAKBLE_BLOCK(foreachpos - 1);
01163         //restore the local variable stack(remove index,val and ref idx)
01164         _fs->PopTarget();
01165         END_SCOPE();
01166     }
01167     void SwitchStatement()
01168     {
01169         Lex(); Expect(_SC('(')); CommaExpr(); Expect(_SC(')'));
01170         Expect(_SC('{'));
01171         SQInteger expr = _fs->TopTarget();
01172         bool bfirst = true;
01173         SQInteger tonextcondjmp = -1;
01174         SQInteger skipcondjmp = -1;
01175         SQInteger __nbreaks__ = _fs->_unresolvedbreaks.size();
01176         _fs->_breaktargets.push_back(0);
01177         while(_token == TK_CASE) {
01178             if(!bfirst) {
01179                 _fs->AddInstruction(_OP_JMP, 0, 0);
01180                 skipcondjmp = _fs->GetCurrentPos();
01181                 _fs->SetIntructionParam(tonextcondjmp, 1, _fs->GetCurrentPos() - tonextcondjmp);
01182             }
01183             //condition
01184             Lex(); Expression(); Expect(_SC(':'));
01185             SQInteger trg = _fs->PopTarget();
01186             SQInteger eqtarget = trg;
01187             bool local = _fs->IsLocal(trg);
01188             if(local) {
01189                 eqtarget = _fs->PushTarget(); //we need to allocate a extra reg
01190             }
01191             _fs->AddInstruction(_OP_EQ, eqtarget, trg, expr);
01192             _fs->AddInstruction(_OP_JZ, eqtarget, 0);
01193             if(local) {
01194                 _fs->PopTarget();
01195             }
01196             
01197             //end condition
01198             if(skipcondjmp != -1) {
01199                 _fs->SetIntructionParam(skipcondjmp, 1, (_fs->GetCurrentPos() - skipcondjmp));
01200             }
01201             tonextcondjmp = _fs->GetCurrentPos();
01202             BEGIN_SCOPE();
01203             Statements();
01204             END_SCOPE();
01205             bfirst = false;
01206         }
01207         if(tonextcondjmp != -1)
01208             _fs->SetIntructionParam(tonextcondjmp, 1, _fs->GetCurrentPos() - tonextcondjmp);
01209         if(_token == TK_DEFAULT) {
01210             Lex(); Expect(_SC(':'));
01211             BEGIN_SCOPE();
01212             Statements();
01213             END_SCOPE();
01214         }
01215         Expect(_SC('}'));
01216         _fs->PopTarget();
01217         __nbreaks__ = _fs->_unresolvedbreaks.size() - __nbreaks__;
01218         if(__nbreaks__ > 0)ResolveBreaks(_fs, __nbreaks__);
01219         _fs->_breaktargets.pop_back();
01220     }
01221     void FunctionStatement()
01222     {
01223         SQObject id;
01224         Lex(); id = Expect(TK_IDENTIFIER);
01225         _fs->PushTarget(0);
01226         _fs->AddInstruction(_OP_LOAD, _fs->PushTarget(), _fs->GetConstant(id));
01227         if(_token == TK_DOUBLE_COLON) Emit2ArgsOP(_OP_GET);
01228         
01229         while(_token == TK_DOUBLE_COLON) {
01230             Lex();
01231             id = Expect(TK_IDENTIFIER);
01232             _fs->AddInstruction(_OP_LOAD, _fs->PushTarget(), _fs->GetConstant(id));
01233             if(_token == TK_DOUBLE_COLON) Emit2ArgsOP(_OP_GET);
01234         }
01235         Expect(_SC('('));
01236         CreateFunction(id);
01237         _fs->AddInstruction(_OP_CLOSURE, _fs->PushTarget(), _fs->_functions.size() - 1, 0);
01238         EmitDerefOp(_OP_NEWSLOT);
01239         _fs->PopTarget();
01240     }
01241     void ClassStatement()
01242     {
01243         SQExpState es;
01244         Lex();
01245         es = _es;
01246         _es.donot_get = true;
01247         PrefixedExpr();
01248         if(_es.etype == EXPR) {
01249             Error(_SC("invalid class name"));
01250         }
01251         else if(_es.etype == OBJECT || _es.etype == BASE) {
01252             ClassExp();
01253             EmitDerefOp(_OP_NEWSLOT);
01254             _fs->PopTarget();
01255         }
01256         else {
01257             Error(_SC("cannot create a class in a local with the syntax(class <local>)"));
01258         }
01259         _es = es;
01260     }
01261     SQObject ExpectScalar()
01262     {
01263         SQObject val;
01264         val._type = OT_NULL; val._unVal.nInteger = 0; //shut up GCC 4.x
01265         switch(_token) {
01266             case TK_INTEGER:
01267                 val._type = OT_INTEGER;
01268                 val._unVal.nInteger = _lex._nvalue;
01269                 break;
01270             case TK_FLOAT:
01271                 val._type = OT_FLOAT;
01272                 val._unVal.fFloat = _lex._fvalue;
01273                 break;
01274             case TK_STRING_LITERAL:
01275                 val = _fs->CreateString(_lex._svalue,_lex._longstr.size()-1);
01276                 break;
01277             case TK_TRUE:
01278             case TK_FALSE:
01279                 val._type = OT_BOOL;
01280                 val._unVal.nInteger = _token == TK_TRUE ? 1 : 0;
01281                 break;
01282             case '-':
01283                 Lex();
01284                 switch(_token)
01285                 {
01286                 case TK_INTEGER:
01287                     val._type = OT_INTEGER;
01288                     val._unVal.nInteger = -_lex._nvalue;
01289                 break;
01290                 case TK_FLOAT:
01291                     val._type = OT_FLOAT;
01292                     val._unVal.fFloat = -_lex._fvalue;
01293                 break;
01294                 default:
01295                     Error(_SC("scalar expected : integer,float"));
01296                 }
01297                 break;
01298             default:
01299                 Error(_SC("scalar expected : integer,float or string"));
01300         }
01301         Lex();
01302         return val;
01303     }
01304     void EnumStatement()
01305     {
01306         Lex(); 
01307         SQObject id = Expect(TK_IDENTIFIER);
01308         Expect(_SC('{'));
01309         
01310         SQObject table = _fs->CreateTable();
01311         SQInteger nval = 0;
01312         while(_token != _SC('}')) {
01313             SQObject key = Expect(TK_IDENTIFIER);
01314             SQObject val;
01315             if(_token == _SC('=')) {
01316                 Lex();
01317                 val = ExpectScalar();
01318             }
01319             else {
01320                 val._type = OT_INTEGER;
01321                 val._unVal.nInteger = nval++;
01322             }
01323             _table(table)->NewSlot(SQObjectPtr(key),SQObjectPtr(val));
01324             if(_token == ',') Lex();
01325         }
01326         SQTable *enums = _table(_ss(_vm)->_consts);
01327         SQObjectPtr strongid = id; 
01328         enums->NewSlot(SQObjectPtr(strongid),SQObjectPtr(table));
01329         strongid.Null();
01330         Lex();
01331     }
01332     void TryCatchStatement()
01333     {
01334         SQObject exid;
01335         Lex();
01336         _fs->AddInstruction(_OP_PUSHTRAP,0,0);
01337         _fs->_traps++;
01338         if(_fs->_breaktargets.size()) _fs->_breaktargets.top()++;
01339         if(_fs->_continuetargets.size()) _fs->_continuetargets.top()++;
01340         SQInteger trappos = _fs->GetCurrentPos();
01341         {
01342             BEGIN_SCOPE();
01343             Statement();
01344             END_SCOPE();
01345         }
01346         _fs->_traps--;
01347         _fs->AddInstruction(_OP_POPTRAP, 1, 0);
01348         if(_fs->_breaktargets.size()) _fs->_breaktargets.top()--;
01349         if(_fs->_continuetargets.size()) _fs->_continuetargets.top()--;
01350         _fs->AddInstruction(_OP_JMP, 0, 0);
01351         SQInteger jmppos = _fs->GetCurrentPos();
01352         _fs->SetIntructionParam(trappos, 1, (_fs->GetCurrentPos() - trappos));
01353         Expect(TK_CATCH); Expect(_SC('(')); exid = Expect(TK_IDENTIFIER); Expect(_SC(')'));
01354         {
01355             BEGIN_SCOPE();
01356             SQInteger ex_target = _fs->PushLocalVariable(exid);
01357             _fs->SetIntructionParam(trappos, 0, ex_target);
01358             Statement();
01359             _fs->SetIntructionParams(jmppos, 0, (_fs->GetCurrentPos() - jmppos), 0);
01360             END_SCOPE();
01361         }
01362     }
01363     void FunctionExp(SQInteger ftype,bool lambda = false)
01364     {
01365         Lex(); Expect(_SC('('));
01366         SQObjectPtr dummy;
01367         CreateFunction(dummy,lambda);
01368         _fs->AddInstruction(_OP_CLOSURE, _fs->PushTarget(), _fs->_functions.size() - 1, ftype == TK_FUNCTION?0:1);
01369     }
01370     void ClassExp()
01371     {
01372         SQInteger base = -1;
01373         SQInteger attrs = -1;
01374         if(_token == TK_EXTENDS) {
01375             Lex(); Expression();
01376             base = _fs->TopTarget();
01377         }
01378         if(_token == TK_ATTR_OPEN) {
01379             Lex();
01380             _fs->AddInstruction(_OP_NEWOBJ, _fs->PushTarget(),0,NOT_TABLE);
01381             ParseTableOrClass(_SC(','),TK_ATTR_CLOSE);
01382             attrs = _fs->TopTarget();
01383         }
01384         Expect(_SC('{'));
01385         if(attrs != -1) _fs->PopTarget();
01386         if(base != -1) _fs->PopTarget();
01387         _fs->AddInstruction(_OP_NEWOBJ, _fs->PushTarget(), base, attrs,NOT_CLASS);
01388         ParseTableOrClass(_SC(';'),_SC('}'));
01389     }
01390     void DeleteExpr()
01391     {
01392         SQExpState es;
01393         Lex();
01394         es = _es;
01395         _es.donot_get = true;
01396         PrefixedExpr();
01397         if(_es.etype==EXPR) Error(_SC("can't delete an expression"));
01398         if(_es.etype==OBJECT || _es.etype==BASE) {
01399             Emit2ArgsOP(_OP_DELETE);
01400         }
01401         else {
01402             Error(_SC("cannot delete an (outer) local"));
01403         }
01404         _es = es;
01405     }
01406     void PrefixIncDec(SQInteger token)
01407     {
01408         SQExpState  es;
01409         SQInteger diff = (token==TK_MINUSMINUS) ? -1 : 1;
01410         Lex();
01411         es = _es;
01412         _es.donot_get = true;
01413         PrefixedExpr();
01414         if(_es.etype==EXPR) {
01415             Error(_SC("can't '++' or '--' an expression"));
01416         }
01417         else if(_es.etype==OBJECT || _es.etype==BASE) {
01418             Emit2ArgsOP(_OP_INC, diff);
01419         }
01420         else if(_es.etype==LOCAL) {
01421             SQInteger src = _fs->TopTarget();
01422             _fs->AddInstruction(_OP_INCL, src, src, 0, diff);
01423             
01424         }
01425         else if(_es.etype==OUTER) {
01426             SQInteger tmp = _fs->PushTarget();
01427             _fs->AddInstruction(_OP_GETOUTER, tmp, _es.epos);
01428             _fs->AddInstruction(_OP_INCL,     tmp, tmp, 0, diff);
01429             _fs->AddInstruction(_OP_SETOUTER, tmp, _es.epos, tmp);
01430         }
01431         _es = es;
01432     }
01433     void CreateFunction(SQObject &name,bool lambda = false)
01434     {
01435         SQFuncState *funcstate = _fs->PushChildState(_ss(_vm));
01436         funcstate->_name = name;
01437         SQObject paramname;
01438         funcstate->AddParameter(_fs->CreateString(_SC("this")));
01439         funcstate->_sourcename = _sourcename;
01440         SQInteger defparams = 0;
01441         while(_token!=_SC(')')) {
01442             if(_token == TK_VARPARAMS) {
01443                 if(defparams > 0) Error(_SC("function with default parameters cannot have variable number of parameters"));
01444                 funcstate->AddParameter(_fs->CreateString(_SC("vargv")));
01445                 funcstate->_varparams = true;
01446                 Lex();
01447                 if(_token != _SC(')')) Error(_SC("expected ')'"));
01448                 break;
01449             }
01450             else {
01451                 paramname = Expect(TK_IDENTIFIER);
01452                 funcstate->AddParameter(paramname);
01453                 if(_token == _SC('=')) { 
01454                     Lex();
01455                     Expression();
01456                     funcstate->AddDefaultParam(_fs->TopTarget());
01457                     defparams++;
01458                 }
01459                 else {
01460                     if(defparams > 0) Error(_SC("expected '='"));
01461                 }
01462                 if(_token == _SC(',')) Lex();
01463                 else if(_token != _SC(')')) Error(_SC("expected ')' or ','"));
01464             }
01465         }
01466         Expect(_SC(')'));
01467         for(SQInteger n = 0; n < defparams; n++) {
01468             _fs->PopTarget();
01469         }
01470                 
01471         SQFuncState *currchunk = _fs;
01472         _fs = funcstate;
01473         if(lambda) { 
01474             Expression(); 
01475             _fs->AddInstruction(_OP_RETURN, 1, _fs->PopTarget());}
01476         else { 
01477             Statement(false); 
01478         }
01479         funcstate->AddLineInfos(_lex._prevtoken == _SC('\n')?_lex._lasttokenline:_lex._currentline, _lineinfo, true);
01480         funcstate->AddInstruction(_OP_RETURN, -1);
01481         funcstate->SetStackSize(0);
01482 
01483         SQFunctionProto *func = funcstate->BuildProto();
01484 #ifdef _DEBUG_DUMP
01485         funcstate->Dump(func);
01486 #endif
01487         _fs = currchunk;
01488         _fs->_functions.push_back(func);
01489         _fs->PopChildState();
01490     }
01491     void ResolveBreaks(SQFuncState *funcstate, SQInteger ntoresolve)
01492     {
01493         while(ntoresolve > 0) {
01494             SQInteger pos = funcstate->_unresolvedbreaks.back();
01495             funcstate->_unresolvedbreaks.pop_back();
01496             //set the jmp instruction
01497             funcstate->SetIntructionParams(pos, 0, funcstate->GetCurrentPos() - pos, 0);
01498             ntoresolve--;
01499         }
01500     }
01501     void ResolveContinues(SQFuncState *funcstate, SQInteger ntoresolve, SQInteger targetpos)
01502     {
01503         while(ntoresolve > 0) {
01504             SQInteger pos = funcstate->_unresolvedcontinues.back();
01505             funcstate->_unresolvedcontinues.pop_back();
01506             //set the jmp instruction
01507             funcstate->SetIntructionParams(pos, 0, targetpos - pos, 0);
01508             ntoresolve--;
01509         }
01510     }
01511 private:
01512     SQInteger _token;
01513     SQFuncState *_fs;
01514     SQObjectPtr _sourcename;
01515     SQLexer _lex;
01516     bool _lineinfo;
01517     bool _raiseerror;
01518     SQInteger _debugline;
01519     SQInteger _debugop;
01520     SQExpState   _es;
01521     SQScope _scope;
01522     SQChar _compilererror[MAX_COMPILER_ERROR_LEN];
01523     jmp_buf _errorjmp;
01524     SQVM *_vm;
01525 };
01526 
01527 bool Compile(SQVM *vm,SQLEXREADFUNC rg, SQUserPointer up, const SQChar *sourcename, SQObjectPtr &out, bool raiseerror, bool lineinfo)
01528 {
01529     SQCompiler p(vm, rg, up, sourcename, raiseerror, lineinfo);
01530     return p.Compile(out);
01531 }
01532 
01533 #endif