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       case '-':
01114         Lex();
01115         switch(_token)
01116         {
01117         case TK_INTEGER:
01118           val._type = OT_INTEGER;
01119           val._unVal.nInteger = -_lex._nvalue;
01120         break;
01121         case TK_FLOAT:
01122           val._type = OT_FLOAT;
01123           val._unVal.fFloat = -_lex._fvalue;
01124         break;
01125         default:
01126           Error(_SC("scalar expected : integer,float"));
01127           val._type = OT_NULL; // Silent compile-warning
01128         }
01129         break;
01130       default:
01131         Error(_SC("scalar expected : integer,float or string"));
01132         val._type = OT_NULL; // Silent compile-warning
01133     }
01134     Lex();
01135     return val;
01136   }
01137   void EnumStatement()
01138   {
01139 
01140     Lex();
01141     SQObject id = Expect(TK_IDENTIFIER);
01142     Expect(_SC('{'));
01143 
01144     SQObject table = _fs->CreateTable();
01145     SQInteger nval = 0;
01146     while(_token != _SC('}')) {
01147       SQObject key = Expect(TK_IDENTIFIER);
01148       SQObject val;
01149       if(_token == _SC('=')) {
01150         Lex();
01151         val = ExpectScalar();
01152       }
01153       else {
01154         val._type = OT_INTEGER;
01155         val._unVal.nInteger = nval++;
01156       }
01157       _table(table)->NewSlot(SQObjectPtr(key),SQObjectPtr(val));
01158       if(_token == ',') Lex();
01159     }
01160     SQTable *enums = _table(_ss(_vm)->_consts);
01161     SQObjectPtr strongid = id;
01162     /*SQObjectPtr dummy;
01163     if(enums->Get(strongid,dummy)) {
01164       dummy.Null(); strongid.Null();
01165       Error(_SC("enumeration already exists"));
01166     }*/
01167     enums->NewSlot(SQObjectPtr(strongid),SQObjectPtr(table));
01168     strongid.Null();
01169     Lex();
01170 
01171   }
01172   void TryCatchStatement()
01173   {
01174     SQObject exid;
01175     Lex();
01176     _fs->AddInstruction(_OP_PUSHTRAP,0,0);
01177     _fs->_traps++;
01178     if(_fs->_breaktargets.size()) _fs->_breaktargets.top()++;
01179     if(_fs->_continuetargets.size()) _fs->_continuetargets.top()++;
01180     SQInteger trappos = _fs->GetCurrentPos();
01181     Statement();
01182     _fs->_traps--;
01183     _fs->AddInstruction(_OP_POPTRAP, 1, 0);
01184     if(_fs->_breaktargets.size()) _fs->_breaktargets.top()--;
01185     if(_fs->_continuetargets.size()) _fs->_continuetargets.top()--;
01186     _fs->AddInstruction(_OP_JMP, 0, 0);
01187     SQInteger jmppos = _fs->GetCurrentPos();
01188     _fs->SetIntructionParam(trappos, 1, (_fs->GetCurrentPos() - trappos));
01189     Expect(TK_CATCH); Expect(_SC('(')); exid = Expect(TK_IDENTIFIER); Expect(_SC(')'));
01190     SQInteger stacksize = _fs->GetStackSize();
01191     SQInteger ex_target = _fs->PushLocalVariable(exid);
01192     _fs->SetIntructionParam(trappos, 0, ex_target);
01193     Statement();
01194     _fs->SetIntructionParams(jmppos, 0, (_fs->GetCurrentPos() - jmppos), 0);
01195     CleanStack(stacksize);
01196   }
01197   void FunctionExp(SQInteger ftype)
01198   {
01199     Lex(); Expect(_SC('('));
01200     CreateFunction(_null_);
01201     _fs->AddInstruction(_OP_CLOSURE, _fs->PushTarget(), _fs->_functions.size() - 1, ftype == TK_FUNCTION?0:1);
01202   }
01203   void ClassExp()
01204   {
01205     SQInteger base = -1;
01206     SQInteger attrs = -1;
01207     if(_token == TK_EXTENDS) {
01208       Lex(); Expression();
01209       base = _fs->TopTarget();
01210     }
01211     if(_token == TK_ATTR_OPEN) {
01212       Lex();
01213       _fs->AddInstruction(_OP_NEWTABLE, _fs->PushTarget());
01214       ParseTableOrClass(_SC(','),TK_ATTR_CLOSE);
01215       attrs = _fs->TopTarget();
01216     }
01217     Expect(_SC('{'));
01218     if(attrs != -1) _fs->PopTarget();
01219     if(base != -1) _fs->PopTarget();
01220     _fs->AddInstruction(_OP_CLASS, _fs->PushTarget(), base, attrs);
01221     ParseTableOrClass(_SC(';'));
01222   }
01223   void DelegateExpr()
01224   {
01225     Lex(); CommaExpr();
01226     Expect(_SC(':'));
01227     CommaExpr();
01228     SQInteger table = _fs->PopTarget(), delegate = _fs->PopTarget();
01229     _fs->AddInstruction(_OP_DELEGATE, _fs->PushTarget(), table, delegate);
01230   }
01231   void DeleteExpr()
01232   {
01233     ExpState es;
01234     Lex(); PushExpState();
01235     _exst._class_or_delete = true;
01236     _exst._funcarg = false;
01237     PrefixedExpr();
01238     es = PopExpState();
01239     if(es._deref == DEREF_NO_DEREF) Error(_SC("can't delete an expression"));
01240     if(es._deref == DEREF_FIELD) Emit2ArgsOP(_OP_DELETE);
01241     else Error(_SC("cannot delete a local"));
01242   }
01243   void PrefixIncDec(SQInteger token)
01244   {
01245     ExpState es;
01246     Lex(); PushExpState();
01247     _exst._class_or_delete = true;
01248     _exst._funcarg = false;
01249     PrefixedExpr();
01250     es = PopExpState();
01251     if(es._deref == DEREF_FIELD) Emit2ArgsOP(_OP_INC,token == TK_MINUSMINUS?-1:1);
01252     else {
01253       SQInteger src = _fs->PopTarget();
01254       _fs->AddInstruction(_OP_INCL, _fs->PushTarget(), src, 0, token == TK_MINUSMINUS?-1:1);
01255     }
01256   }
01257   void CreateFunction(SQObject &name)
01258   {
01259 
01260     SQFuncState *funcstate = _fs->PushChildState(_ss(_vm));
01261     funcstate->_name = name;
01262     SQObject paramname;
01263     funcstate->AddParameter(_fs->CreateString(_SC("this")));
01264     funcstate->_sourcename = _sourcename;
01265     SQInteger defparams = 0;
01266     while(_token!=_SC(')')) {
01267       if(_token == TK_VARPARAMS) {
01268         if(defparams > 0) Error(_SC("function with default parameters cannot have variable number of parameters"));
01269         funcstate->_varparams = true;
01270         Lex();
01271         if(_token != _SC(')')) Error(_SC("expected ')'"));
01272         break;
01273       }
01274       else {
01275         paramname = Expect(TK_IDENTIFIER);
01276         funcstate->AddParameter(paramname);
01277         if(_token == _SC('=')) {
01278           Lex();
01279           Expression();
01280           funcstate->AddDefaultParam(_fs->TopTarget());
01281           defparams++;
01282         }
01283         else {
01284           if(defparams > 0) Error(_SC("expected '='"));
01285         }
01286         if(_token == _SC(',')) Lex();
01287         else if(_token != _SC(')')) Error(_SC("expected ')' or ','"));
01288       }
01289     }
01290     Expect(_SC(')'));
01291     for(SQInteger n = 0; n < defparams; n++) {
01292       _fs->PopTarget();
01293     }
01294     //outer values
01295     if(_token == _SC(':')) {
01296       Lex(); Expect(_SC('('));
01297       while(_token != _SC(')')) {
01298         paramname = Expect(TK_IDENTIFIER);
01299         //outers are treated as implicit local variables
01300         funcstate->AddOuterValue(paramname);
01301         if(_token == _SC(',')) Lex();
01302         else if(_token != _SC(')')) Error(_SC("expected ')' or ','"));
01303       }
01304       Lex();
01305     }
01306 
01307     SQFuncState *currchunk = _fs;
01308     _fs = funcstate;
01309     Statement();
01310     funcstate->AddLineInfos(_lex._prevtoken == _SC('\n')?_lex._lasttokenline:_lex._currentline, _lineinfo, true);
01311         funcstate->AddInstruction(_OP_RETURN, -1);
01312     funcstate->SetStackSize(0);
01313     //_fs->->_stacksize = _fs->_stacksize;
01314     SQFunctionProto *func = funcstate->BuildProto();
01315 #ifdef _DEBUG_DUMP
01316     funcstate->Dump(func);
01317 #endif
01318     _fs = currchunk;
01319     _fs->_functions.push_back(func);
01320     _fs->PopChildState();
01321   }
01322   void CleanStack(SQInteger stacksize)
01323   {
01324     if(_fs->GetStackSize() != stacksize)
01325       _fs->SetStackSize(stacksize);
01326   }
01327   void ResolveBreaks(SQFuncState *funcstate, SQInteger ntoresolve)
01328   {
01329     while(ntoresolve > 0) {
01330       SQInteger pos = funcstate->_unresolvedbreaks.back();
01331       funcstate->_unresolvedbreaks.pop_back();
01332       //set the jmp instruction
01333       funcstate->SetIntructionParams(pos, 0, funcstate->GetCurrentPos() - pos, 0);
01334       ntoresolve--;
01335     }
01336   }
01337   void ResolveContinues(SQFuncState *funcstate, SQInteger ntoresolve, SQInteger targetpos)
01338   {
01339     while(ntoresolve > 0) {
01340       SQInteger pos = funcstate->_unresolvedcontinues.back();
01341       funcstate->_unresolvedcontinues.pop_back();
01342       //set the jmp instruction
01343       funcstate->SetIntructionParams(pos, 0, targetpos - pos, 0);
01344       ntoresolve--;
01345     }
01346   }
01347 private:
01348   SQInteger _token;
01349   SQFuncState *_fs;
01350   SQObjectPtr _sourcename;
01351   SQLexer _lex;
01352   bool _lineinfo;
01353   bool _raiseerror;
01354   SQInteger _debugline;
01355   SQInteger _debugop;
01356   ExpStateVec _expstates;
01357   SQVM *_vm;
01358 };
01359 
01360 bool Compile(SQVM *vm,SQLEXREADFUNC rg, SQUserPointer up, const SQChar *sourcename, SQObjectPtr &out, bool raiseerror, bool lineinfo)
01361 {
01362   SQCompiler p(vm, rg, up, sourcename, raiseerror, lineinfo);
01363   return p.Compile(out);
01364 }

Generated on Wed Dec 23 20:12:45 2009 for OpenTTD by  doxygen 1.5.6