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