# sqcompiler.cpp

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