Back to home page

Enduro/X

 
 

    


0001 /*

0002     see copyright notice in pscript.h

0003 */
0004 #include "pspcheader.h"
0005 #ifndef NO_COMPILER
0006 #include <stdarg.h>
0007 #include <setjmp.h>
0008 #include "psopcodes.h"
0009 #include "psstring.h"
0010 #include "psfuncproto.h"
0011 #include "pscompiler.h"
0012 #include "psfuncstate.h"
0013 #include "pslexer.h"
0014 #include "psvm.h"
0015 #include "pstable.h"
0016 
0017 #define EXPR   1
0018 #define OBJECT 2
0019 #define BASE   3
0020 #define LOCAL  4
0021 #define OUTER  5
0022 
0023 struct PSExpState {
0024   PSInteger  etype;       /* expr. type; one of EXPR, OBJECT, BASE, OUTER or LOCAL */
0025   PSInteger  epos;        /* expr. location on stack; -1 for OBJECT and BASE */
0026   bool       donot_get;   /* signal not to deref the next value */
0027 };
0028 
0029 #define MAX_COMPILER_ERROR_LEN 256
0030 
0031 struct PSScope {
0032     PSInteger outers;
0033     PSInteger stacksize;
0034 };
0035 
0036 #define BEGIN_SCOPE() PSScope __oldscope__ = _scope; \
0037                      _scope.outers = _fs->_outers; \
0038                      _scope.stacksize = _fs->GetStackSize();
0039 
0040 #define RESOLVE_OUTERS() if(_fs->GetStackSize() != _scope.stacksize) { \
0041                             if(_fs->CountOuters(_scope.stacksize)) { \
0042                                 _fs->AddInstruction(_OP_CLOSE,0,_scope.stacksize); \
0043                             } \
0044                         }
0045 
0046 #define END_SCOPE_NO_CLOSE() {  if(_fs->GetStackSize() != _scope.stacksize) { \
0047                             _fs->SetStackSize(_scope.stacksize); \
0048                         } \
0049                         _scope = __oldscope__; \
0050                     }
0051 
0052 #define END_SCOPE() {   PSInteger oldouters = _fs->_outers;\
0053                         if(_fs->GetStackSize() != _scope.stacksize) { \
0054                             _fs->SetStackSize(_scope.stacksize); \
0055                             if(oldouters != _fs->_outers) { \
0056                                 _fs->AddInstruction(_OP_CLOSE,0,_scope.stacksize); \
0057                             } \
0058                         } \
0059                         _scope = __oldscope__; \
0060                     }
0061 
0062 #define BEGIN_BREAKBLE_BLOCK()  PSInteger __nbreaks__=_fs->_unresolvedbreaks.size(); \
0063                             PSInteger __ncontinues__=_fs->_unresolvedcontinues.size(); \
0064                             _fs->_breaktargets.push_back(0);_fs->_continuetargets.push_back(0);
0065 
0066 #define END_BREAKBLE_BLOCK(continue_target) {__nbreaks__=_fs->_unresolvedbreaks.size()-__nbreaks__; \
0067                     __ncontinues__=_fs->_unresolvedcontinues.size()-__ncontinues__; \
0068                     if(__ncontinues__>0)ResolveContinues(_fs,__ncontinues__,continue_target); \
0069                     if(__nbreaks__>0)ResolveBreaks(_fs,__nbreaks__); \
0070                     _fs->_breaktargets.pop_back();_fs->_continuetargets.pop_back();}
0071 
0072 class PSCompiler
0073 {
0074 public:
0075     PSCompiler(PSVM *v, PSLEXREADFUNC rg, PSUserPointer up, const PSChar* sourcename, bool raiseerror, bool lineinfo)
0076     {
0077         _vm=v;
0078         _lex.Init(_ss(v), rg, up,ThrowError,this);
0079         _sourcename = PSString::Create(_ss(v), sourcename);
0080         _lineinfo = lineinfo;_raiseerror = raiseerror;
0081         _scope.outers = 0;
0082         _scope.stacksize = 0;
0083         _compilererror[0] = _SC('\0');
0084     }
0085     static void ThrowError(void *ud, const PSChar *s) {
0086         PSCompiler *c = (PSCompiler *)ud;
0087         c->Error(s);
0088     }
0089     void Error(const PSChar *s, ...)
0090     {
0091         va_list vl;
0092         va_start(vl, s);
0093         scvsprintf(_compilererror, MAX_COMPILER_ERROR_LEN, s, vl);
0094         va_end(vl);
0095         longjmp(_errorjmp,1);
0096     }
0097     void Lex(){ _token = _lex.Lex();}
0098     PSObject Expect(PSInteger tok)
0099     {
0100 
0101         if(_token != tok) {
0102             if(_token == TK_CONSTRUCTOR && tok == TK_IDENTIFIER) {
0103                 //do nothing

0104             }
0105             else {
0106                 const PSChar *etypename;
0107                 if(tok > 255) {
0108                     switch(tok)
0109                     {
0110                     case TK_IDENTIFIER:
0111                         etypename = _SC("IDENTIFIER");
0112                         break;
0113                     case TK_STRING_LITERAL:
0114                         etypename = _SC("STRING_LITERAL");
0115                         break;
0116                     case TK_INTEGER:
0117                         etypename = _SC("INTEGER");
0118                         break;
0119                     case TK_FLOAT:
0120                         etypename = _SC("FLOAT");
0121                         break;
0122                     default:
0123                         etypename = _lex.Tok2Str(tok);
0124                     }
0125                     Error(_SC("expected '%s'"), etypename);
0126                 }
0127                 Error(_SC("expected '%c'"), tok);
0128             }
0129         }
0130         PSObjectPtr ret;
0131         switch(tok)
0132         {
0133         case TK_IDENTIFIER:
0134             ret = _fs->CreateString(_lex._svalue);
0135             break;
0136         case TK_STRING_LITERAL:
0137             ret = _fs->CreateString(_lex._svalue,_lex._longstr.size()-1);
0138             break;
0139         case TK_INTEGER:
0140             ret = PSObjectPtr(_lex._nvalue);
0141             break;
0142         case TK_FLOAT:
0143             ret = PSObjectPtr(_lex._fvalue);
0144             break;
0145         }
0146         Lex();
0147         return ret;
0148     }
0149     bool IsEndOfStatement() { return ((_lex._prevtoken == _SC('\n')) || (_token == PSCRIPT_EOB) || (_token == _SC('}')) || (_token == _SC(';'))); }
0150     void OptionalSemicolon()
0151     {
0152         if(_token == _SC(';')) { Lex(); return; }
0153         if(!IsEndOfStatement()) {
0154             Error(_SC("end of statement expected (; or lf)"));
0155         }
0156     }
0157     void MoveIfCurrentTargetIsLocal() {
0158         PSInteger trg = _fs->TopTarget();
0159         if(_fs->IsLocal(trg)) {
0160             trg = _fs->PopTarget(); //pops the target and moves it

0161             _fs->AddInstruction(_OP_MOVE, _fs->PushTarget(), trg);
0162         }
0163     }
0164     bool Compile(PSObjectPtr &o)
0165     {
0166         _debugline = 1;
0167         _debugop = 0;
0168 
0169         PSFuncState funcstate(_ss(_vm), NULL,ThrowError,this);
0170         funcstate._name = PSString::Create(_ss(_vm), _SC("main"));
0171         _fs = &funcstate;
0172         _fs->AddParameter(_fs->CreateString(_SC("this")));
0173         _fs->AddParameter(_fs->CreateString(_SC("vargv")));
0174         _fs->_varparams = true;
0175         _fs->_sourcename = _sourcename;
0176         PSInteger stacksize = _fs->GetStackSize();
0177         if(setjmp(_errorjmp) == 0) {
0178             Lex();
0179             while(_token > 0){
0180                 Statement();
0181                 if(_lex._prevtoken != _SC('}') && _lex._prevtoken != _SC(';')) OptionalSemicolon();
0182             }
0183             _fs->SetStackSize(stacksize);
0184             _fs->AddLineInfos(_lex._currentline, _lineinfo, true);
0185             _fs->AddInstruction(_OP_RETURN, 0xFF);
0186             _fs->SetStackSize(0);
0187             o =_fs->BuildProto();
0188 #ifdef _DEBUG_DUMP
0189             _fs->Dump(_funcproto(o));
0190 #endif
0191         }
0192         else {
0193             if(_raiseerror && _ss(_vm)->_compilererrorhandler) {
0194                 _ss(_vm)->_compilererrorhandler(_vm, _compilererror, type(_sourcename) == OT_STRING?_stringval(_sourcename):_SC("unknown"),
0195                     _lex._currentline, _lex._currentcolumn);
0196             }
0197             _vm->_lasterror = PSString::Create(_ss(_vm), _compilererror, -1);
0198             return false;
0199         }
0200         return true;
0201     }
0202     void Statements()
0203     {
0204         while(_token != _SC('}') && _token != TK_DEFAULT && _token != TK_CASE) {
0205             Statement();
0206             if(_lex._prevtoken != _SC('}') && _lex._prevtoken != _SC(';')) OptionalSemicolon();
0207         }
0208     }
0209     void Statement(bool closeframe = true)
0210     {
0211         _fs->AddLineInfos(_lex._currentline, _lineinfo);
0212         switch(_token){
0213         case _SC(';'):  Lex();                  break;
0214         case TK_IF:     IfStatement();          break;
0215         case TK_WHILE:      WhileStatement();       break;
0216         case TK_DO:     DoWhileStatement();     break;
0217         case TK_FOR:        ForStatement();         break;
0218         case TK_FOREACH:    ForEachStatement();     break;
0219         case TK_SWITCH: SwitchStatement();      break;
0220         case TK_LOCAL:      LocalDeclStatement();   break;
0221         case TK_RETURN:
0222         case TK_YIELD: {
0223             PSOpcode op;
0224             if(_token == TK_RETURN) {
0225                 op = _OP_RETURN;
0226             }
0227             else {
0228                 op = _OP_YIELD;
0229                 _fs->_bgenerator = true;
0230             }
0231             Lex();
0232             if(!IsEndOfStatement()) {
0233                 PSInteger retexp = _fs->GetCurrentPos()+1;
0234                 CommaExpr();
0235                 if(op == _OP_RETURN && _fs->_traps > 0)
0236                     _fs->AddInstruction(_OP_POPTRAP, _fs->_traps, 0);
0237                 _fs->_returnexp = retexp;
0238                 _fs->AddInstruction(op, 1, _fs->PopTarget(),_fs->GetStackSize());
0239             }
0240             else{
0241                 if(op == _OP_RETURN && _fs->_traps > 0)
0242                     _fs->AddInstruction(_OP_POPTRAP, _fs->_traps ,0);
0243                 _fs->_returnexp = -1;
0244                 _fs->AddInstruction(op, 0xFF,0,_fs->GetStackSize());
0245             }
0246             break;}
0247         case TK_BREAK:
0248             if(_fs->_breaktargets.size() <= 0)Error(_SC("'break' has to be in a loop block"));
0249             if(_fs->_breaktargets.top() > 0){
0250                 _fs->AddInstruction(_OP_POPTRAP, _fs->_breaktargets.top(), 0);
0251             }
0252             RESOLVE_OUTERS();
0253             _fs->AddInstruction(_OP_JMP, 0, -1234);
0254             _fs->_unresolvedbreaks.push_back(_fs->GetCurrentPos());
0255             Lex();
0256             break;
0257         case TK_CONTINUE:
0258             if(_fs->_continuetargets.size() <= 0)Error(_SC("'continue' has to be in a loop block"));
0259             if(_fs->_continuetargets.top() > 0) {
0260                 _fs->AddInstruction(_OP_POPTRAP, _fs->_continuetargets.top(), 0);
0261             }
0262             RESOLVE_OUTERS();
0263             _fs->AddInstruction(_OP_JMP, 0, -1234);
0264             _fs->_unresolvedcontinues.push_back(_fs->GetCurrentPos());
0265             Lex();
0266             break;
0267         case TK_FUNCTION:
0268             FunctionStatement();
0269             break;
0270         case TK_CLASS:
0271             ClassStatement();
0272             break;
0273         case TK_ENUM:
0274             EnumStatement();
0275             break;
0276         case _SC('{'):{
0277                 BEGIN_SCOPE();
0278                 Lex();
0279                 Statements();
0280                 Expect(_SC('}'));
0281                 if(closeframe) {
0282                     END_SCOPE();
0283                 }
0284                 else {
0285                     END_SCOPE_NO_CLOSE();
0286                 }
0287             }
0288             break;
0289         case TK_TRY:
0290             TryCatchStatement();
0291             break;
0292         case TK_THROW:
0293             Lex();
0294             CommaExpr();
0295             _fs->AddInstruction(_OP_THROW, _fs->PopTarget());
0296             break;
0297         case TK_CONST:
0298             {
0299             Lex();
0300             PSObject id = Expect(TK_IDENTIFIER);
0301             Expect('=');
0302             PSObject val = ExpectScalar();
0303             OptionalSemicolon();
0304             PSTable *enums = _table(_ss(_vm)->_consts);
0305             PSObjectPtr strongid = id;
0306             enums->NewSlot(strongid,PSObjectPtr(val));
0307             strongid.Null();
0308             }
0309             break;
0310         default:
0311             CommaExpr();
0312             _fs->DiscardTarget();
0313             //_fs->PopTarget();

0314             break;
0315         }
0316         _fs->SnoozeOpt();
0317     }
0318     void EmitDerefOp(PSOpcode op)
0319     {
0320         PSInteger val = _fs->PopTarget();
0321         PSInteger key = _fs->PopTarget();
0322         PSInteger src = _fs->PopTarget();
0323         _fs->AddInstruction(op,_fs->PushTarget(),src,key,val);
0324     }
0325     void Emit2ArgsOP(PSOpcode op, PSInteger p3 = 0)
0326     {
0327         PSInteger p2 = _fs->PopTarget(); //src in OP_GET

0328         PSInteger p1 = _fs->PopTarget(); //key in OP_GET

0329         _fs->AddInstruction(op,_fs->PushTarget(), p1, p2, p3);
0330     }
0331     void EmitCompoundArith(PSInteger tok, PSInteger etype, PSInteger pos)
0332     {
0333         /* Generate code depending on the expression type */
0334         switch(etype) {
0335         case LOCAL:{
0336             PSInteger p2 = _fs->PopTarget(); //src in OP_GET

0337             PSInteger p1 = _fs->PopTarget(); //key in OP_GET

0338             _fs->PushTarget(p1);
0339             //EmitCompArithLocal(tok, p1, p1, p2);

0340             _fs->AddInstruction(ChooseArithOpByToken(tok),p1, p2, p1, 0);
0341             _fs->SnoozeOpt();
0342                    }
0343             break;
0344         case OBJECT:
0345         case BASE:
0346             {
0347                 PSInteger val = _fs->PopTarget();
0348                 PSInteger key = _fs->PopTarget();
0349                 PSInteger src = _fs->PopTarget();
0350                 /* _OP_COMPARITH mixes dest obj and source val in the arg1 */
0351                 _fs->AddInstruction(_OP_COMPARITH, _fs->PushTarget(), (src<<16)|val, key, ChooseCompArithCharByToken(tok));
0352             }
0353             break;
0354         case OUTER:
0355             {
0356                 PSInteger val = _fs->TopTarget();
0357                 PSInteger tmp = _fs->PushTarget();
0358                 _fs->AddInstruction(_OP_GETOUTER,   tmp, pos);
0359                 _fs->AddInstruction(ChooseArithOpByToken(tok), tmp, val, tmp, 0);
0360                 _fs->PopTarget();
0361                 _fs->PopTarget();
0362                 _fs->AddInstruction(_OP_SETOUTER, _fs->PushTarget(), pos, tmp);
0363             }
0364             break;
0365         }
0366     }
0367     void CommaExpr()
0368     {
0369         for(Expression();_token == ',';_fs->PopTarget(), Lex(), CommaExpr());
0370     }
0371     void Expression()
0372     {
0373          PSExpState es = _es;
0374         _es.etype     = EXPR;
0375         _es.epos      = -1;
0376         _es.donot_get = false;
0377         LogicalOrExp();
0378         switch(_token)  {
0379         case _SC('='):
0380         case TK_NEWSLOT:
0381         case TK_MINUSEQ:
0382         case TK_PLUSEQ:
0383         case TK_MULEQ:
0384         case TK_DIVEQ:
0385         case TK_MODEQ:{
0386             PSInteger op = _token;
0387             PSInteger ds = _es.etype;
0388             PSInteger pos = _es.epos;
0389             if(ds == EXPR) Error(_SC("can't assign expression"));
0390             else if(ds == BASE) Error(_SC("'base' cannot be modified"));
0391             Lex(); Expression();
0392 
0393             switch(op){
0394             case TK_NEWSLOT:
0395                 if(ds == OBJECT || ds == BASE)
0396                     EmitDerefOp(_OP_NEWSLOT);
0397                 else //if _derefstate != DEREF_NO_DEREF && DEREF_FIELD so is the index of a local

0398                     Error(_SC("can't 'create' a local slot"));
0399                 break;
0400             case _SC('='): //ASSIGN

0401                 switch(ds) {
0402                 case LOCAL:
0403                     {
0404                         PSInteger src = _fs->PopTarget();
0405                         PSInteger dst = _fs->TopTarget();
0406                         _fs->AddInstruction(_OP_MOVE, dst, src);
0407                     }
0408                     break;
0409                 case OBJECT:
0410                 case BASE:
0411                     EmitDerefOp(_OP_SET);
0412                     break;
0413                 case OUTER:
0414                     {
0415                         PSInteger src = _fs->PopTarget();
0416                         PSInteger dst = _fs->PushTarget();
0417                         _fs->AddInstruction(_OP_SETOUTER, dst, pos, src);
0418                     }
0419                 }
0420                 break;
0421             case TK_MINUSEQ:
0422             case TK_PLUSEQ:
0423             case TK_MULEQ:
0424             case TK_DIVEQ:
0425             case TK_MODEQ:
0426                 EmitCompoundArith(op, ds, pos);
0427                 break;
0428             }
0429             }
0430             break;
0431         case _SC('?'): {
0432             Lex();
0433             _fs->AddInstruction(_OP_JZ, _fs->PopTarget());
0434             PSInteger jzpos = _fs->GetCurrentPos();
0435             PSInteger trg = _fs->PushTarget();
0436             Expression();
0437             PSInteger first_exp = _fs->PopTarget();
0438             if(trg != first_exp) _fs->AddInstruction(_OP_MOVE, trg, first_exp);
0439             PSInteger endfirstexp = _fs->GetCurrentPos();
0440             _fs->AddInstruction(_OP_JMP, 0, 0);
0441             Expect(_SC(':'));
0442             PSInteger jmppos = _fs->GetCurrentPos();
0443             Expression();
0444             PSInteger second_exp = _fs->PopTarget();
0445             if(trg != second_exp) _fs->AddInstruction(_OP_MOVE, trg, second_exp);
0446             _fs->SetIntructionParam(jmppos, 1, _fs->GetCurrentPos() - jmppos);
0447             _fs->SetIntructionParam(jzpos, 1, endfirstexp - jzpos + 1);
0448             _fs->SnoozeOpt();
0449             }
0450             break;
0451         }
0452         _es = es;
0453     }
0454     template<typename T> void INVOKE_EXP(T f)
0455     {
0456         PSExpState es = _es;
0457         _es.etype     = EXPR;
0458         _es.epos      = -1;
0459         _es.donot_get = false;
0460         (this->*f)();
0461         _es = es;
0462     }
0463     template<typename T> void BIN_EXP(PSOpcode op, T f,PSInteger op3 = 0)
0464     {
0465         Lex();
0466         INVOKE_EXP(f);
0467         PSInteger op1 = _fs->PopTarget();PSInteger op2 = _fs->PopTarget();
0468         _fs->AddInstruction(op, _fs->PushTarget(), op1, op2, op3);
0469     }
0470     void LogicalOrExp()
0471     {
0472         LogicalAndExp();
0473         for(;;) if(_token == TK_OR) {
0474             PSInteger first_exp = _fs->PopTarget();
0475             PSInteger trg = _fs->PushTarget();
0476             _fs->AddInstruction(_OP_OR, trg, 0, first_exp, 0);
0477             PSInteger jpos = _fs->GetCurrentPos();
0478             if(trg != first_exp) _fs->AddInstruction(_OP_MOVE, trg, first_exp);
0479             Lex(); INVOKE_EXP(&PSCompiler::LogicalOrExp);
0480             _fs->SnoozeOpt();
0481             PSInteger second_exp = _fs->PopTarget();
0482             if(trg != second_exp) _fs->AddInstruction(_OP_MOVE, trg, second_exp);
0483             _fs->SnoozeOpt();
0484             _fs->SetIntructionParam(jpos, 1, (_fs->GetCurrentPos() - jpos));
0485             break;
0486         }else return;
0487     }
0488     void LogicalAndExp()
0489     {
0490         BitwiseOrExp();
0491         for(;;) switch(_token) {
0492         case TK_AND: {
0493             PSInteger first_exp = _fs->PopTarget();
0494             PSInteger trg = _fs->PushTarget();
0495             _fs->AddInstruction(_OP_AND, trg, 0, first_exp, 0);
0496             PSInteger jpos = _fs->GetCurrentPos();
0497             if(trg != first_exp) _fs->AddInstruction(_OP_MOVE, trg, first_exp);
0498             Lex(); INVOKE_EXP(&PSCompiler::LogicalAndExp);
0499             _fs->SnoozeOpt();
0500             PSInteger second_exp = _fs->PopTarget();
0501             if(trg != second_exp) _fs->AddInstruction(_OP_MOVE, trg, second_exp);
0502             _fs->SnoozeOpt();
0503             _fs->SetIntructionParam(jpos, 1, (_fs->GetCurrentPos() - jpos));
0504             break;
0505             }
0506 
0507         default:
0508             return;
0509         }
0510     }
0511     void BitwiseOrExp()
0512     {
0513         BitwiseXorExp();
0514         for(;;) if(_token == _SC('|'))
0515         {BIN_EXP(_OP_BITW, &PSCompiler::BitwiseXorExp,BW_OR);
0516         }else return;
0517     }
0518     void BitwiseXorExp()
0519     {
0520         BitwiseAndExp();
0521         for(;;) if(_token == _SC('^'))
0522         {BIN_EXP(_OP_BITW, &PSCompiler::BitwiseAndExp,BW_XOR);
0523         }else return;
0524     }
0525     void BitwiseAndExp()
0526     {
0527         EqExp();
0528         for(;;) if(_token == _SC('&'))
0529         {BIN_EXP(_OP_BITW, &PSCompiler::EqExp,BW_AND);
0530         }else return;
0531     }
0532     void EqExp()
0533     {
0534         CompExp();
0535         for(;;) switch(_token) {
0536         case TK_EQ: BIN_EXP(_OP_EQ, &PSCompiler::CompExp); break;
0537         case TK_NE: BIN_EXP(_OP_NE, &PSCompiler::CompExp); break;
0538         case TK_3WAYSCMP: BIN_EXP(_OP_CMP, &PSCompiler::CompExp,CMP_3W); break;
0539         default: return;
0540         }
0541     }
0542     void CompExp()
0543     {
0544         ShiftExp();
0545         for(;;) switch(_token) {
0546         case _SC('>'): BIN_EXP(_OP_CMP, &PSCompiler::ShiftExp,CMP_G); break;
0547         case _SC('<'): BIN_EXP(_OP_CMP, &PSCompiler::ShiftExp,CMP_L); break;
0548         case TK_GE: BIN_EXP(_OP_CMP, &PSCompiler::ShiftExp,CMP_GE); break;
0549         case TK_LE: BIN_EXP(_OP_CMP, &PSCompiler::ShiftExp,CMP_LE); break;
0550         case TK_IN: BIN_EXP(_OP_EXISTS, &PSCompiler::ShiftExp); break;
0551         case TK_INSTANCEOF: BIN_EXP(_OP_INSTANCEOF, &PSCompiler::ShiftExp); break;
0552         default: return;
0553         }
0554     }
0555     void ShiftExp()
0556     {
0557         PlusExp();
0558         for(;;) switch(_token) {
0559         case TK_USHIFTR: BIN_EXP(_OP_BITW, &PSCompiler::PlusExp,BW_USHIFTR); break;
0560         case TK_SHIFTL: BIN_EXP(_OP_BITW, &PSCompiler::PlusExp,BW_SHIFTL); break;
0561         case TK_SHIFTR: BIN_EXP(_OP_BITW, &PSCompiler::PlusExp,BW_SHIFTR); break;
0562         default: return;
0563         }
0564     }
0565     PSOpcode ChooseArithOpByToken(PSInteger tok)
0566     {
0567         switch(tok) {
0568             case TK_PLUSEQ: case '+': return _OP_ADD;
0569             case TK_MINUSEQ: case '-': return _OP_SUB;
0570             case TK_MULEQ: case '*': return _OP_MUL;
0571             case TK_DIVEQ: case '/': return _OP_DIV;
0572             case TK_MODEQ: case '%': return _OP_MOD;
0573             default: assert(0);
0574         }
0575         return _OP_ADD;
0576     }
0577     PSInteger ChooseCompArithCharByToken(PSInteger tok)
0578     {
0579         PSInteger oper;
0580         switch(tok){
0581         case TK_MINUSEQ: oper = '-'; break;
0582         case TK_PLUSEQ: oper = '+'; break;
0583         case TK_MULEQ: oper = '*'; break;
0584         case TK_DIVEQ: oper = '/'; break;
0585         case TK_MODEQ: oper = '%'; break;
0586         default: oper = 0; //shut up compiler

0587             assert(0); break;
0588         };
0589         return oper;
0590     }
0591     void PlusExp()
0592     {
0593         MultExp();
0594         for(;;) switch(_token) {
0595         case _SC('+'): case _SC('-'):
0596             BIN_EXP(ChooseArithOpByToken(_token), &PSCompiler::MultExp); break;
0597         default: return;
0598         }
0599     }
0600 
0601     void MultExp()
0602     {
0603         PrefixedExpr();
0604         for(;;) switch(_token) {
0605         case _SC('*'): case _SC('/'): case _SC('%'):
0606             BIN_EXP(ChooseArithOpByToken(_token), &PSCompiler::PrefixedExpr); break;
0607         default: return;
0608         }
0609     }
0610     //if 'pos' != -1 the previous variable is a local variable

0611     void PrefixedExpr()
0612     {
0613         PSInteger pos = Factor();
0614         for(;;) {
0615             switch(_token) {
0616             case _SC('.'):
0617                 pos = -1;
0618                 Lex();
0619 
0620                 _fs->AddInstruction(_OP_LOAD, _fs->PushTarget(), _fs->GetConstant(Expect(TK_IDENTIFIER)));
0621                 if(_es.etype==BASE) {
0622                     Emit2ArgsOP(_OP_GET);
0623                     pos = _fs->TopTarget();
0624                     _es.etype = EXPR;
0625                     _es.epos   = pos;
0626                 }
0627                 else {
0628                     if(NeedGet()) {
0629                         Emit2ArgsOP(_OP_GET);
0630                     }
0631                     _es.etype = OBJECT;
0632                 }
0633                 break;
0634             case _SC('['):
0635                 if(_lex._prevtoken == _SC('\n')) Error(_SC("cannot brake deref/or comma needed after [exp]=exp slot declaration"));
0636                 Lex(); Expression(); Expect(_SC(']'));
0637                 pos = -1;
0638                 if(_es.etype==BASE) {
0639                     Emit2ArgsOP(_OP_GET);
0640                     pos = _fs->TopTarget();
0641                     _es.etype = EXPR;
0642                     _es.epos   = pos;
0643                 }
0644                 else {
0645                     if(NeedGet()) {
0646                         Emit2ArgsOP(_OP_GET);
0647                     }
0648                     _es.etype = OBJECT;
0649                 }
0650                 break;
0651             case TK_MINUSMINUS:
0652             case TK_PLUSPLUS:
0653                 {
0654                     if(IsEndOfStatement()) return;
0655                     PSInteger diff = (_token==TK_MINUSMINUS) ? -1 : 1;
0656                     Lex();
0657                     switch(_es.etype)
0658                     {
0659                         case EXPR: Error(_SC("can't '++' or '--' an expression")); break;
0660                         case OBJECT:
0661                         case BASE:
0662                             if(_es.donot_get == true)  { Error(_SC("can't '++' or '--' an expression")); break; } //mmh dor this make sense?

0663                             Emit2ArgsOP(_OP_PINC, diff);
0664                             break;
0665                         case LOCAL: {
0666                             PSInteger src = _fs->PopTarget();
0667                             _fs->AddInstruction(_OP_PINCL, _fs->PushTarget(), src, 0, diff);
0668                                     }
0669                             break;
0670                         case OUTER: {
0671                             PSInteger tmp1 = _fs->PushTarget();
0672                             PSInteger tmp2 = _fs->PushTarget();
0673                             _fs->AddInstruction(_OP_GETOUTER, tmp2, _es.epos);
0674                             _fs->AddInstruction(_OP_PINCL,    tmp1, tmp2, 0, diff);
0675                             _fs->AddInstruction(_OP_SETOUTER, tmp2, _es.epos, tmp2);
0676                             _fs->PopTarget();
0677                         }
0678                     }
0679                 }
0680                 return;
0681                 break;
0682             case _SC('('):
0683                 switch(_es.etype) {
0684                     case OBJECT: {
0685                         PSInteger key     = _fs->PopTarget();  /* location of the key */
0686                         PSInteger table   = _fs->PopTarget();  /* location of the object */
0687                         PSInteger closure = _fs->PushTarget(); /* location for the closure */
0688                         PSInteger ttarget = _fs->PushTarget(); /* location for 'this' pointer */
0689                         _fs->AddInstruction(_OP_PREPCALL, closure, key, table, ttarget);
0690                         }
0691                         break;
0692                     case BASE:
0693                         //Emit2ArgsOP(_OP_GET);

0694                         _fs->AddInstruction(_OP_MOVE, _fs->PushTarget(), 0);
0695                         break;
0696                     case OUTER:
0697                         _fs->AddInstruction(_OP_GETOUTER, _fs->PushTarget(), _es.epos);
0698                         _fs->AddInstruction(_OP_MOVE,     _fs->PushTarget(), 0);
0699                         break;
0700                     default:
0701                         _fs->AddInstruction(_OP_MOVE, _fs->PushTarget(), 0);
0702                 }
0703                 _es.etype = EXPR;
0704                 Lex();
0705                 FunctionCallArgs();
0706                 break;
0707             default: return;
0708             }
0709         }
0710     }
0711     PSInteger Factor()
0712     {
0713         //_es.etype = EXPR;

0714         switch(_token)
0715         {
0716         case TK_STRING_LITERAL:
0717             _fs->AddInstruction(_OP_LOAD, _fs->PushTarget(), _fs->GetConstant(_fs->CreateString(_lex._svalue,_lex._longstr.size()-1)));
0718             Lex();
0719             break;
0720         case TK_BASE:
0721             Lex();
0722             _fs->AddInstruction(_OP_GETBASE, _fs->PushTarget());
0723             _es.etype  = BASE;
0724             _es.epos   = _fs->TopTarget();
0725             return (_es.epos);
0726             break;
0727         case TK_IDENTIFIER:
0728         case TK_CONSTRUCTOR:
0729         case TK_THIS:{
0730                 PSObject id;
0731                 PSObject constant;
0732 
0733                 switch(_token) {
0734                     case TK_IDENTIFIER:  id = _fs->CreateString(_lex._svalue);       break;
0735                     case TK_THIS:        id = _fs->CreateString(_SC("this"),4);        break;
0736                     case TK_CONSTRUCTOR: id = _fs->CreateString(_SC("constructor"),11); break;
0737                 }
0738 
0739                 PSInteger pos = -1;
0740                 Lex();
0741                 if((pos = _fs->GetLocalVariable(id)) != -1) {
0742                     /* Handle a local variable (includes 'this') */
0743                     _fs->PushTarget(pos);
0744                     _es.etype  = LOCAL;
0745                     _es.epos   = pos;
0746                 }
0747 
0748                 else if((pos = _fs->GetOuterVariable(id)) != -1) {
0749                     /* Handle a free var */
0750                     if(NeedGet()) {
0751                         _es.epos  = _fs->PushTarget();
0752                         _fs->AddInstruction(_OP_GETOUTER, _es.epos, pos);
0753                         /* _es.etype = EXPR; already default value */
0754                     }
0755                     else {
0756                         _es.etype = OUTER;
0757                         _es.epos  = pos;
0758                     }
0759                 }
0760 
0761                 else if(_fs->IsConstant(id, constant)) {
0762                     /* Handle named constant */
0763                     PSObjectPtr constval;
0764                     PSObject    constid;
0765                     if(type(constant) == OT_TABLE) {
0766                         Expect('.');
0767                         constid = Expect(TK_IDENTIFIER);
0768                         if(!_table(constant)->Get(constid, constval)) {
0769                             constval.Null();
0770                             Error(_SC("invalid constant [%s.%s]"), _stringval(id), _stringval(constid));
0771                         }
0772                     }
0773                     else {
0774                         constval = constant;
0775                     }
0776                     _es.epos = _fs->PushTarget();
0777 
0778                     /* generate direct or literal function depending on size */
0779                     PSObjectType ctype = type(constval);
0780                     switch(ctype) {
0781                         case OT_INTEGER: EmitLoadConstInt(_integer(constval),_es.epos); break;
0782                         case OT_FLOAT: EmitLoadConstFloat(_float(constval),_es.epos); break;
0783                         case OT_BOOL: _fs->AddInstruction(_OP_LOADBOOL, _es.epos, _integer(constval)); break;
0784                         default: _fs->AddInstruction(_OP_LOAD,_es.epos,_fs->GetConstant(constval)); break;
0785                     }
0786                     _es.etype = EXPR;
0787                 }
0788                 else {
0789                     /* Handle a non-local variable, aka a field. Push the 'this' pointer on

0790                     * the virtual stack (always found in offset 0, so no instruction needs to

0791                     * be generated), and push the key next. Generate an _OP_LOAD instruction

0792                     * for the latter. If we are not using the variable as a dref expr, generate

0793                     * the _OP_GET instruction.

0794                     */
0795                     _fs->PushTarget(0);
0796                     _fs->AddInstruction(_OP_LOAD, _fs->PushTarget(), _fs->GetConstant(id));
0797                     if(NeedGet()) {
0798                         Emit2ArgsOP(_OP_GET);
0799                     }
0800                     _es.etype = OBJECT;
0801                 }
0802                 return _es.epos;
0803             }
0804             break;
0805         case TK_DOUBLE_COLON:  // "::"

0806             _fs->AddInstruction(_OP_LOADROOT, _fs->PushTarget());
0807             _es.etype = OBJECT;
0808             _token = _SC('.'); /* hack: drop into PrefixExpr, case '.'*/
0809             _es.epos = -1;
0810             return _es.epos;
0811             break;
0812         case TK_NULL:
0813             _fs->AddInstruction(_OP_LOADNULLS, _fs->PushTarget(),1);
0814             Lex();
0815             break;
0816         case TK_INTEGER: EmitLoadConstInt(_lex._nvalue,-1); Lex();  break;
0817         case TK_FLOAT: EmitLoadConstFloat(_lex._fvalue,-1); Lex(); break;
0818         case TK_TRUE: case TK_FALSE:
0819             _fs->AddInstruction(_OP_LOADBOOL, _fs->PushTarget(),_token == TK_TRUE?1:0);
0820             Lex();
0821             break;
0822         case _SC('['): {
0823                 _fs->AddInstruction(_OP_NEWOBJ, _fs->PushTarget(),0,0,NOT_ARRAY);
0824                 PSInteger apos = _fs->GetCurrentPos(),key = 0;
0825                 Lex();
0826                 while(_token != _SC(']')) {
0827                     Expression();
0828                     if(_token == _SC(',')) Lex();
0829                     PSInteger val = _fs->PopTarget();
0830                     PSInteger array = _fs->TopTarget();
0831                     _fs->AddInstruction(_OP_APPENDARRAY, array, val, AAT_STACK);
0832                     key++;
0833                 }
0834                 _fs->SetIntructionParam(apos, 1, key);
0835                 Lex();
0836             }
0837             break;
0838         case _SC('{'):
0839             _fs->AddInstruction(_OP_NEWOBJ, _fs->PushTarget(),0,NOT_TABLE);
0840             Lex();ParseTableOrClass(_SC(','),_SC('}'));
0841             break;
0842         case TK_FUNCTION: FunctionExp(_token);break;
0843         case _SC('@'): FunctionExp(_token,true);break;
0844         case TK_CLASS: Lex(); ClassExp();break;
0845         case _SC('-'):
0846             Lex();
0847             switch(_token) {
0848             case TK_INTEGER: EmitLoadConstInt(-_lex._nvalue,-1); Lex(); break;
0849             case TK_FLOAT: EmitLoadConstFloat(-_lex._fvalue,-1); Lex(); break;
0850             default: UnaryOP(_OP_NEG);
0851             }
0852             break;
0853         case _SC('!'): Lex(); UnaryOP(_OP_NOT); break;
0854         case _SC('~'):
0855             Lex();
0856             if(_token == TK_INTEGER)  { EmitLoadConstInt(~_lex._nvalue,-1); Lex(); break; }
0857             UnaryOP(_OP_BWNOT);
0858             break;
0859         case TK_TYPEOF : Lex() ;UnaryOP(_OP_TYPEOF); break;
0860         case TK_RESUME : Lex(); UnaryOP(_OP_RESUME); break;
0861         case TK_CLONE : Lex(); UnaryOP(_OP_CLONE); break;
0862         case TK_MINUSMINUS :
0863         case TK_PLUSPLUS :PrefixIncDec(_token); break;
0864         case TK_DELETE : DeleteExpr(); break;
0865         case _SC('('): Lex(); CommaExpr(); Expect(_SC(')'));
0866             break;
0867         case TK___LINE__: EmitLoadConstInt(_lex._currentline,-1); Lex(); break;
0868         case TK___FILE__: _fs->AddInstruction(_OP_LOAD, _fs->PushTarget(), _fs->GetConstant(_sourcename)); Lex(); break;
0869         default: Error(_SC("expression expected"));
0870         }
0871         _es.etype = EXPR;
0872         return -1;
0873     }
0874     void EmitLoadConstInt(PSInteger value,PSInteger target)
0875     {
0876         if(target < 0) {
0877             target = _fs->PushTarget();
0878         }
0879         if(value <= INT_MAX && value > INT_MIN) { //does it fit in 32 bits?

0880             _fs->AddInstruction(_OP_LOADINT, target,value);
0881         }
0882         else {
0883             _fs->AddInstruction(_OP_LOAD, target, _fs->GetNumericConstant(value));
0884         }
0885     }
0886     void EmitLoadConstFloat(PSFloat value,PSInteger target)
0887     {
0888         if(target < 0) {
0889             target = _fs->PushTarget();
0890         }
0891         if(sizeof(PSFloat) == sizeof(PSInt32)) {
0892             _fs->AddInstruction(_OP_LOADFLOAT, target,*((PSInt32 *)&value));
0893         }
0894         else {
0895             _fs->AddInstruction(_OP_LOAD, target, _fs->GetNumericConstant(value));
0896         }
0897     }
0898     void UnaryOP(PSOpcode op)
0899     {
0900         PrefixedExpr();
0901         PSInteger src = _fs->PopTarget();
0902         _fs->AddInstruction(op, _fs->PushTarget(), src);
0903     }
0904     bool NeedGet()
0905     {
0906         switch(_token) {
0907         case _SC('='): case _SC('('): case TK_NEWSLOT: case TK_MODEQ: case TK_MULEQ:
0908         case TK_DIVEQ: case TK_MINUSEQ: case TK_PLUSEQ:
0909             return false;
0910         case TK_PLUSPLUS: case TK_MINUSMINUS:
0911             if (!IsEndOfStatement()) {
0912                 return false;
0913             }
0914         break;
0915         }
0916         return (!_es.donot_get || ( _es.donot_get && (_token == _SC('.') || _token == _SC('['))));
0917     }
0918     void FunctionCallArgs()
0919     {
0920         PSInteger nargs = 1;//this

0921          while(_token != _SC(')')) {
0922              Expression();
0923              MoveIfCurrentTargetIsLocal();
0924              nargs++;
0925              if(_token == _SC(',')){
0926                  Lex();
0927                  if(_token == ')') Error(_SC("expression expected, found ')'"));
0928              }
0929          }
0930          Lex();
0931          for(PSInteger i = 0; i < (nargs - 1); i++) _fs->PopTarget();
0932          PSInteger stackbase = _fs->PopTarget();
0933          PSInteger closure = _fs->PopTarget();
0934          _fs->AddInstruction(_OP_CALL, _fs->PushTarget(), closure, stackbase, nargs);
0935     }
0936     void ParseTableOrClass(PSInteger separator,PSInteger terminator)
0937     {
0938         PSInteger tpos = _fs->GetCurrentPos(),nkeys = 0;
0939         while(_token != terminator) {
0940             bool hasattrs = false;
0941             bool isstatic = false;
0942             //check if is an attribute

0943             if(separator == ';') {
0944                 if(_token == TK_ATTR_OPEN) {
0945                     _fs->AddInstruction(_OP_NEWOBJ, _fs->PushTarget(),0,NOT_TABLE); Lex();
0946                     ParseTableOrClass(',',TK_ATTR_CLOSE);
0947                     hasattrs = true;
0948                 }
0949                 if(_token == TK_STATIC) {
0950                     isstatic = true;
0951                     Lex();
0952                 }
0953             }
0954             switch(_token) {
0955             case TK_FUNCTION:
0956             case TK_CONSTRUCTOR:{
0957                 PSInteger tk = _token;
0958                 Lex();
0959                 PSObject id = tk == TK_FUNCTION ? Expect(TK_IDENTIFIER) : _fs->CreateString(_SC("constructor"));
0960                 Expect(_SC('('));
0961                 _fs->AddInstruction(_OP_LOAD, _fs->PushTarget(), _fs->GetConstant(id));
0962                 CreateFunction(id);
0963                 _fs->AddInstruction(_OP_CLOSURE, _fs->PushTarget(), _fs->_functions.size() - 1, 0);
0964                                 }
0965                                 break;
0966             case _SC('['):
0967                 Lex(); CommaExpr(); Expect(_SC(']'));
0968                 Expect(_SC('=')); Expression();
0969                 break;
0970             case TK_STRING_LITERAL: //JSON

0971                 if(separator == ',') { //only works for tables

0972                     _fs->AddInstruction(_OP_LOAD, _fs->PushTarget(), _fs->GetConstant(Expect(TK_STRING_LITERAL)));
0973                     Expect(_SC(':')); Expression();
0974                     break;
0975                 }
0976             default :
0977                 _fs->AddInstruction(_OP_LOAD, _fs->PushTarget(), _fs->GetConstant(Expect(TK_IDENTIFIER)));
0978                 Expect(_SC('=')); Expression();
0979             }
0980             if(_token == separator) Lex();//optional comma/semicolon

0981             nkeys++;
0982             PSInteger val = _fs->PopTarget();
0983             PSInteger key = _fs->PopTarget();
0984             PSInteger attrs = hasattrs ? _fs->PopTarget():-1;
0985             ((void)attrs);
0986             assert((hasattrs && (attrs == key-1)) || !hasattrs);
0987             unsigned char flags = (hasattrs?NEW_SLOT_ATTRIBUTES_FLAG:0)|(isstatic?NEW_SLOT_STATIC_FLAG:0);
0988             PSInteger table = _fs->TopTarget(); //<<BECAUSE OF THIS NO COMMON EMIT FUNC IS POSSIBLE

0989             if(separator == _SC(',')) { //hack recognizes a table from the separator

0990                 _fs->AddInstruction(_OP_NEWSLOT, 0xFF, table, key, val);
0991             }
0992             else {
0993                 _fs->AddInstruction(_OP_NEWSLOTA, flags, table, key, val); //this for classes only as it invokes _newmember

0994             }
0995         }
0996         if(separator == _SC(',')) //hack recognizes a table from the separator

0997             _fs->SetIntructionParam(tpos, 1, nkeys);
0998         Lex();
0999     }
1000     void LocalDeclStatement()
1001     {
1002         PSObject varname;
1003         Lex();
1004         if( _token == TK_FUNCTION) {
1005             Lex();
1006             varname = Expect(TK_IDENTIFIER);
1007             Expect(_SC('('));
1008             CreateFunction(varname,false);
1009             _fs->AddInstruction(_OP_CLOSURE, _fs->PushTarget(), _fs->_functions.size() - 1, 0);
1010             _fs->PopTarget();
1011             _fs->PushLocalVariable(varname);
1012             return;
1013         }
1014 
1015         do {
1016             varname = Expect(TK_IDENTIFIER);
1017             if(_token == _SC('=')) {
1018                 Lex(); Expression();
1019                 PSInteger src = _fs->PopTarget();
1020                 PSInteger dest = _fs->PushTarget();
1021                 if(dest != src) _fs->AddInstruction(_OP_MOVE, dest, src);
1022             }
1023             else{
1024                 _fs->AddInstruction(_OP_LOADNULLS, _fs->PushTarget(),1);
1025             }
1026             _fs->PopTarget();
1027             _fs->PushLocalVariable(varname);
1028             if(_token == _SC(',')) Lex(); else break;
1029         } while(1);
1030     }
1031     void IfBlock()
1032     {
1033         if (_token == _SC('{'))
1034         {
1035             BEGIN_SCOPE();
1036             Lex();
1037             Statements();
1038             Expect(_SC('}'));
1039             if (true) {
1040                 END_SCOPE();
1041             }
1042             else {
1043                 END_SCOPE_NO_CLOSE();
1044             }
1045         }
1046         else {
1047             //BEGIN_SCOPE();

1048             Statement();
1049             if (_lex._prevtoken != _SC('}') && _lex._prevtoken != _SC(';')) OptionalSemicolon();
1050             //END_SCOPE();

1051         }
1052     }
1053     void IfStatement()
1054     {
1055         PSInteger jmppos;
1056         bool haselse = false;
1057         Lex(); Expect(_SC('(')); CommaExpr(); Expect(_SC(')'));
1058         _fs->AddInstruction(_OP_JZ, _fs->PopTarget());
1059         PSInteger jnepos = _fs->GetCurrentPos();
1060 
1061 
1062 
1063         IfBlock();
1064         //

1065         /*static int n = 0;

1066         if (_token != _SC('}') && _token != TK_ELSE) {

1067             printf("IF %d-----------------------!!!!!!!!!\n", n);

1068             if (n == 5)

1069             {

1070                 printf("asd");

1071             }

1072             n++;

1073             //OptionalSemicolon();

1074         }*/
1075 
1076 
1077         PSInteger endifblock = _fs->GetCurrentPos();
1078         if(_token == TK_ELSE){
1079             haselse = true;
1080             //BEGIN_SCOPE();

1081             _fs->AddInstruction(_OP_JMP);
1082             jmppos = _fs->GetCurrentPos();
1083             Lex();
1084             //Statement(); if(_lex._prevtoken != _SC('}')) OptionalSemicolon();

1085             IfBlock();
1086             //END_SCOPE();

1087             _fs->SetIntructionParam(jmppos, 1, _fs->GetCurrentPos() - jmppos);
1088         }
1089         _fs->SetIntructionParam(jnepos, 1, endifblock - jnepos + (haselse?1:0));
1090     }
1091     void WhileStatement()
1092     {
1093         PSInteger jzpos, jmppos;
1094         jmppos = _fs->GetCurrentPos();
1095         Lex(); Expect(_SC('(')); CommaExpr(); Expect(_SC(')'));
1096 
1097         BEGIN_BREAKBLE_BLOCK();
1098         _fs->AddInstruction(_OP_JZ, _fs->PopTarget());
1099         jzpos = _fs->GetCurrentPos();
1100         BEGIN_SCOPE();
1101 
1102         Statement();
1103 
1104         END_SCOPE();
1105         _fs->AddInstruction(_OP_JMP, 0, jmppos - _fs->GetCurrentPos() - 1);
1106         _fs->SetIntructionParam(jzpos, 1, _fs->GetCurrentPos() - jzpos);
1107 
1108         END_BREAKBLE_BLOCK(jmppos);
1109     }
1110     void DoWhileStatement()
1111     {
1112         Lex();
1113         PSInteger jmptrg = _fs->GetCurrentPos();
1114         BEGIN_BREAKBLE_BLOCK()
1115         BEGIN_SCOPE();
1116         Statement();
1117         END_SCOPE();
1118         Expect(TK_WHILE);
1119         PSInteger continuetrg = _fs->GetCurrentPos();
1120         Expect(_SC('(')); CommaExpr(); Expect(_SC(')'));
1121         _fs->AddInstruction(_OP_JZ, _fs->PopTarget(), 1);
1122         _fs->AddInstruction(_OP_JMP, 0, jmptrg - _fs->GetCurrentPos() - 1);
1123         END_BREAKBLE_BLOCK(continuetrg);
1124     }
1125     void ForStatement()
1126     {
1127         Lex();
1128         BEGIN_SCOPE();
1129         Expect(_SC('('));
1130         if(_token == TK_LOCAL) LocalDeclStatement();
1131         else if(_token != _SC(';')){
1132             CommaExpr();
1133             _fs->PopTarget();
1134         }
1135         Expect(_SC(';'));
1136         _fs->SnoozeOpt();
1137         PSInteger jmppos = _fs->GetCurrentPos();
1138         PSInteger jzpos = -1;
1139         if(_token != _SC(';')) { CommaExpr(); _fs->AddInstruction(_OP_JZ, _fs->PopTarget()); jzpos = _fs->GetCurrentPos(); }
1140         Expect(_SC(';'));
1141         _fs->SnoozeOpt();
1142         PSInteger expstart = _fs->GetCurrentPos() + 1;
1143         if(_token != _SC(')')) {
1144             CommaExpr();
1145             _fs->PopTarget();
1146         }
1147         Expect(_SC(')'));
1148         _fs->SnoozeOpt();
1149         PSInteger expend = _fs->GetCurrentPos();
1150         PSInteger expsize = (expend - expstart) + 1;
1151         PSInstructionVec exp;
1152         if(expsize > 0) {
1153             for(PSInteger i = 0; i < expsize; i++)
1154                 exp.push_back(_fs->GetInstruction(expstart + i));
1155             _fs->PopInstructions(expsize);
1156         }
1157         BEGIN_BREAKBLE_BLOCK()
1158         Statement();
1159         PSInteger continuetrg = _fs->GetCurrentPos();
1160         if(expsize > 0) {
1161             for(PSInteger i = 0; i < expsize; i++)
1162                 _fs->AddInstruction(exp[i]);
1163         }
1164         _fs->AddInstruction(_OP_JMP, 0, jmppos - _fs->GetCurrentPos() - 1, 0);
1165         if(jzpos>  0) _fs->SetIntructionParam(jzpos, 1, _fs->GetCurrentPos() - jzpos);
1166         END_SCOPE();
1167 
1168         END_BREAKBLE_BLOCK(continuetrg);
1169     }
1170     void ForEachStatement()
1171     {
1172         PSObject idxname, valname;
1173         Lex(); Expect(_SC('(')); valname = Expect(TK_IDENTIFIER);
1174         if(_token == _SC(',')) {
1175             idxname = valname;
1176             Lex(); valname = Expect(TK_IDENTIFIER);
1177         }
1178         else{
1179             idxname = _fs->CreateString(_SC("@INDEX@"));
1180         }
1181         Expect(TK_IN);
1182 
1183         //save the stack size

1184         BEGIN_SCOPE();
1185         //put the table in the stack(evaluate the table expression)

1186         Expression(); Expect(_SC(')'));
1187         PSInteger container = _fs->TopTarget();
1188         //push the index local var

1189         PSInteger indexpos = _fs->PushLocalVariable(idxname);
1190         _fs->AddInstruction(_OP_LOADNULLS, indexpos,1);
1191         //push the value local var

1192         PSInteger valuepos = _fs->PushLocalVariable(valname);
1193         _fs->AddInstruction(_OP_LOADNULLS, valuepos,1);
1194         //push reference index

1195         PSInteger itrpos = _fs->PushLocalVariable(_fs->CreateString(_SC("@ITERATOR@"))); //use invalid id to make it inaccessible

1196         _fs->AddInstruction(_OP_LOADNULLS, itrpos,1);
1197         PSInteger jmppos = _fs->GetCurrentPos();
1198         _fs->AddInstruction(_OP_FOREACH, container, 0, indexpos);
1199         PSInteger foreachpos = _fs->GetCurrentPos();
1200         _fs->AddInstruction(_OP_POSTFOREACH, container, 0, indexpos);
1201         //generate the statement code

1202         BEGIN_BREAKBLE_BLOCK()
1203         Statement();
1204         _fs->AddInstruction(_OP_JMP, 0, jmppos - _fs->GetCurrentPos() - 1);
1205         _fs->SetIntructionParam(foreachpos, 1, _fs->GetCurrentPos() - foreachpos);
1206         _fs->SetIntructionParam(foreachpos + 1, 1, _fs->GetCurrentPos() - foreachpos);
1207         END_BREAKBLE_BLOCK(foreachpos - 1);
1208         //restore the local variable stack(remove index,val and ref idx)

1209         _fs->PopTarget();
1210         END_SCOPE();
1211     }
1212     void SwitchStatement()
1213     {
1214         Lex(); Expect(_SC('(')); CommaExpr(); Expect(_SC(')'));
1215         Expect(_SC('{'));
1216         PSInteger expr = _fs->TopTarget();
1217         bool bfirst = true;
1218         PSInteger tonextcondjmp = -1;
1219         PSInteger skipcondjmp = -1;
1220         PSInteger __nbreaks__ = _fs->_unresolvedbreaks.size();
1221         _fs->_breaktargets.push_back(0);
1222         while(_token == TK_CASE) {
1223             if(!bfirst) {
1224                 _fs->AddInstruction(_OP_JMP, 0, 0);
1225                 skipcondjmp = _fs->GetCurrentPos();
1226                 _fs->SetIntructionParam(tonextcondjmp, 1, _fs->GetCurrentPos() - tonextcondjmp);
1227             }
1228             //condition

1229             Lex(); Expression(); Expect(_SC(':'));
1230             PSInteger trg = _fs->PopTarget();
1231             PSInteger eqtarget = trg;
1232             bool local = _fs->IsLocal(trg);
1233             if(local) {
1234                 eqtarget = _fs->PushTarget(); //we need to allocate a extra reg

1235             }
1236             _fs->AddInstruction(_OP_EQ, eqtarget, trg, expr);
1237             _fs->AddInstruction(_OP_JZ, eqtarget, 0);
1238             if(local) {
1239                 _fs->PopTarget();
1240             }
1241 
1242             //end condition

1243             if(skipcondjmp != -1) {
1244                 _fs->SetIntructionParam(skipcondjmp, 1, (_fs->GetCurrentPos() - skipcondjmp));
1245             }
1246             tonextcondjmp = _fs->GetCurrentPos();
1247             BEGIN_SCOPE();
1248             Statements();
1249             END_SCOPE();
1250             bfirst = false;
1251         }
1252         if(tonextcondjmp != -1)
1253             _fs->SetIntructionParam(tonextcondjmp, 1, _fs->GetCurrentPos() - tonextcondjmp);
1254         if(_token == TK_DEFAULT) {
1255             Lex(); Expect(_SC(':'));
1256             BEGIN_SCOPE();
1257             Statements();
1258             END_SCOPE();
1259         }
1260         Expect(_SC('}'));
1261         _fs->PopTarget();
1262         __nbreaks__ = _fs->_unresolvedbreaks.size() - __nbreaks__;
1263         if(__nbreaks__ > 0)ResolveBreaks(_fs, __nbreaks__);
1264         _fs->_breaktargets.pop_back();
1265     }
1266     void FunctionStatement()
1267     {
1268         PSObject id;
1269         Lex(); id = Expect(TK_IDENTIFIER);
1270         _fs->PushTarget(0);
1271         _fs->AddInstruction(_OP_LOAD, _fs->PushTarget(), _fs->GetConstant(id));
1272         if(_token == TK_DOUBLE_COLON) Emit2ArgsOP(_OP_GET);
1273 
1274         while(_token == TK_DOUBLE_COLON) {
1275             Lex();
1276             id = Expect(TK_IDENTIFIER);
1277             _fs->AddInstruction(_OP_LOAD, _fs->PushTarget(), _fs->GetConstant(id));
1278             if(_token == TK_DOUBLE_COLON) Emit2ArgsOP(_OP_GET);
1279         }
1280         Expect(_SC('('));
1281         CreateFunction(id);
1282         _fs->AddInstruction(_OP_CLOSURE, _fs->PushTarget(), _fs->_functions.size() - 1, 0);
1283         EmitDerefOp(_OP_NEWSLOT);
1284         _fs->PopTarget();
1285     }
1286     void ClassStatement()
1287     {
1288         PSExpState es;
1289         Lex();
1290         es = _es;
1291         _es.donot_get = true;
1292         PrefixedExpr();
1293         if(_es.etype == EXPR) {
1294             Error(_SC("invalid class name"));
1295         }
1296         else if(_es.etype == OBJECT || _es.etype == BASE) {
1297             ClassExp();
1298             EmitDerefOp(_OP_NEWSLOT);
1299             _fs->PopTarget();
1300         }
1301         else {
1302             Error(_SC("cannot create a class in a local with the syntax(class <local>)"));
1303         }
1304         _es = es;
1305     }
1306     PSObject ExpectScalar()
1307     {
1308         PSObject val;
1309         val._type = OT_NULL; val._unVal.nInteger = 0; //shut up GCC 4.x

1310         switch(_token) {
1311             case TK_INTEGER:
1312                 val._type = OT_INTEGER;
1313                 val._unVal.nInteger = _lex._nvalue;
1314                 break;
1315             case TK_FLOAT:
1316                 val._type = OT_FLOAT;
1317                 val._unVal.fFloat = _lex._fvalue;
1318                 break;
1319             case TK_STRING_LITERAL:
1320                 val = _fs->CreateString(_lex._svalue,_lex._longstr.size()-1);
1321                 break;
1322             case TK_TRUE:
1323             case TK_FALSE:
1324                 val._type = OT_BOOL;
1325                 val._unVal.nInteger = _token == TK_TRUE ? 1 : 0;
1326                 break;
1327             case '-':
1328                 Lex();
1329                 switch(_token)
1330                 {
1331                 case TK_INTEGER:
1332                     val._type = OT_INTEGER;
1333                     val._unVal.nInteger = -_lex._nvalue;
1334                 break;
1335                 case TK_FLOAT:
1336                     val._type = OT_FLOAT;
1337                     val._unVal.fFloat = -_lex._fvalue;
1338                 break;
1339                 default:
1340                     Error(_SC("scalar expected : integer,float"));
1341                 }
1342                 break;
1343             default:
1344                 Error(_SC("scalar expected : integer,float or string"));
1345         }
1346         Lex();
1347         return val;
1348     }
1349     void EnumStatement()
1350     {
1351         Lex();
1352         PSObject id = Expect(TK_IDENTIFIER);
1353         Expect(_SC('{'));
1354 
1355         PSObject table = _fs->CreateTable();
1356         PSInteger nval = 0;
1357         while(_token != _SC('}')) {
1358             PSObject key = Expect(TK_IDENTIFIER);
1359             PSObject val;
1360             if(_token == _SC('=')) {
1361                 Lex();
1362                 val = ExpectScalar();
1363             }
1364             else {
1365                 val._type = OT_INTEGER;
1366                 val._unVal.nInteger = nval++;
1367             }
1368             _table(table)->NewSlot(PSObjectPtr(key),PSObjectPtr(val));
1369             if(_token == ',') Lex();
1370         }
1371         PSTable *enums = _table(_ss(_vm)->_consts);
1372         PSObjectPtr strongid = id;
1373         enums->NewSlot(PSObjectPtr(strongid),PSObjectPtr(table));
1374         strongid.Null();
1375         Lex();
1376     }
1377     void TryCatchStatement()
1378     {
1379         PSObject exid;
1380         Lex();
1381         _fs->AddInstruction(_OP_PUSHTRAP,0,0);
1382         _fs->_traps++;
1383         if(_fs->_breaktargets.size()) _fs->_breaktargets.top()++;
1384         if(_fs->_continuetargets.size()) _fs->_continuetargets.top()++;
1385         PSInteger trappos = _fs->GetCurrentPos();
1386         {
1387             BEGIN_SCOPE();
1388             Statement();
1389             END_SCOPE();
1390         }
1391         _fs->_traps--;
1392         _fs->AddInstruction(_OP_POPTRAP, 1, 0);
1393         if(_fs->_breaktargets.size()) _fs->_breaktargets.top()--;
1394         if(_fs->_continuetargets.size()) _fs->_continuetargets.top()--;
1395         _fs->AddInstruction(_OP_JMP, 0, 0);
1396         PSInteger jmppos = _fs->GetCurrentPos();
1397         _fs->SetIntructionParam(trappos, 1, (_fs->GetCurrentPos() - trappos));
1398         Expect(TK_CATCH); Expect(_SC('(')); exid = Expect(TK_IDENTIFIER); Expect(_SC(')'));
1399         {
1400             BEGIN_SCOPE();
1401             PSInteger ex_target = _fs->PushLocalVariable(exid);
1402             _fs->SetIntructionParam(trappos, 0, ex_target);
1403             Statement();
1404             _fs->SetIntructionParams(jmppos, 0, (_fs->GetCurrentPos() - jmppos), 0);
1405             END_SCOPE();
1406         }
1407     }
1408     void FunctionExp(PSInteger ftype,bool lambda = false)
1409     {
1410         Lex(); Expect(_SC('('));
1411         PSObjectPtr dummy;
1412         CreateFunction(dummy,lambda);
1413         _fs->AddInstruction(_OP_CLOSURE, _fs->PushTarget(), _fs->_functions.size() - 1, ftype == TK_FUNCTION?0:1);
1414     }
1415     void ClassExp()
1416     {
1417         PSInteger base = -1;
1418         PSInteger attrs = -1;
1419         if(_token == TK_EXTENDS) {
1420             Lex(); Expression();
1421             base = _fs->TopTarget();
1422         }
1423         if(_token == TK_ATTR_OPEN) {
1424             Lex();
1425             _fs->AddInstruction(_OP_NEWOBJ, _fs->PushTarget(),0,NOT_TABLE);
1426             ParseTableOrClass(_SC(','),TK_ATTR_CLOSE);
1427             attrs = _fs->TopTarget();
1428         }
1429         Expect(_SC('{'));
1430         if(attrs != -1) _fs->PopTarget();
1431         if(base != -1) _fs->PopTarget();
1432         _fs->AddInstruction(_OP_NEWOBJ, _fs->PushTarget(), base, attrs,NOT_CLASS);
1433         ParseTableOrClass(_SC(';'),_SC('}'));
1434     }
1435     void DeleteExpr()
1436     {
1437         PSExpState es;
1438         Lex();
1439         es = _es;
1440         _es.donot_get = true;
1441         PrefixedExpr();
1442         if(_es.etype==EXPR) Error(_SC("can't delete an expression"));
1443         if(_es.etype==OBJECT || _es.etype==BASE) {
1444             Emit2ArgsOP(_OP_DELETE);
1445         }
1446         else {
1447             Error(_SC("cannot delete an (outer) local"));
1448         }
1449         _es = es;
1450     }
1451     void PrefixIncDec(PSInteger token)
1452     {
1453         PSExpState  es;
1454         PSInteger diff = (token==TK_MINUSMINUS) ? -1 : 1;
1455         Lex();
1456         es = _es;
1457         _es.donot_get = true;
1458         PrefixedExpr();
1459         if(_es.etype==EXPR) {
1460             Error(_SC("can't '++' or '--' an expression"));
1461         }
1462         else if(_es.etype==OBJECT || _es.etype==BASE) {
1463             Emit2ArgsOP(_OP_INC, diff);
1464         }
1465         else if(_es.etype==LOCAL) {
1466             PSInteger src = _fs->TopTarget();
1467             _fs->AddInstruction(_OP_INCL, src, src, 0, diff);
1468 
1469         }
1470         else if(_es.etype==OUTER) {
1471             PSInteger tmp = _fs->PushTarget();
1472             _fs->AddInstruction(_OP_GETOUTER, tmp, _es.epos);
1473             _fs->AddInstruction(_OP_INCL,     tmp, tmp, 0, diff);
1474             _fs->AddInstruction(_OP_SETOUTER, tmp, _es.epos, tmp);
1475         }
1476         _es = es;
1477     }
1478     void CreateFunction(PSObject &name,bool lambda = false)
1479     {
1480         PSFuncState *funcstate = _fs->PushChildState(_ss(_vm));
1481         funcstate->_name = name;
1482         PSObject paramname;
1483         funcstate->AddParameter(_fs->CreateString(_SC("this")));
1484         funcstate->_sourcename = _sourcename;
1485         PSInteger defparams = 0;
1486         while(_token!=_SC(')')) {
1487             if(_token == TK_VARPARAMS) {
1488                 if(defparams > 0) Error(_SC("function with default parameters cannot have variable number of parameters"));
1489                 funcstate->AddParameter(_fs->CreateString(_SC("vargv")));
1490                 funcstate->_varparams = true;
1491                 Lex();
1492                 if(_token != _SC(')')) Error(_SC("expected ')'"));
1493                 break;
1494             }
1495             else {
1496                 paramname = Expect(TK_IDENTIFIER);
1497                 funcstate->AddParameter(paramname);
1498                 if(_token == _SC('=')) {
1499                     Lex();
1500                     Expression();
1501                     funcstate->AddDefaultParam(_fs->TopTarget());
1502                     defparams++;
1503                 }
1504                 else {
1505                     if(defparams > 0) Error(_SC("expected '='"));
1506                 }
1507                 if(_token == _SC(',')) Lex();
1508                 else if(_token != _SC(')')) Error(_SC("expected ')' or ','"));
1509             }
1510         }
1511         Expect(_SC(')'));
1512         for(PSInteger n = 0; n < defparams; n++) {
1513             _fs->PopTarget();
1514         }
1515 
1516         PSFuncState *currchunk = _fs;
1517         _fs = funcstate;
1518         if(lambda) {
1519             Expression();
1520             _fs->AddInstruction(_OP_RETURN, 1, _fs->PopTarget());}
1521         else {
1522             Statement(false);
1523         }
1524         funcstate->AddLineInfos(_lex._prevtoken == _SC('\n')?_lex._lasttokenline:_lex._currentline, _lineinfo, true);
1525         funcstate->AddInstruction(_OP_RETURN, -1);
1526         funcstate->SetStackSize(0);
1527 
1528         PSFunctionProto *func = funcstate->BuildProto();
1529 #ifdef _DEBUG_DUMP
1530         funcstate->Dump(func);
1531 #endif
1532         _fs = currchunk;
1533         _fs->_functions.push_back(func);
1534         _fs->PopChildState();
1535     }
1536     void ResolveBreaks(PSFuncState *funcstate, PSInteger ntoresolve)
1537     {
1538         while(ntoresolve > 0) {
1539             PSInteger pos = funcstate->_unresolvedbreaks.back();
1540             funcstate->_unresolvedbreaks.pop_back();
1541             //set the jmp instruction

1542             funcstate->SetIntructionParams(pos, 0, funcstate->GetCurrentPos() - pos, 0);
1543             ntoresolve--;
1544         }
1545     }
1546     void ResolveContinues(PSFuncState *funcstate, PSInteger ntoresolve, PSInteger targetpos)
1547     {
1548         while(ntoresolve > 0) {
1549             PSInteger pos = funcstate->_unresolvedcontinues.back();
1550             funcstate->_unresolvedcontinues.pop_back();
1551             //set the jmp instruction

1552             funcstate->SetIntructionParams(pos, 0, targetpos - pos, 0);
1553             ntoresolve--;
1554         }
1555     }
1556 private:
1557     PSInteger _token;
1558     PSFuncState *_fs;
1559     PSObjectPtr _sourcename;
1560     PSLexer _lex;
1561     bool _lineinfo;
1562     bool _raiseerror;
1563     PSInteger _debugline;
1564     PSInteger _debugop;
1565     PSExpState   _es;
1566     PSScope _scope;
1567     PSChar _compilererror[MAX_COMPILER_ERROR_LEN];
1568     jmp_buf _errorjmp;
1569     PSVM *_vm;
1570 };
1571 
1572 bool Compile(PSVM *vm,PSLEXREADFUNC rg, PSUserPointer up, const PSChar *sourcename, PSObjectPtr &out, bool raiseerror, bool lineinfo)
1573 {
1574     PSCompiler p(vm, rg, up, sourcename, raiseerror, lineinfo);
1575     return p.Compile(out);
1576 }
1577 
1578 #endif