1 /*
2 see copyright notice in squirrel.h
3 */
4 #include "sqpcheader.h"
5 #include <stdarg.h>
6 #include <setjmp.h>
7 #include "sqopcodes.h"
8 #include "sqstring.h"
9 #include "sqfuncproto.h"
10 #include "sqcompiler.h"
11 #include "sqfuncstate.h"
12 #include "sqlexer.h"
13 #include "sqvm.h"
14 #include "sqtable.h"
15
16 #define DEREF_NO_DEREF -1
17 #define DEREF_FIELD -2
18
19 struct ExpState
20 {
ExpStateExpState21 ExpState()
22 {
23 _deref = DEREF_NO_DEREF;
24 _freevar = false;
25 _class_or_delete = false;
26 _funcarg = false;
27 }
28 bool _class_or_delete;
29 bool _funcarg;
30 bool _freevar;
31 SQInteger _deref;
32 };
33
34 typedef sqvector<ExpState> ExpStateVec;
35
36 #define _exst (_expstates.top())
37
38 #define BEGIN_BREAKBLE_BLOCK() SQInteger __nbreaks__=_fs->_unresolvedbreaks.size(); \
39 SQInteger __ncontinues__=_fs->_unresolvedcontinues.size(); \
40 _fs->_breaktargets.push_back(0);_fs->_continuetargets.push_back(0);
41
42 #define END_BREAKBLE_BLOCK(continue_target) {__nbreaks__=_fs->_unresolvedbreaks.size()-__nbreaks__; \
43 __ncontinues__=_fs->_unresolvedcontinues.size()-__ncontinues__; \
44 if(__ncontinues__>0)ResolveContinues(_fs,__ncontinues__,continue_target); \
45 if(__nbreaks__>0)ResolveBreaks(_fs,__nbreaks__); \
46 _fs->_breaktargets.pop_back();_fs->_continuetargets.pop_back();}
47
48 class SQCompiler
49 {
50 public:
SQCompiler(SQVM * v,SQLEXREADFUNC rg,SQUserPointer up,const SQChar * sourcename,bool raiseerror,bool lineinfo)51 SQCompiler(SQVM *v, SQLEXREADFUNC rg, SQUserPointer up, const SQChar* sourcename, bool raiseerror, bool lineinfo)
52 {
53 _vm=v;
54 _lex.Init(_ss(v), rg, up,ThrowError,this);
55 _sourcename = SQString::Create(_ss(v), sourcename);
56 _lineinfo = lineinfo;_raiseerror = raiseerror;
57 compilererror = NULL;
58 }
ThrowError(void * ud,const SQChar * s)59 static void ThrowError(void *ud, const SQChar *s) {
60 SQCompiler *c = (SQCompiler *)ud;
61 c->Error(s);
62 }
Error(const SQChar * s,...)63 void Error(const SQChar *s, ...)
64 {
65 static SQChar temp[256];
66 va_list vl;
67 va_start(vl, s);
68 scvsprintf(temp, s, vl);
69 va_end(vl);
70 compilererror = temp;
71 longjmp(_errorjmp,1);
72 }
Lex()73 void Lex(){ _token = _lex.Lex();}
PushExpState()74 void PushExpState(){ _expstates.push_back(ExpState()); }
IsDerefToken(SQInteger tok)75 bool IsDerefToken(SQInteger tok)
76 {
77 switch(tok){
78 case _SC('='): case _SC('('): case TK_NEWSLOT:
79 case TK_MODEQ: case TK_MULEQ: case TK_DIVEQ: case TK_MINUSEQ: case TK_PLUSEQ: case TK_PLUSPLUS: case TK_MINUSMINUS: return true;
80 }
81 return false;
82 }
PopExpState()83 ExpState PopExpState()
84 {
85 ExpState ret = _expstates.top();
86 _expstates.pop_back();
87 return ret;
88 }
Expect(SQInteger tok)89 SQObject Expect(SQInteger tok)
90 {
91
92 if(_token != tok) {
93 if(_token == TK_CONSTRUCTOR && tok == TK_IDENTIFIER) {
94 //ret = SQString::Create(_ss(_vm),_SC("constructor"));
95 //do nothing
96 }
97 else {
98 const SQChar *etypename;
99 if(tok > 255) {
100 switch(tok)
101 {
102 case TK_IDENTIFIER:
103 etypename = _SC("IDENTIFIER");
104 break;
105 case TK_STRING_LITERAL:
106 etypename = _SC("STRING_LITERAL");
107 break;
108 case TK_INTEGER:
109 etypename = _SC("INTEGER");
110 break;
111 case TK_FLOAT:
112 etypename = _SC("FLOAT");
113 break;
114 default:
115 etypename = _lex.Tok2Str(tok);
116 }
117 Error(_SC("expected '%s'"), etypename);
118 }
119 Error(_SC("expected '%c'"), tok);
120 }
121 }
122 SQObjectPtr ret;
123 switch(tok)
124 {
125 case TK_IDENTIFIER:
126 ret = _fs->CreateString(_lex._svalue);
127 break;
128 case TK_STRING_LITERAL:
129 ret = _fs->CreateString(_lex._svalue,_lex._longstr.size()-1);
130 break;
131 case TK_INTEGER:
132 ret = SQObjectPtr(_lex._nvalue);
133 break;
134 case TK_FLOAT:
135 ret = SQObjectPtr(_lex._fvalue);
136 break;
137 }
138 Lex();
139 return ret;
140 }
IsEndOfStatement()141 bool IsEndOfStatement() { return ((_lex._prevtoken == _SC('\n')) || (_token == SQUIRREL_EOB) || (_token == _SC('}')) || (_token == _SC(';'))); }
OptionalSemicolon()142 void OptionalSemicolon()
143 {
144 if(_token == _SC(';')) { Lex(); return; }
145 if(!IsEndOfStatement()) {
146 Error(_SC("end of statement expected (; or lf)"));
147 }
148 }
MoveIfCurrentTargetIsLocal()149 void MoveIfCurrentTargetIsLocal() {
150 SQInteger trg = _fs->TopTarget();
151 if(_fs->IsLocal(trg)) {
152 trg = _fs->PopTarget(); //no pops the target and move it
153 _fs->AddInstruction(_OP_MOVE, _fs->PushTarget(), trg);
154 }
155 }
Compile(SQObjectPtr & o)156 bool Compile(SQObjectPtr &o)
157 {
158 _debugline = 1;
159 _debugop = 0;
160
161 SQFuncState funcstate(_ss(_vm), NULL,ThrowError,this);
162 funcstate._name = SQString::Create(_ss(_vm), _SC("main"));
163 _fs = &funcstate;
164 _fs->AddParameter(_fs->CreateString(_SC("this")));
165 _fs->_sourcename = _sourcename;
166 SQInteger stacksize = _fs->GetStackSize();
167 if(setjmp(_errorjmp) == 0) {
168 Lex();
169 while(_token > 0){
170 Statement();
171 if(_lex._prevtoken != _SC('}')) OptionalSemicolon();
172 }
173 CleanStack(stacksize);
174 _fs->AddLineInfos(_lex._currentline, _lineinfo, true);
175 _fs->AddInstruction(_OP_RETURN, 0xFF);
176 _fs->SetStackSize(0);
177 o =_fs->BuildProto();
178 #ifdef _DEBUG_DUMP
179 _fs->Dump(_funcproto(o));
180 #endif
181 }
182 else {
183 if(_raiseerror && _ss(_vm)->_compilererrorhandler) {
184 _ss(_vm)->_compilererrorhandler(_vm, compilererror, type(_sourcename) == OT_STRING?_stringval(_sourcename):_SC("unknown"),
185 _lex._currentline, _lex._currentcolumn);
186 }
187 _vm->_lasterror = SQString::Create(_ss(_vm), compilererror, -1);
188 return false;
189 }
190 return true;
191 }
Statements()192 void Statements()
193 {
194 while(_token != _SC('}') && _token != TK_DEFAULT && _token != TK_CASE) {
195 Statement();
196 if(_lex._prevtoken != _SC('}') && _lex._prevtoken != _SC(';')) OptionalSemicolon();
197 }
198 }
Statement()199 void Statement()
200 {
201 _fs->AddLineInfos(_lex._currentline, _lineinfo);
202 switch(_token){
203 case _SC(';'): Lex(); break;
204 case TK_IF: IfStatement(); break;
205 case TK_WHILE: WhileStatement(); break;
206 case TK_DO: DoWhileStatement(); break;
207 case TK_FOR: ForStatement(); break;
208 case TK_FOREACH: ForEachStatement(); break;
209 case TK_SWITCH: SwitchStatement(); break;
210 case TK_LOCAL: LocalDeclStatement(); break;
211 case TK_RETURN:
212 case TK_YIELD: {
213 SQOpcode op;
214 if(_token == TK_RETURN) {
215 op = _OP_RETURN;
216
217 }
218 else {
219 op = _OP_YIELD;
220 _fs->_bgenerator = true;
221 }
222 Lex();
223 if(!IsEndOfStatement()) {
224 SQInteger retexp = _fs->GetCurrentPos()+1;
225 CommaExpr();
226 if(op == _OP_RETURN && _fs->_traps > 0)
227 _fs->AddInstruction(_OP_POPTRAP, _fs->_traps, 0);
228 _fs->_returnexp = retexp;
229 _fs->AddInstruction(op, 1, _fs->PopTarget());
230 }
231 else{
232 if(op == _OP_RETURN && _fs->_traps > 0)
233 _fs->AddInstruction(_OP_POPTRAP, _fs->_traps ,0);
234 _fs->_returnexp = -1;
235 _fs->AddInstruction(op, 0xFF);
236 }
237 break;}
238 case TK_BREAK:
239 if(_fs->_breaktargets.size() <= 0)Error(_SC("'break' has to be in a loop block"));
240 if(_fs->_breaktargets.top() > 0){
241 _fs->AddInstruction(_OP_POPTRAP, _fs->_breaktargets.top(), 0);
242 }
243 _fs->AddInstruction(_OP_JMP, 0, -1234);
244 _fs->_unresolvedbreaks.push_back(_fs->GetCurrentPos());
245 Lex();
246 break;
247 case TK_CONTINUE:
248 if(_fs->_continuetargets.size() <= 0)Error(_SC("'continue' has to be in a loop block"));
249 if(_fs->_continuetargets.top() > 0) {
250 _fs->AddInstruction(_OP_POPTRAP, _fs->_continuetargets.top(), 0);
251 }
252 _fs->AddInstruction(_OP_JMP, 0, -1234);
253 _fs->_unresolvedcontinues.push_back(_fs->GetCurrentPos());
254 Lex();
255 break;
256 case TK_FUNCTION:
257 FunctionStatement();
258 break;
259 case TK_CLASS:
260 ClassStatement();
261 break;
262 case TK_ENUM:
263 EnumStatement();
264 break;
265 case _SC('{'):{
266 SQInteger stacksize = _fs->GetStackSize();
267 Lex();
268 Statements();
269 Expect(_SC('}'));
270 _fs->SetStackSize(stacksize);
271 }
272 break;
273 case TK_TRY:
274 TryCatchStatement();
275 break;
276 case TK_THROW:
277 Lex();
278 CommaExpr();
279 _fs->AddInstruction(_OP_THROW, _fs->PopTarget());
280 break;
281 case TK_CONST:
282 {
283 Lex();
284 SQObject id = Expect(TK_IDENTIFIER);
285 Expect('=');
286 SQObject val = ExpectScalar();
287 OptionalSemicolon();
288 SQTable *enums = _table(_ss(_vm)->_consts);
289 SQObjectPtr strongid = id;
290 enums->NewSlot(strongid,SQObjectPtr(val));
291 strongid.Null();
292 }
293 break;
294 default:
295 CommaExpr();
296 _fs->PopTarget();
297 break;
298 }
299 _fs->SnoozeOpt();
300 }
EmitDerefOp(SQOpcode op)301 void EmitDerefOp(SQOpcode op)
302 {
303 SQInteger val = _fs->PopTarget();
304 SQInteger key = _fs->PopTarget();
305 SQInteger src = _fs->PopTarget();
306 _fs->AddInstruction(op,_fs->PushTarget(),src,key,val);
307 }
Emit2ArgsOP(SQOpcode op,SQInteger p3=0)308 void Emit2ArgsOP(SQOpcode op, SQInteger p3 = 0)
309 {
310 SQInteger p2 = _fs->PopTarget(); //src in OP_GET
311 SQInteger p1 = _fs->PopTarget(); //key in OP_GET
312 _fs->AddInstruction(op,_fs->PushTarget(), p1, p2, p3);
313 }
EmitCompoundArith(SQInteger tok,bool deref)314 void EmitCompoundArith(SQInteger tok,bool deref)
315 {
316 SQInteger oper;
317 switch(tok){
318 case TK_MINUSEQ: oper = '-'; break;
319 case TK_PLUSEQ: oper = '+'; break;
320 case TK_MULEQ: oper = '*'; break;
321 case TK_DIVEQ: oper = '/'; break;
322 case TK_MODEQ: oper = '%'; break;
323 default: oper = 0; //shut up compiler
324 assert(0); break;
325 };
326 if(deref) {
327 SQInteger val = _fs->PopTarget();
328 SQInteger key = _fs->PopTarget();
329 SQInteger src = _fs->PopTarget();
330 //mixes dest obj and source val in the arg1(hack?)
331 _fs->AddInstruction(_OP_COMPARITH,_fs->PushTarget(),(src<<16)|val,key,oper);
332 }
333 else {
334 Emit2ArgsOP(_OP_COMPARITHL, oper);
335 }
336 }
CommaExpr()337 void CommaExpr()
338 {
339 for(Expression();_token == ',';_fs->PopTarget(), Lex(), CommaExpr());
340 }
Expression(bool funcarg=false)341 ExpState Expression(bool funcarg = false)
342 {
343 PushExpState();
344 _exst._class_or_delete = false;
345 _exst._funcarg = funcarg;
346 LogicalOrExp();
347 switch(_token) {
348 case _SC('='):
349 case TK_NEWSLOT:
350 case TK_MINUSEQ:
351 case TK_PLUSEQ:
352 case TK_MULEQ:
353 case TK_DIVEQ:
354 case TK_MODEQ:
355 {
356 SQInteger op = _token;
357 SQInteger ds = _exst._deref;
358 bool freevar = _exst._freevar;
359 if(ds == DEREF_NO_DEREF) Error(_SC("can't assign expression"));
360 Lex(); Expression();
361
362 switch(op){
363 case TK_NEWSLOT:
364 if(freevar) Error(_SC("free variables cannot be modified"));
365 if(ds == DEREF_FIELD)
366 EmitDerefOp(_OP_NEWSLOT);
367 else //if _derefstate != DEREF_NO_DEREF && DEREF_FIELD so is the index of a local
368 Error(_SC("can't 'create' a local slot"));
369 break;
370 case _SC('='): //ASSIGN
371 if(freevar) Error(_SC("free variables cannot be modified"));
372 if(ds == DEREF_FIELD)
373 EmitDerefOp(_OP_SET);
374 else {//if _derefstate != DEREF_NO_DEREF && DEREF_FIELD so is the index of a local
375 SQInteger p2 = _fs->PopTarget(); //src in OP_GET
376 SQInteger p1 = _fs->TopTarget(); //key in OP_GET
377 _fs->AddInstruction(_OP_MOVE, p1, p2);
378 }
379 break;
380 case TK_MINUSEQ:
381 case TK_PLUSEQ:
382 case TK_MULEQ:
383 case TK_DIVEQ:
384 case TK_MODEQ:
385 EmitCompoundArith(op,ds == DEREF_FIELD);
386 break;
387 }
388 }
389 break;
390 case _SC('?'): {
391 Lex();
392 _fs->AddInstruction(_OP_JZ, _fs->PopTarget());
393 SQInteger jzpos = _fs->GetCurrentPos();
394 SQInteger trg = _fs->PushTarget();
395 Expression();
396 SQInteger first_exp = _fs->PopTarget();
397 if(trg != first_exp) _fs->AddInstruction(_OP_MOVE, trg, first_exp);
398 SQInteger endfirstexp = _fs->GetCurrentPos();
399 _fs->AddInstruction(_OP_JMP, 0, 0);
400 Expect(_SC(':'));
401 SQInteger jmppos = _fs->GetCurrentPos();
402 Expression();
403 SQInteger second_exp = _fs->PopTarget();
404 if(trg != second_exp) _fs->AddInstruction(_OP_MOVE, trg, second_exp);
405 _fs->SetIntructionParam(jmppos, 1, _fs->GetCurrentPos() - jmppos);
406 _fs->SetIntructionParam(jzpos, 1, endfirstexp - jzpos + 1);
407 _fs->SnoozeOpt();
408 }
409 break;
410 }
411 return PopExpState();
412 }
BIN_EXP(SQOpcode op,void (SQCompiler::* f)(void),SQInteger op3=0)413 void BIN_EXP(SQOpcode op, void (SQCompiler::*f)(void),SQInteger op3 = 0)
414 {
415 Lex(); (this->*f)();
416 SQInteger op1 = _fs->PopTarget();SQInteger op2 = _fs->PopTarget();
417 _fs->AddInstruction(op, _fs->PushTarget(), op1, op2, op3);
418 }
LogicalOrExp()419 void LogicalOrExp()
420 {
421 LogicalAndExp();
422 for(;;) if(_token == TK_OR) {
423 SQInteger first_exp = _fs->PopTarget();
424 SQInteger trg = _fs->PushTarget();
425 _fs->AddInstruction(_OP_OR, trg, 0, first_exp, 0);
426 SQInteger jpos = _fs->GetCurrentPos();
427 if(trg != first_exp) _fs->AddInstruction(_OP_MOVE, trg, first_exp);
428 Lex(); LogicalOrExp();
429 _fs->SnoozeOpt();
430 SQInteger second_exp = _fs->PopTarget();
431 if(trg != second_exp) _fs->AddInstruction(_OP_MOVE, trg, second_exp);
432 _fs->SnoozeOpt();
433 _fs->SetIntructionParam(jpos, 1, (_fs->GetCurrentPos() - jpos));
434 break;
435 }else return;
436 }
LogicalAndExp()437 void LogicalAndExp()
438 {
439 BitwiseOrExp();
440 for(;;) switch(_token) {
441 case TK_AND: {
442 SQInteger first_exp = _fs->PopTarget();
443 SQInteger trg = _fs->PushTarget();
444 _fs->AddInstruction(_OP_AND, trg, 0, first_exp, 0);
445 SQInteger jpos = _fs->GetCurrentPos();
446 if(trg != first_exp) _fs->AddInstruction(_OP_MOVE, trg, first_exp);
447 Lex(); LogicalAndExp();
448 _fs->SnoozeOpt();
449 SQInteger second_exp = _fs->PopTarget();
450 if(trg != second_exp) _fs->AddInstruction(_OP_MOVE, trg, second_exp);
451 _fs->SnoozeOpt();
452 _fs->SetIntructionParam(jpos, 1, (_fs->GetCurrentPos() - jpos));
453 break;
454 }
455 case TK_IN: BIN_EXP(_OP_EXISTS, &SQCompiler::BitwiseOrExp); break;
456 case TK_INSTANCEOF: BIN_EXP(_OP_INSTANCEOF, &SQCompiler::BitwiseOrExp); break;
457 default:
458 return;
459 }
460 }
BitwiseOrExp()461 void BitwiseOrExp()
462 {
463 BitwiseXorExp();
464 for(;;) if(_token == _SC('|'))
465 {BIN_EXP(_OP_BITW, &SQCompiler::BitwiseXorExp,BW_OR);
466 }else return;
467 }
BitwiseXorExp()468 void BitwiseXorExp()
469 {
470 BitwiseAndExp();
471 for(;;) if(_token == _SC('^'))
472 {BIN_EXP(_OP_BITW, &SQCompiler::BitwiseAndExp,BW_XOR);
473 }else return;
474 }
BitwiseAndExp()475 void BitwiseAndExp()
476 {
477 CompExp();
478 for(;;) if(_token == _SC('&'))
479 {BIN_EXP(_OP_BITW, &SQCompiler::CompExp,BW_AND);
480 }else return;
481 }
CompExp()482 void CompExp()
483 {
484 ShiftExp();
485 for(;;) switch(_token) {
486 case TK_EQ: BIN_EXP(_OP_EQ, &SQCompiler::ShiftExp); break;
487 case _SC('>'): BIN_EXP(_OP_CMP, &SQCompiler::ShiftExp,CMP_G); break;
488 case _SC('<'): BIN_EXP(_OP_CMP, &SQCompiler::ShiftExp,CMP_L); break;
489 case TK_GE: BIN_EXP(_OP_CMP, &SQCompiler::ShiftExp,CMP_GE); break;
490 case TK_LE: BIN_EXP(_OP_CMP, &SQCompiler::ShiftExp,CMP_LE); break;
491 case TK_NE: BIN_EXP(_OP_NE, &SQCompiler::ShiftExp); break;
492 default: return;
493 }
494 }
ShiftExp()495 void ShiftExp()
496 {
497 PlusExp();
498 for(;;) switch(_token) {
499 case TK_USHIFTR: BIN_EXP(_OP_BITW, &SQCompiler::PlusExp,BW_USHIFTR); break;
500 case TK_SHIFTL: BIN_EXP(_OP_BITW, &SQCompiler::PlusExp,BW_SHIFTL); break;
501 case TK_SHIFTR: BIN_EXP(_OP_BITW, &SQCompiler::PlusExp,BW_SHIFTR); break;
502 default: return;
503 }
504 }
PlusExp()505 void PlusExp()
506 {
507 MultExp();
508 for(;;) switch(_token) {
509 case _SC('+'): case _SC('-'):
510 BIN_EXP(_OP_ARITH, &SQCompiler::MultExp,_token); break;
511 default: return;
512 }
513 }
514
MultExp()515 void MultExp()
516 {
517 PrefixedExpr();
518 for(;;) switch(_token) {
519 case _SC('*'): case _SC('/'): case _SC('%'):
520 BIN_EXP(_OP_ARITH, &SQCompiler::PrefixedExpr,_token); break;
521 default: return;
522 }
523 }
524 //if 'pos' != -1 the previous variable is a local variable
PrefixedExpr()525 void PrefixedExpr()
526 {
527 SQInteger pos = Factor();
528 for(;;) {
529 switch(_token) {
530 case _SC('.'): {
531 pos = -1;
532 Lex();
533 if(_token == TK_PARENT) {
534 Lex();
535 if(!NeedGet())
536 Error(_SC("parent cannot be set"));
537 SQInteger src = _fs->PopTarget();
538 _fs->AddInstruction(_OP_GETPARENT, _fs->PushTarget(), src);
539 }
540 else {
541 _fs->AddInstruction(_OP_LOAD, _fs->PushTarget(), _fs->GetConstant(Expect(TK_IDENTIFIER)));
542 if(NeedGet()) Emit2ArgsOP(_OP_GET);
543 }
544 _exst._deref = DEREF_FIELD;
545 _exst._freevar = false;
546 }
547 break;
548 case _SC('['):
549 if(_lex._prevtoken == _SC('\n')) Error(_SC("cannot brake deref/or comma needed after [exp]=exp slot declaration"));
550 Lex(); Expression(); Expect(_SC(']'));
551 pos = -1;
552 if(NeedGet()) Emit2ArgsOP(_OP_GET);
553 _exst._deref = DEREF_FIELD;
554 _exst._freevar = false;
555 break;
556 case TK_MINUSMINUS:
557 case TK_PLUSPLUS:
558 if(_exst._deref != DEREF_NO_DEREF && !IsEndOfStatement()) {
559 SQInteger tok = _token; Lex();
560 if(pos < 0)
561 Emit2ArgsOP(_OP_PINC,tok == TK_MINUSMINUS?-1:1);
562 else {//if _derefstate != DEREF_NO_DEREF && DEREF_FIELD so is the index of a local
563 SQInteger src = _fs->PopTarget();
564 _fs->AddInstruction(_OP_PINCL, _fs->PushTarget(), src, 0, tok == TK_MINUSMINUS?-1:1);
565 }
566
567 }
568 return;
569 break;
570 case _SC('('):
571 {
572 if(_exst._deref != DEREF_NO_DEREF) {
573 if(pos<0) {
574 SQInteger key = _fs->PopTarget(); //key
575 SQInteger table = _fs->PopTarget(); //table etc...
576 SQInteger closure = _fs->PushTarget();
577 SQInteger ttarget = _fs->PushTarget();
578 _fs->AddInstruction(_OP_PREPCALL, closure, key, table, ttarget);
579 }
580 else{
581 _fs->AddInstruction(_OP_MOVE, _fs->PushTarget(), 0);
582 }
583 }
584 else
585 _fs->AddInstruction(_OP_MOVE, _fs->PushTarget(), 0);
586 _exst._deref = DEREF_NO_DEREF;
587 Lex();
588 FunctionCallArgs();
589 }
590 break;
591 default: return;
592 }
593 }
594 }
Factor()595 SQInteger Factor()
596 {
597 _exst._deref = DEREF_NO_DEREF;
598 switch(_token)
599 {
600 case TK_STRING_LITERAL: {
601 //SQObjectPtr id(SQString::Create(_ss(_vm), _lex._svalue,_lex._longstr.size()-1));
602 _fs->AddInstruction(_OP_LOAD, _fs->PushTarget(), _fs->GetConstant(_fs->CreateString(_lex._svalue,_lex._longstr.size()-1)));
603 Lex();
604 }
605 break;
606 case TK_VARGC: Lex(); _fs->AddInstruction(_OP_VARGC, _fs->PushTarget()); break;
607 case TK_VARGV: { Lex();
608 Expect(_SC('['));
609 Expression();
610 Expect(_SC(']'));
611 SQInteger src = _fs->PopTarget();
612 _fs->AddInstruction(_OP_GETVARGV, _fs->PushTarget(), src);
613 }
614 break;
615 case TK_IDENTIFIER:
616 case TK_CONSTRUCTOR:
617 case TK_THIS:{
618 _exst._freevar = false;
619 SQObject id;
620 SQObject constant;
621 switch(_token) {
622 case TK_IDENTIFIER: id = _fs->CreateString(_lex._svalue); break;
623 case TK_THIS: id = _fs->CreateString(_SC("this")); break;
624 case TK_CONSTRUCTOR: id = _fs->CreateString(_SC("constructor")); break;
625 }
626 SQInteger pos = -1;
627 Lex();
628 if((pos = _fs->GetLocalVariable(id)) == -1) {
629 //checks if is a free variable
630 if((pos = _fs->GetOuterVariable(id)) != -1) {
631 _exst._deref = _fs->PushTarget();
632 _fs->AddInstruction(_OP_LOADFREEVAR, _exst._deref ,pos);
633 _exst._freevar = true;
634 }
635 else if(_fs->IsConstant(id,constant)) { //line 634
636 SQObjectPtr constval;
637 SQObject constid;
638 if(type(constant) == OT_TABLE) {
639 Expect('.'); constid = Expect(TK_IDENTIFIER);
640 if(!_table(constant)->Get(constid,constval)) {
641 constval.Null();
642 Error(_SC("invalid constant [%s.%s]"), _stringval(id),_stringval(constid));
643 }
644 }
645 else {
646 constval = constant;
647 }
648 _exst._deref = _fs->PushTarget();
649 SQObjectType ctype = type(constval);
650 if(ctype == OT_INTEGER && (_integer(constval) & (~0x7FFFFFFF)) == 0) {
651 _fs->AddInstruction(_OP_LOADINT, _exst._deref,_integer(constval));
652 }
653 else if(ctype == OT_FLOAT && sizeof(SQFloat) == sizeof(SQInt32)) {
654 SQFloat f = _float(constval);
655 _fs->AddInstruction(_OP_LOADFLOAT, _exst._deref,*((SQInt32 *)&f));
656 }
657 else {
658 _fs->AddInstruction(_OP_LOAD, _exst._deref, _fs->GetConstant(constval));
659 }
660
661 _exst._freevar = true;
662 }
663 else {
664 _fs->PushTarget(0);
665 _fs->AddInstruction(_OP_LOAD, _fs->PushTarget(), _fs->GetConstant(id));
666 if(NeedGet()) Emit2ArgsOP(_OP_GET);
667 _exst._deref = DEREF_FIELD;
668 }
669 }
670
671 else{
672 _fs->PushTarget(pos);
673 _exst._deref = pos;
674 }
675 return _exst._deref;
676 }
677 break;
678 case TK_PARENT: Lex();_fs->AddInstruction(_OP_GETPARENT, _fs->PushTarget(), 0); break;
679 case TK_DOUBLE_COLON: // "::"
680 _fs->AddInstruction(_OP_LOADROOTTABLE, _fs->PushTarget());
681 _exst._deref = DEREF_FIELD;
682 _token = _SC('.'); //hack
683 return -1;
684 break;
685 case TK_NULL:
686 _fs->AddInstruction(_OP_LOADNULLS, _fs->PushTarget(),1);
687 Lex();
688 break;
689 case TK_INTEGER: {
690 if((_lex._nvalue & (~0x7FFFFFFF)) == 0) { //does it fit in 32 bits?
691 _fs->AddInstruction(_OP_LOADINT, _fs->PushTarget(),_lex._nvalue);
692 }
693 else {
694 _fs->AddInstruction(_OP_LOAD, _fs->PushTarget(), _fs->GetNumericConstant(_lex._nvalue));
695 }
696 Lex();
697 }
698 break;
699 case TK_FLOAT:
700 if(sizeof(SQFloat) == sizeof(SQInt32)) {
701 _fs->AddInstruction(_OP_LOADFLOAT, _fs->PushTarget(),*((SQInt32 *)&_lex._fvalue));
702 }
703 else {
704 _fs->AddInstruction(_OP_LOAD, _fs->PushTarget(), _fs->GetNumericConstant(_lex._fvalue));
705 }
706 Lex();
707 break;
708 case TK_TRUE: case TK_FALSE:
709 _fs->AddInstruction(_OP_LOADBOOL, _fs->PushTarget(),_token == TK_TRUE?1:0);
710 Lex();
711 break;
712 case _SC('['): {
713 _fs->AddInstruction(_OP_NEWARRAY, _fs->PushTarget());
714 SQInteger apos = _fs->GetCurrentPos(),key = 0;
715 Lex();
716 while(_token != _SC(']')) {
717 Expression();
718 if(_token == _SC(',')) Lex();
719 SQInteger val = _fs->PopTarget();
720 SQInteger array = _fs->TopTarget();
721 _fs->AddInstruction(_OP_APPENDARRAY, array, val);
722 key++;
723 }
724 _fs->SetIntructionParam(apos, 1, key);
725 Lex();
726 }
727 break;
728 case _SC('{'):{
729 _fs->AddInstruction(_OP_NEWTABLE, _fs->PushTarget());
730 Lex();ParseTableOrClass(_SC(','));
731 }
732 break;
733 case TK_FUNCTION: FunctionExp(_token);break;
734 case TK_CLASS: Lex(); ClassExp();break;
735 case _SC('-'): UnaryOP(_OP_NEG); break;
736 case _SC('!'): UnaryOP(_OP_NOT); break;
737 case _SC('~'): UnaryOP(_OP_BWNOT); break;
738 case TK_TYPEOF : UnaryOP(_OP_TYPEOF); break;
739 case TK_RESUME : UnaryOP(_OP_RESUME); break;
740 case TK_CLONE : UnaryOP(_OP_CLONE); break;
741 case TK_MINUSMINUS :
742 case TK_PLUSPLUS :PrefixIncDec(_token); break;
743 case TK_DELETE : DeleteExpr(); break;
744 case TK_DELEGATE : DelegateExpr(); break;
745 case _SC('('): Lex(); CommaExpr(); Expect(_SC(')'));
746 break;
747 default: Error(_SC("expression expected"));
748 }
749 return -1;
750 }
UnaryOP(SQOpcode op)751 void UnaryOP(SQOpcode op)
752 {
753 Lex(); PrefixedExpr();
754 SQInteger src = _fs->PopTarget();
755 _fs->AddInstruction(op, _fs->PushTarget(), src);
756 }
NeedGet()757 bool NeedGet()
758 {
759 switch(_token) {
760 case _SC('='): case _SC('('): case TK_NEWSLOT: case TK_PLUSPLUS: case TK_MINUSMINUS:
761 case TK_PLUSEQ: case TK_MINUSEQ: case TK_MULEQ: case TK_DIVEQ: case TK_MODEQ:
762 return false;
763 }
764 return (!_exst._class_or_delete) || (_exst._class_or_delete && (_token == _SC('.') || _token == _SC('[')));
765 }
766
FunctionCallArgs()767 void FunctionCallArgs()
768 {
769 SQInteger nargs = 1;//this
770 while(_token != _SC(')')) {
771 Expression(true);
772 MoveIfCurrentTargetIsLocal();
773 nargs++;
774 if(_token == _SC(',')){
775 Lex();
776 if(_token == ')') Error(_SC("expression expected, found ')'"));
777 }
778 }
779 Lex();
780 for(SQInteger i = 0; i < (nargs - 1); i++) _fs->PopTarget();
781 SQInteger stackbase = _fs->PopTarget();
782 SQInteger closure = _fs->PopTarget();
783 _fs->AddInstruction(_OP_CALL, _fs->PushTarget(), closure, stackbase, nargs);
784 }
ParseTableOrClass(SQInteger separator,SQInteger terminator='}')785 void ParseTableOrClass(SQInteger separator,SQInteger terminator = '}')
786 {
787 SQInteger tpos = _fs->GetCurrentPos(),nkeys = 0;
788
789 while(_token != terminator) {
790 bool hasattrs = false;
791 bool isstatic = false;
792 //check if is an attribute
793 if(separator == ';') {
794 if(_token == TK_ATTR_OPEN) {
795 _fs->AddInstruction(_OP_NEWTABLE, _fs->PushTarget()); Lex();
796 ParseTableOrClass(',',TK_ATTR_CLOSE);
797 hasattrs = true;
798 }
799 if(_token == TK_STATIC) {
800 isstatic = true;
801 Lex();
802 }
803 }
804 switch(_token) {
805 case TK_FUNCTION:
806 case TK_CONSTRUCTOR:{
807 SQInteger tk = _token;
808 Lex();
809 SQObject id = tk == TK_FUNCTION ? Expect(TK_IDENTIFIER) : _fs->CreateString(_SC("constructor"));
810 Expect(_SC('('));
811 _fs->AddInstruction(_OP_LOAD, _fs->PushTarget(), _fs->GetConstant(id));
812 CreateFunction(id);
813 _fs->AddInstruction(_OP_CLOSURE, _fs->PushTarget(), _fs->_functions.size() - 1, 0);
814 }
815 break;
816 case _SC('['):
817 Lex(); CommaExpr(); Expect(_SC(']'));
818 Expect(_SC('=')); Expression();
819 break;
820 default :
821 _fs->AddInstruction(_OP_LOAD, _fs->PushTarget(), _fs->GetConstant(Expect(TK_IDENTIFIER)));
822 Expect(_SC('=')); Expression();
823 }
824
825 if(_token == separator) Lex();//optional comma/semicolon
826 nkeys++;
827 SQInteger val = _fs->PopTarget();
828 SQInteger key = _fs->PopTarget();
829 SQInteger attrs = hasattrs ? _fs->PopTarget():-1;
830 // C::B patch: Eliminate compiler warnings
831 assert((hasattrs && (attrs == key-1)) || !hasattrs);
832 // C::B patch: Eliminate compiler warnings
833 int flags = (hasattrs?NEW_SLOT_ATTRIBUTES_FLAG:0)|(isstatic?NEW_SLOT_STATIC_FLAG:0);
834 SQInteger table = _fs->TopTarget(); //<<BECAUSE OF THIS NO COMMON EMIT FUNC IS POSSIBLE
835 _fs->AddInstruction(_OP_NEWSLOTA, flags, table, key, val);
836 //_fs->PopTarget();
837 }
838 if(separator == _SC(',')) //hack recognizes a table from the separator
839 _fs->SetIntructionParam(tpos, 1, nkeys);
840 Lex();
841 }
LocalDeclStatement()842 void LocalDeclStatement()
843 {
844 SQObject varname;
845 do {
846 Lex(); varname = Expect(TK_IDENTIFIER);
847 if(_token == _SC('=')) {
848 Lex(); Expression();
849 SQInteger src = _fs->PopTarget();
850 SQInteger dest = _fs->PushTarget();
851 if(dest != src) _fs->AddInstruction(_OP_MOVE, dest, src);
852 }
853 else{
854 _fs->AddInstruction(_OP_LOADNULLS, _fs->PushTarget(),1);
855 }
856 _fs->PopTarget();
857 _fs->PushLocalVariable(varname);
858
859 } while(_token == _SC(','));
860 }
IfStatement()861 void IfStatement()
862 {
863 SQInteger jmppos;
864 bool haselse = false;
865 Lex(); Expect(_SC('(')); CommaExpr(); Expect(_SC(')'));
866 _fs->AddInstruction(_OP_JZ, _fs->PopTarget());
867 SQInteger jnepos = _fs->GetCurrentPos();
868 SQInteger stacksize = _fs->GetStackSize();
869
870 Statement();
871 //
872 if(_token != _SC('}') && _token != TK_ELSE) OptionalSemicolon();
873
874 CleanStack(stacksize);
875 SQInteger endifblock = _fs->GetCurrentPos();
876 if(_token == TK_ELSE){
877 haselse = true;
878 stacksize = _fs->GetStackSize();
879 _fs->AddInstruction(_OP_JMP);
880 jmppos = _fs->GetCurrentPos();
881 Lex();
882 Statement(); OptionalSemicolon();
883 CleanStack(stacksize);
884 _fs->SetIntructionParam(jmppos, 1, _fs->GetCurrentPos() - jmppos);
885 }
886 _fs->SetIntructionParam(jnepos, 1, endifblock - jnepos + (haselse?1:0));
887 }
WhileStatement()888 void WhileStatement()
889 {
890 SQInteger jzpos, jmppos;
891 SQInteger stacksize = _fs->GetStackSize();
892 jmppos = _fs->GetCurrentPos();
893 Lex(); Expect(_SC('(')); CommaExpr(); Expect(_SC(')'));
894
895 BEGIN_BREAKBLE_BLOCK();
896 _fs->AddInstruction(_OP_JZ, _fs->PopTarget());
897 jzpos = _fs->GetCurrentPos();
898 stacksize = _fs->GetStackSize();
899
900 Statement();
901
902 CleanStack(stacksize);
903 _fs->AddInstruction(_OP_JMP, 0, jmppos - _fs->GetCurrentPos() - 1);
904 _fs->SetIntructionParam(jzpos, 1, _fs->GetCurrentPos() - jzpos);
905
906 END_BREAKBLE_BLOCK(jmppos);
907 }
DoWhileStatement()908 void DoWhileStatement()
909 {
910 Lex();
911 SQInteger jzpos = _fs->GetCurrentPos();
912 SQInteger stacksize = _fs->GetStackSize();
913 BEGIN_BREAKBLE_BLOCK()
914 Statement();
915 CleanStack(stacksize);
916 Expect(TK_WHILE);
917 SQInteger continuetrg = _fs->GetCurrentPos();
918 Expect(_SC('(')); CommaExpr(); Expect(_SC(')'));
919 _fs->AddInstruction(_OP_JNZ, _fs->PopTarget(), jzpos - _fs->GetCurrentPos() - 1);
920 END_BREAKBLE_BLOCK(continuetrg);
921 }
ForStatement()922 void ForStatement()
923 {
924 Lex();
925 SQInteger stacksize = _fs->GetStackSize();
926 Expect(_SC('('));
927 if(_token == TK_LOCAL) LocalDeclStatement();
928 else if(_token != _SC(';')){
929 CommaExpr();
930 _fs->PopTarget();
931 }
932 Expect(_SC(';'));
933 _fs->SnoozeOpt();
934 SQInteger jmppos = _fs->GetCurrentPos();
935 SQInteger jzpos = -1;
936 if(_token != _SC(';')) { CommaExpr(); _fs->AddInstruction(_OP_JZ, _fs->PopTarget()); jzpos = _fs->GetCurrentPos(); }
937 Expect(_SC(';'));
938 _fs->SnoozeOpt();
939 SQInteger expstart = _fs->GetCurrentPos() + 1;
940 if(_token != _SC(')')) {
941 CommaExpr();
942 _fs->PopTarget();
943 }
944 Expect(_SC(')'));
945 _fs->SnoozeOpt();
946 SQInteger expend = _fs->GetCurrentPos();
947 SQInteger expsize = (expend - expstart) + 1;
948 SQInstructionVec exp;
949 if(expsize > 0) {
950 for(SQInteger i = 0; i < expsize; i++)
951 exp.push_back(_fs->GetInstruction(expstart + i));
952 _fs->PopInstructions(expsize);
953 }
954 BEGIN_BREAKBLE_BLOCK()
955 Statement();
956 SQInteger continuetrg = _fs->GetCurrentPos();
957 if(expsize > 0) {
958 for(SQInteger i = 0; i < expsize; i++)
959 _fs->AddInstruction(exp[i]);
960 }
961 _fs->AddInstruction(_OP_JMP, 0, jmppos - _fs->GetCurrentPos() - 1, 0);
962 if(jzpos> 0) _fs->SetIntructionParam(jzpos, 1, _fs->GetCurrentPos() - jzpos);
963 CleanStack(stacksize);
964
965 END_BREAKBLE_BLOCK(continuetrg);
966 }
ForEachStatement()967 void ForEachStatement()
968 {
969 SQObject idxname, valname;
970 Lex(); Expect(_SC('(')); valname = Expect(TK_IDENTIFIER);
971 if(_token == _SC(',')) {
972 idxname = valname;
973 Lex(); valname = Expect(TK_IDENTIFIER);
974 }
975 else{
976 idxname = _fs->CreateString(_SC("@INDEX@"));
977 }
978 Expect(TK_IN);
979
980 //save the stack size
981 SQInteger stacksize = _fs->GetStackSize();
982 //put the table in the stack(evaluate the table expression)
983 Expression(); Expect(_SC(')'));
984 SQInteger container = _fs->TopTarget();
985 //push the index local var
986 SQInteger indexpos = _fs->PushLocalVariable(idxname);
987 _fs->AddInstruction(_OP_LOADNULLS, indexpos,1);
988 //push the value local var
989 SQInteger valuepos = _fs->PushLocalVariable(valname);
990 _fs->AddInstruction(_OP_LOADNULLS, valuepos,1);
991 //push reference index
992 SQInteger itrpos = _fs->PushLocalVariable(_fs->CreateString(_SC("@ITERATOR@"))); //use invalid id to make it inaccessible
993 _fs->AddInstruction(_OP_LOADNULLS, itrpos,1);
994 SQInteger jmppos = _fs->GetCurrentPos();
995 _fs->AddInstruction(_OP_FOREACH, container, 0, indexpos);
996 SQInteger foreachpos = _fs->GetCurrentPos();
997 _fs->AddInstruction(_OP_POSTFOREACH, container, 0, indexpos);
998 //generate the statement code
999 BEGIN_BREAKBLE_BLOCK()
1000 Statement();
1001 _fs->AddInstruction(_OP_JMP, 0, jmppos - _fs->GetCurrentPos() - 1);
1002 _fs->SetIntructionParam(foreachpos, 1, _fs->GetCurrentPos() - foreachpos);
1003 _fs->SetIntructionParam(foreachpos + 1, 1, _fs->GetCurrentPos() - foreachpos);
1004 //restore the local variable stack(remove index,val and ref idx)
1005 CleanStack(stacksize);
1006 END_BREAKBLE_BLOCK(foreachpos - 1);
1007 }
SwitchStatement()1008 void SwitchStatement()
1009 {
1010 Lex(); Expect(_SC('(')); CommaExpr(); Expect(_SC(')'));
1011 Expect(_SC('{'));
1012 SQInteger expr = _fs->TopTarget();
1013 bool bfirst = true;
1014 SQInteger tonextcondjmp = -1;
1015 SQInteger skipcondjmp = -1;
1016 SQInteger __nbreaks__ = _fs->_unresolvedbreaks.size();
1017 _fs->_breaktargets.push_back(0);
1018 while(_token == TK_CASE) {
1019 //_fs->AddLineInfos(_lex._currentline, _lineinfo); think about this one
1020 if(!bfirst) {
1021 _fs->AddInstruction(_OP_JMP, 0, 0);
1022 skipcondjmp = _fs->GetCurrentPos();
1023 _fs->SetIntructionParam(tonextcondjmp, 1, _fs->GetCurrentPos() - tonextcondjmp);
1024 }
1025 //condition
1026 Lex(); Expression(); Expect(_SC(':'));
1027 SQInteger trg = _fs->PopTarget();
1028 _fs->AddInstruction(_OP_EQ, trg, trg, expr);
1029 _fs->AddInstruction(_OP_JZ, trg, 0);
1030 //end condition
1031 if(skipcondjmp != -1) {
1032 _fs->SetIntructionParam(skipcondjmp, 1, (_fs->GetCurrentPos() - skipcondjmp));
1033 }
1034 tonextcondjmp = _fs->GetCurrentPos();
1035 SQInteger stacksize = _fs->GetStackSize();
1036 Statements();
1037 _fs->SetStackSize(stacksize);
1038 bfirst = false;
1039 }
1040 if(tonextcondjmp != -1)
1041 _fs->SetIntructionParam(tonextcondjmp, 1, _fs->GetCurrentPos() - tonextcondjmp);
1042 if(_token == TK_DEFAULT) {
1043 // _fs->AddLineInfos(_lex._currentline, _lineinfo);
1044 Lex(); Expect(_SC(':'));
1045 SQInteger stacksize = _fs->GetStackSize();
1046 Statements();
1047 _fs->SetStackSize(stacksize);
1048 }
1049 Expect(_SC('}'));
1050 _fs->PopTarget();
1051 __nbreaks__ = _fs->_unresolvedbreaks.size() - __nbreaks__;
1052 if(__nbreaks__ > 0)ResolveBreaks(_fs, __nbreaks__);
1053 _fs->_breaktargets.pop_back();
1054
1055 }
FunctionStatement()1056 void FunctionStatement()
1057 {
1058 SQObject id;
1059 Lex(); id = Expect(TK_IDENTIFIER);
1060 _fs->PushTarget(0);
1061 _fs->AddInstruction(_OP_LOAD, _fs->PushTarget(), _fs->GetConstant(id));
1062 if(_token == TK_DOUBLE_COLON) Emit2ArgsOP(_OP_GET);
1063
1064 while(_token == TK_DOUBLE_COLON) {
1065 Lex();
1066 id = Expect(TK_IDENTIFIER);
1067 _fs->AddInstruction(_OP_LOAD, _fs->PushTarget(), _fs->GetConstant(id));
1068 if(_token == TK_DOUBLE_COLON) Emit2ArgsOP(_OP_GET);
1069 }
1070 Expect(_SC('('));
1071 CreateFunction(id);
1072 _fs->AddInstruction(_OP_CLOSURE, _fs->PushTarget(), _fs->_functions.size() - 1, 0);
1073 EmitDerefOp(_OP_NEWSLOT);
1074 _fs->PopTarget();
1075 }
ClassStatement()1076 void ClassStatement()
1077 {
1078 ExpState es;
1079 Lex(); PushExpState();
1080 _exst._class_or_delete = true;
1081 _exst._funcarg = false;
1082 PrefixedExpr();
1083 es = PopExpState();
1084 if(es._deref == DEREF_NO_DEREF) Error(_SC("invalid class name"));
1085 if(es._deref == DEREF_FIELD) {
1086 ClassExp();
1087 EmitDerefOp(_OP_NEWSLOT);
1088 _fs->PopTarget();
1089 }
1090 else Error(_SC("cannot create a class in a local with the syntax(class <local>)"));
1091 }
ExpectScalar()1092 SQObject ExpectScalar()
1093 {
1094 SQObject val;
1095 switch(_token) {
1096 case TK_INTEGER:
1097 val._type = OT_INTEGER;
1098 val._unVal.nInteger = _lex._nvalue;
1099 break;
1100 case TK_FLOAT:
1101 val._type = OT_FLOAT;
1102 val._unVal.fFloat = _lex._fvalue;
1103 break;
1104 case TK_STRING_LITERAL:
1105 val = _fs->CreateString(_lex._svalue,_lex._longstr.size()-1);
1106 break;
1107 case '-':
1108 Lex();
1109 switch(_token)
1110 {
1111 case TK_INTEGER:
1112 val._type = OT_INTEGER;
1113 val._unVal.nInteger = -_lex._nvalue;
1114 break;
1115 case TK_FLOAT:
1116 val._type = OT_FLOAT;
1117 val._unVal.fFloat = -_lex._fvalue;
1118 break;
1119 default:
1120 Error(_SC("scalar expected : integer,float"));
1121 }
1122 break;
1123 default:
1124 Error(_SC("scalar expected : integer,float or string"));
1125 }
1126 Lex();
1127 return val;
1128 }
EnumStatement()1129 void EnumStatement()
1130 {
1131
1132 Lex();
1133 SQObject id = Expect(TK_IDENTIFIER);
1134 Expect(_SC('{'));
1135
1136 SQObject table = _fs->CreateTable();
1137 SQInteger nval = 0;
1138 while(_token != _SC('}')) {
1139 SQObject key = Expect(TK_IDENTIFIER);
1140 SQObject val;
1141 if(_token == _SC('=')) {
1142 Lex();
1143 val = ExpectScalar();
1144 }
1145 else {
1146 val._type = OT_INTEGER;
1147 val._unVal.nInteger = nval++;
1148 }
1149 _table(table)->NewSlot(SQObjectPtr(key),SQObjectPtr(val));
1150 if(_token == ',') Lex();
1151 }
1152 SQTable *enums = _table(_ss(_vm)->_consts);
1153 SQObjectPtr strongid = id;
1154 /*SQObjectPtr dummy;
1155 if(enums->Get(strongid,dummy)) {
1156 dummy.Null(); strongid.Null();
1157 Error(_SC("enumeration already exists"));
1158 }*/
1159 enums->NewSlot(SQObjectPtr(strongid),SQObjectPtr(table));
1160 strongid.Null();
1161 Lex();
1162
1163 }
TryCatchStatement()1164 void TryCatchStatement()
1165 {
1166 SQObject exid;
1167 Lex();
1168 _fs->AddInstruction(_OP_PUSHTRAP,0,0);
1169 _fs->_traps++;
1170 if(_fs->_breaktargets.size()) _fs->_breaktargets.top()++;
1171 if(_fs->_continuetargets.size()) _fs->_continuetargets.top()++;
1172 SQInteger trappos = _fs->GetCurrentPos();
1173 Statement();
1174 _fs->_traps--;
1175 _fs->AddInstruction(_OP_POPTRAP, 1, 0);
1176 if(_fs->_breaktargets.size()) _fs->_breaktargets.top()--;
1177 if(_fs->_continuetargets.size()) _fs->_continuetargets.top()--;
1178 _fs->AddInstruction(_OP_JMP, 0, 0);
1179 SQInteger jmppos = _fs->GetCurrentPos();
1180 _fs->SetIntructionParam(trappos, 1, (_fs->GetCurrentPos() - trappos));
1181 Expect(TK_CATCH); Expect(_SC('(')); exid = Expect(TK_IDENTIFIER); Expect(_SC(')'));
1182 SQInteger stacksize = _fs->GetStackSize();
1183 SQInteger ex_target = _fs->PushLocalVariable(exid);
1184 _fs->SetIntructionParam(trappos, 0, ex_target);
1185 Statement();
1186 _fs->SetIntructionParams(jmppos, 0, (_fs->GetCurrentPos() - jmppos), 0);
1187 CleanStack(stacksize);
1188 }
FunctionExp(SQInteger ftype)1189 void FunctionExp(SQInteger ftype)
1190 {
1191 Lex(); Expect(_SC('('));
1192 CreateFunction(_null_);
1193 _fs->AddInstruction(_OP_CLOSURE, _fs->PushTarget(), _fs->_functions.size() - 1, ftype == TK_FUNCTION?0:1);
1194 }
ClassExp()1195 void ClassExp()
1196 {
1197 SQInteger base = -1;
1198 SQInteger attrs = -1;
1199 if(_token == TK_EXTENDS) {
1200 Lex(); Expression();
1201 base = _fs->TopTarget();
1202 }
1203 if(_token == TK_ATTR_OPEN) {
1204 Lex();
1205 _fs->AddInstruction(_OP_NEWTABLE, _fs->PushTarget());
1206 ParseTableOrClass(_SC(','),TK_ATTR_CLOSE);
1207 attrs = _fs->TopTarget();
1208 }
1209 Expect(_SC('{'));
1210 if(attrs != -1) _fs->PopTarget();
1211 if(base != -1) _fs->PopTarget();
1212 _fs->AddInstruction(_OP_CLASS, _fs->PushTarget(), base, attrs);
1213 ParseTableOrClass(_SC(';'));
1214 }
DelegateExpr()1215 void DelegateExpr()
1216 {
1217 Lex(); CommaExpr();
1218 Expect(_SC(':'));
1219 CommaExpr();
1220 SQInteger table = _fs->PopTarget(), delegate = _fs->PopTarget();
1221 _fs->AddInstruction(_OP_DELEGATE, _fs->PushTarget(), table, delegate);
1222 }
DeleteExpr()1223 void DeleteExpr()
1224 {
1225 ExpState es;
1226 Lex(); PushExpState();
1227 _exst._class_or_delete = true;
1228 _exst._funcarg = false;
1229 PrefixedExpr();
1230 es = PopExpState();
1231 if(es._deref == DEREF_NO_DEREF) Error(_SC("can't delete an expression"));
1232 if(es._deref == DEREF_FIELD) Emit2ArgsOP(_OP_DELETE);
1233 else Error(_SC("cannot delete a local"));
1234 }
PrefixIncDec(SQInteger token)1235 void PrefixIncDec(SQInteger token)
1236 {
1237 ExpState es;
1238 Lex(); PushExpState();
1239 _exst._class_or_delete = true;
1240 _exst._funcarg = false;
1241 PrefixedExpr();
1242 es = PopExpState();
1243 if(es._deref == DEREF_FIELD) Emit2ArgsOP(_OP_INC,token == TK_MINUSMINUS?-1:1);
1244 else {
1245 SQInteger src = _fs->PopTarget();
1246 _fs->AddInstruction(_OP_INCL, _fs->PushTarget(), src, 0, token == TK_MINUSMINUS?-1:1);
1247 }
1248 }
CreateFunction(SQObject & name)1249 void CreateFunction(SQObject &name)
1250 {
1251
1252 SQFuncState *funcstate = _fs->PushChildState(_ss(_vm));
1253 funcstate->_name = name;
1254 SQObject paramname;
1255 funcstate->AddParameter(_fs->CreateString(_SC("this")));
1256 funcstate->_sourcename = _sourcename;
1257 SQInteger defparams = 0;
1258 while(_token!=_SC(')')) {
1259 if(_token == TK_VARPARAMS) {
1260 if(defparams > 0) Error(_SC("function with default parameters cannot have variable number of parameters"));
1261 funcstate->_varparams = true;
1262 Lex();
1263 if(_token != _SC(')')) Error(_SC("expected ')'"));
1264 break;
1265 }
1266 else {
1267 paramname = Expect(TK_IDENTIFIER);
1268 funcstate->AddParameter(paramname);
1269 if(_token == _SC('=')) {
1270 Lex();
1271 Expression();
1272 funcstate->AddDefaultParam(_fs->TopTarget());
1273 defparams++;
1274 }
1275 else {
1276 if(defparams > 0) Error(_SC("expected '='"));
1277 }
1278 if(_token == _SC(',')) Lex();
1279 else if(_token != _SC(')')) Error(_SC("expected ')' or ','"));
1280 }
1281 }
1282 Expect(_SC(')'));
1283 for(SQInteger n = 0; n < defparams; n++) {
1284 _fs->PopTarget();
1285 }
1286 //outer values
1287 if(_token == _SC(':')) {
1288 Lex(); Expect(_SC('('));
1289 while(_token != _SC(')')) {
1290 paramname = Expect(TK_IDENTIFIER);
1291 //outers are treated as implicit local variables
1292 funcstate->AddOuterValue(paramname);
1293 if(_token == _SC(',')) Lex();
1294 else if(_token != _SC(')')) Error(_SC("expected ')' or ','"));
1295 }
1296 Lex();
1297 }
1298
1299 SQFuncState *currchunk = _fs;
1300 _fs = funcstate;
1301 Statement();
1302 funcstate->AddLineInfos(_lex._prevtoken == _SC('\n')?_lex._lasttokenline:_lex._currentline, _lineinfo, true);
1303 funcstate->AddInstruction(_OP_RETURN, -1);
1304 funcstate->SetStackSize(0);
1305 //_fs->->_stacksize = _fs->_stacksize;
1306 SQFunctionProto *func = funcstate->BuildProto();
1307 #ifdef _DEBUG_DUMP
1308 funcstate->Dump(func);
1309 #endif
1310 _fs = currchunk;
1311 _fs->_functions.push_back(func);
1312 _fs->PopChildState();
1313 }
CleanStack(SQInteger stacksize)1314 void CleanStack(SQInteger stacksize)
1315 {
1316 if(_fs->GetStackSize() != stacksize)
1317 _fs->SetStackSize(stacksize);
1318 }
ResolveBreaks(SQFuncState * funcstate,SQInteger ntoresolve)1319 void ResolveBreaks(SQFuncState *funcstate, SQInteger ntoresolve)
1320 {
1321 while(ntoresolve > 0) {
1322 SQInteger pos = funcstate->_unresolvedbreaks.back();
1323 funcstate->_unresolvedbreaks.pop_back();
1324 //set the jmp instruction
1325 funcstate->SetIntructionParams(pos, 0, funcstate->GetCurrentPos() - pos, 0);
1326 ntoresolve--;
1327 }
1328 }
ResolveContinues(SQFuncState * funcstate,SQInteger ntoresolve,SQInteger targetpos)1329 void ResolveContinues(SQFuncState *funcstate, SQInteger ntoresolve, SQInteger targetpos)
1330 {
1331 while(ntoresolve > 0) {
1332 SQInteger pos = funcstate->_unresolvedcontinues.back();
1333 funcstate->_unresolvedcontinues.pop_back();
1334 //set the jmp instruction
1335 funcstate->SetIntructionParams(pos, 0, targetpos - pos, 0);
1336 ntoresolve--;
1337 }
1338 }
1339 private:
1340 SQInteger _token;
1341 SQFuncState *_fs;
1342 SQObjectPtr _sourcename;
1343 SQLexer _lex;
1344 bool _lineinfo;
1345 bool _raiseerror;
1346 SQInteger _debugline;
1347 SQInteger _debugop;
1348 ExpStateVec _expstates;
1349 SQChar *compilererror;
1350 jmp_buf _errorjmp;
1351 SQVM *_vm;
1352 };
1353
Compile(SQVM * vm,SQLEXREADFUNC rg,SQUserPointer up,const SQChar * sourcename,SQObjectPtr & out,bool raiseerror,bool lineinfo)1354 bool Compile(SQVM *vm,SQLEXREADFUNC rg, SQUserPointer up, const SQChar *sourcename, SQObjectPtr &out, bool raiseerror, bool lineinfo)
1355 {
1356 SQCompiler p(vm, rg, up, sourcename, raiseerror, lineinfo);
1357 return p.Compile(out);
1358 }
1359