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