00001
00002
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
00095
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();
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();
00314 SQInteger p1 = _fs->PopTarget();
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;
00327 assert(0); break;
00328 };
00329 if(deref) {
00330 SQInteger val = _fs->PopTarget();
00331 SQInteger key = _fs->PopTarget();
00332 SQInteger src = _fs->PopTarget();
00333
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
00371 Error(_SC("can't 'create' a local slot"));
00372 break;
00373 case _SC('='):
00374 if(freevar) Error(_SC("free variables cannot be modified"));
00375 if(ds == DEREF_FIELD)
00376 EmitDerefOp(_OP_SET);
00377 else {
00378 SQInteger p2 = _fs->PopTarget();
00379 SQInteger p1 = _fs->TopTarget();
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
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 {
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();
00578 SQInteger table = _fs->PopTarget();
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
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
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)) {
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('.');
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) {
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;
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
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();
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();
00835 _fs->AddInstruction(_OP_NEWSLOTA, flags, table, key, val);
00836
00837 }
00838 if(separator == _SC(','))
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
00984 SQInteger stacksize = _fs->GetStackSize();
00985
00986 Expression(); Expect(_SC(')'));
00987 SQInteger container = _fs->TopTarget();
00988
00989 SQInteger indexpos = _fs->PushLocalVariable(idxname);
00990 _fs->AddInstruction(_OP_LOADNULLS, indexpos,1);
00991
00992 SQInteger valuepos = _fs->PushLocalVariable(valname);
00993 _fs->AddInstruction(_OP_LOADNULLS, valuepos,1);
00994
00995 SQInteger itrpos = _fs->PushLocalVariable(_fs->CreateString(_SC("@ITERATOR@")));
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
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
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
01024 if(!bfirst) {
01025 _fs->AddInstruction(_OP_JMP, 0, 0);
01026 skipcondjmp = _fs->GetCurrentPos();
01027 _fs->SetIntructionParam(tonextcondjmp, 1, _fs->GetCurrentPos() - tonextcondjmp);
01028 }
01029
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
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
01049 Lex(); Expect(_SC(':'));
01050 SQInteger stacksize = _fs->GetStackSize();
01051 _last_stacksize = _fs->GetStackSize();
01052 Statements();
01053 _fs->SetStackSize(stacksize);
01054 }
01055 Expect(_SC('}'));
01056 _fs->PopTarget();
01057 __nbreaks__ = _fs->_unresolvedbreaks.size() - __nbreaks__;
01058 if(__nbreaks__ > 0)ResolveBreaks(_fs, __nbreaks__);
01059 _fs->_breaktargets.pop_back();
01060
01061 }
01062 void FunctionStatement()
01063 {
01064 SQObject id;
01065 Lex(); id = Expect(TK_IDENTIFIER);
01066 _fs->PushTarget(0);
01067 _fs->AddInstruction(_OP_LOAD, _fs->PushTarget(), _fs->GetConstant(id));
01068 if(_token == TK_DOUBLE_COLON) Emit2ArgsOP(_OP_GET);
01069
01070 while(_token == TK_DOUBLE_COLON) {
01071 Lex();
01072 id = Expect(TK_IDENTIFIER);
01073 _fs->AddInstruction(_OP_LOAD, _fs->PushTarget(), _fs->GetConstant(id));
01074 if(_token == TK_DOUBLE_COLON) Emit2ArgsOP(_OP_GET);
01075 }
01076 Expect(_SC('('));
01077 CreateFunction(id);
01078 _fs->AddInstruction(_OP_CLOSURE, _fs->PushTarget(), _fs->_functions.size() - 1, 0);
01079 EmitDerefOp(_OP_NEWSLOT);
01080 _fs->PopTarget();
01081 }
01082 void ClassStatement()
01083 {
01084 ExpState es;
01085 Lex(); PushExpState();
01086 _exst._class_or_delete = true;
01087 _exst._funcarg = false;
01088 PrefixedExpr();
01089 es = PopExpState();
01090 if(es._deref == DEREF_NO_DEREF) Error(_SC("invalid class name"));
01091 if(es._deref == DEREF_FIELD) {
01092 ClassExp();
01093 EmitDerefOp(_OP_NEWSLOT);
01094 _fs->PopTarget();
01095 }
01096 else Error(_SC("cannot create a class in a local with the syntax(class <local>)"));
01097 }
01098 SQObject ExpectScalar()
01099 {
01100 SQObject val;
01101 switch(_token) {
01102 case TK_INTEGER:
01103 val._type = OT_INTEGER;
01104 val._unVal.nInteger = _lex._nvalue;
01105 break;
01106 case TK_FLOAT:
01107 val._type = OT_FLOAT;
01108 val._unVal.fFloat = _lex._fvalue;
01109 break;
01110 case TK_STRING_LITERAL:
01111 val = _fs->CreateString(_lex._svalue,_lex._longstr.size()-1);
01112 break;
01113 default:
01114 Error(_SC("scalar expected : integer,float or string"));
01115 val._type = OT_NULL;
01116 }
01117 Lex();
01118 return val;
01119 }
01120 void EnumStatement()
01121 {
01122
01123 Lex();
01124 SQObject id = Expect(TK_IDENTIFIER);
01125 Expect(_SC('{'));
01126
01127 SQObject table = _fs->CreateTable();
01128 SQInteger nval = 0;
01129 while(_token != _SC('}')) {
01130 SQObject key = Expect(TK_IDENTIFIER);
01131 SQObject val;
01132 if(_token == _SC('=')) {
01133 Lex();
01134 val = ExpectScalar();
01135 }
01136 else {
01137 val._type = OT_INTEGER;
01138 val._unVal.nInteger = nval++;
01139 }
01140 _table(table)->NewSlot(SQObjectPtr(key),SQObjectPtr(val));
01141 if(_token == ',') Lex();
01142 }
01143 SQTable *enums = _table(_ss(_vm)->_consts);
01144 SQObjectPtr strongid = id;
01145
01146
01147
01148
01149
01150 enums->NewSlot(SQObjectPtr(strongid),SQObjectPtr(table));
01151 strongid.Null();
01152 Lex();
01153
01154 }
01155 void TryCatchStatement()
01156 {
01157 SQObject exid;
01158 Lex();
01159 _fs->AddInstruction(_OP_PUSHTRAP,0,0);
01160 _fs->_traps++;
01161 if(_fs->_breaktargets.size()) _fs->_breaktargets.top()++;
01162 if(_fs->_continuetargets.size()) _fs->_continuetargets.top()++;
01163 SQInteger trappos = _fs->GetCurrentPos();
01164 Statement();
01165 _fs->_traps--;
01166 _fs->AddInstruction(_OP_POPTRAP, 1, 0);
01167 if(_fs->_breaktargets.size()) _fs->_breaktargets.top()--;
01168 if(_fs->_continuetargets.size()) _fs->_continuetargets.top()--;
01169 _fs->AddInstruction(_OP_JMP, 0, 0);
01170 SQInteger jmppos = _fs->GetCurrentPos();
01171 _fs->SetIntructionParam(trappos, 1, (_fs->GetCurrentPos() - trappos));
01172 Expect(TK_CATCH); Expect(_SC('(')); exid = Expect(TK_IDENTIFIER); Expect(_SC(')'));
01173 SQInteger stacksize = _fs->GetStackSize();
01174 SQInteger ex_target = _fs->PushLocalVariable(exid);
01175 _fs->SetIntructionParam(trappos, 0, ex_target);
01176 Statement();
01177 _fs->SetIntructionParams(jmppos, 0, (_fs->GetCurrentPos() - jmppos), 0);
01178 CleanStack(stacksize);
01179 }
01180 void FunctionExp(SQInteger ftype)
01181 {
01182 Lex(); Expect(_SC('('));
01183 CreateFunction(_null_);
01184 _fs->AddInstruction(_OP_CLOSURE, _fs->PushTarget(), _fs->_functions.size() - 1, ftype == TK_FUNCTION?0:1);
01185 }
01186 void ClassExp()
01187 {
01188 SQInteger base = -1;
01189 SQInteger attrs = -1;
01190 if(_token == TK_EXTENDS) {
01191 Lex(); Expression();
01192 base = _fs->TopTarget();
01193 }
01194 if(_token == TK_ATTR_OPEN) {
01195 Lex();
01196 _fs->AddInstruction(_OP_NEWTABLE, _fs->PushTarget());
01197 ParseTableOrClass(_SC(','),TK_ATTR_CLOSE);
01198 attrs = _fs->TopTarget();
01199 }
01200 Expect(_SC('{'));
01201 if(attrs != -1) _fs->PopTarget();
01202 if(base != -1) _fs->PopTarget();
01203 _fs->AddInstruction(_OP_CLASS, _fs->PushTarget(), base, attrs);
01204 ParseTableOrClass(_SC(';'));
01205 }
01206 void DelegateExpr()
01207 {
01208 Lex(); CommaExpr();
01209 Expect(_SC(':'));
01210 CommaExpr();
01211 SQInteger table = _fs->PopTarget(), delegate = _fs->PopTarget();
01212 _fs->AddInstruction(_OP_DELEGATE, _fs->PushTarget(), table, delegate);
01213 }
01214 void DeleteExpr()
01215 {
01216 ExpState es;
01217 Lex(); PushExpState();
01218 _exst._class_or_delete = true;
01219 _exst._funcarg = false;
01220 PrefixedExpr();
01221 es = PopExpState();
01222 if(es._deref == DEREF_NO_DEREF) Error(_SC("can't delete an expression"));
01223 if(es._deref == DEREF_FIELD) Emit2ArgsOP(_OP_DELETE);
01224 else Error(_SC("cannot delete a local"));
01225 }
01226 void PrefixIncDec(SQInteger token)
01227 {
01228 ExpState es;
01229 Lex(); PushExpState();
01230 _exst._class_or_delete = true;
01231 _exst._funcarg = false;
01232 PrefixedExpr();
01233 es = PopExpState();
01234 if(es._deref == DEREF_FIELD) Emit2ArgsOP(_OP_INC,token == TK_MINUSMINUS?-1:1);
01235 else {
01236 SQInteger src = _fs->PopTarget();
01237 _fs->AddInstruction(_OP_INCL, _fs->PushTarget(), src, 0, token == TK_MINUSMINUS?-1:1);
01238 }
01239 }
01240 void CreateFunction(SQObject &name)
01241 {
01242
01243 SQFuncState *funcstate = _fs->PushChildState(_ss(_vm));
01244 funcstate->_name = name;
01245 SQObject paramname;
01246 funcstate->AddParameter(_fs->CreateString(_SC("this")));
01247 funcstate->_sourcename = _sourcename;
01248 SQInteger defparams = 0;
01249 while(_token!=_SC(')')) {
01250 if(_token == TK_VARPARAMS) {
01251 if(defparams > 0) Error(_SC("function with default parameters cannot have variable number of parameters"));
01252 funcstate->_varparams = true;
01253 Lex();
01254 if(_token != _SC(')')) Error(_SC("expected ')'"));
01255 break;
01256 }
01257 else {
01258 paramname = Expect(TK_IDENTIFIER);
01259 funcstate->AddParameter(paramname);
01260 if(_token == _SC('=')) {
01261 Lex();
01262 Expression();
01263 funcstate->AddDefaultParam(_fs->TopTarget());
01264 defparams++;
01265 }
01266 else {
01267 if(defparams > 0) Error(_SC("expected '='"));
01268 }
01269 if(_token == _SC(',')) Lex();
01270 else if(_token != _SC(')')) Error(_SC("expected ')' or ','"));
01271 }
01272 }
01273 Expect(_SC(')'));
01274 for(SQInteger n = 0; n < defparams; n++) {
01275 _fs->PopTarget();
01276 }
01277
01278 if(_token == _SC(':')) {
01279 Lex(); Expect(_SC('('));
01280 while(_token != _SC(')')) {
01281 paramname = Expect(TK_IDENTIFIER);
01282
01283 funcstate->AddOuterValue(paramname);
01284 if(_token == _SC(',')) Lex();
01285 else if(_token != _SC(')')) Error(_SC("expected ')' or ','"));
01286 }
01287 Lex();
01288 }
01289
01290 SQFuncState *currchunk = _fs;
01291 _fs = funcstate;
01292 Statement();
01293 funcstate->AddLineInfos(_lex._prevtoken == _SC('\n')?_lex._lasttokenline:_lex._currentline, _lineinfo, true);
01294 funcstate->AddInstruction(_OP_RETURN, -1);
01295 funcstate->SetStackSize(0);
01296
01297 SQFunctionProto *func = funcstate->BuildProto();
01298 #ifdef _DEBUG_DUMP
01299 funcstate->Dump(func);
01300 #endif
01301 _fs = currchunk;
01302 _fs->_functions.push_back(func);
01303 _fs->PopChildState();
01304 }
01305 void CleanStack(SQInteger stacksize)
01306 {
01307 if(_fs->GetStackSize() != stacksize)
01308 _fs->SetStackSize(stacksize);
01309 }
01310 void ResolveBreaks(SQFuncState *funcstate, SQInteger ntoresolve)
01311 {
01312 while(ntoresolve > 0) {
01313 SQInteger pos = funcstate->_unresolvedbreaks.back();
01314 funcstate->_unresolvedbreaks.pop_back();
01315
01316 funcstate->SetIntructionParams(pos, 0, funcstate->GetCurrentPos() - pos, 0);
01317 ntoresolve--;
01318 }
01319 }
01320 void ResolveContinues(SQFuncState *funcstate, SQInteger ntoresolve, SQInteger targetpos)
01321 {
01322 while(ntoresolve > 0) {
01323 SQInteger pos = funcstate->_unresolvedcontinues.back();
01324 funcstate->_unresolvedcontinues.pop_back();
01325
01326 funcstate->SetIntructionParams(pos, 0, targetpos - pos, 0);
01327 ntoresolve--;
01328 }
01329 }
01330 private:
01331 SQInteger _token;
01332 SQFuncState *_fs;
01333 SQObjectPtr _sourcename;
01334 SQLexer _lex;
01335 bool _lineinfo;
01336 bool _raiseerror;
01337 SQInteger _debugline;
01338 SQInteger _debugop;
01339 ExpStateVec _expstates;
01340 SQVM *_vm;
01341 };
01342
01343 bool Compile(SQVM *vm,SQLEXREADFUNC rg, SQUserPointer up, const SQChar *sourcename, SQObjectPtr &out, bool raiseerror, bool lineinfo)
01344 {
01345 SQCompiler p(vm, rg, up, sourcename, raiseerror, lineinfo);
01346 return p.Compile(out);
01347 }