Code::Blocks  SVN r11506
sqcompiler.cpp
Go to the documentation of this file.
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 {
22  {
24  _freevar = false;
25  _class_or_delete = false;
26  _funcarg = false;
27  }
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 
49 {
50 public:
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  }
59  static void ThrowError(void *ud, const SQChar *s) {
60  SQCompiler *c = (SQCompiler *)ud;
61  c->Error(s);
62  }
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  }
73  void Lex(){ _token = _lex.Lex();}
74  void PushExpState(){ _expstates.push_back(ExpState()); }
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  }
84  {
85  ExpState ret = _expstates.top();
86  _expstates.pop_back();
87  return ret;
88  }
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  }
141  bool IsEndOfStatement() { return ((_lex._prevtoken == _SC('\n')) || (_token == SQUIRREL_EOB) || (_token == _SC('}')) || (_token == _SC(';'))); }
143  {
144  if(_token == _SC(';')) { Lex(); return; }
145  if(!IsEndOfStatement()) {
146  Error(_SC("end of statement expected (; or lf)"));
147  }
148  }
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  }
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  }
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  }
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  }
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  }
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  }
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  }
337  void CommaExpr()
338  {
339  for(Expression();_token == ',';_fs->PopTarget(), Lex(), CommaExpr());
340  }
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  }
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  }
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  }
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  }
462  {
463  BitwiseXorExp();
464  for(;;) if(_token == _SC('|'))
465  {BIN_EXP(_OP_BITW, &SQCompiler::BitwiseXorExp,BW_OR);
466  }else return;
467  }
469  {
470  BitwiseAndExp();
471  for(;;) if(_token == _SC('^'))
472  {BIN_EXP(_OP_BITW, &SQCompiler::BitwiseAndExp,BW_XOR);
473  }else return;
474  }
476  {
477  CompExp();
478  for(;;) if(_token == _SC('&'))
479  {BIN_EXP(_OP_BITW, &SQCompiler::CompExp,BW_AND);
480  }else return;
481  }
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  }
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  }
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 
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
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  }
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  }
751  void UnaryOP(SQOpcode op)
752  {
753  Lex(); PrefixedExpr();
754  SQInteger src = _fs->PopTarget();
755  _fs->AddInstruction(op, _fs->PushTarget(), src);
756  }
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 
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  }
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  }
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  }
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  }
889  {
890  SQInteger jzpos, jmppos;
891  SQInteger stacksize = _fs->GetStackSize();
892  jmppos = _fs->GetCurrentPos();
893  Lex(); Expect(_SC('(')); CommaExpr(); Expect(_SC(')'));
894 
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  }
909  {
910  Lex();
911  SQInteger jzpos = _fs->GetCurrentPos();
912  SQInteger stacksize = _fs->GetStackSize();
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  }
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  }
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  }
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
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  }
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  }
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  }
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  }
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  }
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  }
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  }
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  }
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  }
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  }
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  }
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  }
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  }
1314  void CleanStack(SQInteger stacksize)
1315  {
1316  if(_fs->GetStackSize() != stacksize)
1317  _fs->SetStackSize(stacksize);
1318  }
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  }
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;
1346  SQInteger _debugline;
1347  SQInteger _debugop;
1348  ExpStateVec _expstates;
1350  jmp_buf _errorjmp;
1351  SQVM *_vm;
1352 };
1353 
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 }
sqvector< ExpState > ExpStateVec
Definition: sqcompiler.cpp:34
void DoWhileStatement()
Definition: sqcompiler.cpp:908
SQObject Expect(SQInteger tok)
Definition: sqcompiler.cpp:89
void Statements()
Definition: sqcompiler.cpp:192
void ParseTableOrClass(SQInteger separator, SQInteger terminator='}')
Definition: sqcompiler.cpp:785
SQChar * compilererror
void BitwiseAndExp()
Definition: sqcompiler.cpp:475
bool _funcarg
Definition: sqcompiler.cpp:29
void ResolveContinues(SQFuncState *funcstate, SQInteger ntoresolve, SQInteger targetpos)
SQInteger _token
SQInteger Factor()
Definition: sqcompiler.cpp:595
void PrefixIncDec(SQInteger token)
SQFuncState * _fs
void SwitchStatement()
ExpStateVec _expstates
void MoveIfCurrentTargetIsLocal()
Definition: sqcompiler.cpp:149
void ForEachStatement()
Definition: sqcompiler.cpp:967
bool IsDerefToken(SQInteger tok)
Definition: sqcompiler.cpp:75
void LogicalOrExp()
Definition: sqcompiler.cpp:419
SQInteger _debugop
SQObjectPtr _null_
Definition: sqstate.cpp:15
void PushExpState()
Definition: sqcompiler.cpp:74
SQInteger _debugline
jmp_buf _errorjmp
void PlusExp()
Definition: sqcompiler.cpp:505
#define DEREF_NO_DEREF
Definition: sqcompiler.cpp:16
void EmitDerefOp(SQOpcode op)
Definition: sqcompiler.cpp:301
void IfStatement()
Definition: sqcompiler.cpp:861
ExpState PopExpState()
Definition: sqcompiler.cpp:83
SQCompiler(SQVM *v, SQLEXREADFUNC rg, SQUserPointer up, const SQChar *sourcename, bool raiseerror, bool lineinfo)
Definition: sqcompiler.cpp:51
void LogicalAndExp()
Definition: sqcompiler.cpp:437
void CommaExpr()
Definition: sqcompiler.cpp:337
SQObject ExpectScalar()
void ForStatement()
Definition: sqcompiler.cpp:922
#define BEGIN_BREAKBLE_BLOCK()
Definition: sqcompiler.cpp:38
void PrefixedExpr()
Definition: sqcompiler.cpp:525
void OptionalSemicolon()
Definition: sqcompiler.cpp:142
void FunctionStatement()
void Error(const SQChar *s,...)
Definition: sqcompiler.cpp:63
void ClassExp()
#define END_BREAKBLE_BLOCK(continue_target)
Definition: sqcompiler.cpp:42
void ClassStatement()
static void ThrowError(void *ud, const SQChar *s)
Definition: sqcompiler.cpp:59
void BIN_EXP(SQOpcode op, void(SQCompiler::*f)(void), SQInteger op3=0)
Definition: sqcompiler.cpp:413
void EnumStatement()
void BitwiseOrExp()
Definition: sqcompiler.cpp:461
void CreateFunction(SQObject &name)
void DeleteExpr()
bool _freevar
Definition: sqcompiler.cpp:30
void FunctionExp(SQInteger ftype)
bool Compile(SQVM *vm, SQLEXREADFUNC rg, SQUserPointer up, const SQChar *sourcename, SQObjectPtr &out, bool raiseerror, bool lineinfo)
void Statement()
Definition: sqcompiler.cpp:199
ExpState Expression(bool funcarg=false)
Definition: sqcompiler.cpp:341
void MultExp()
Definition: sqcompiler.cpp:515
void WhileStatement()
Definition: sqcompiler.cpp:888
void Emit2ArgsOP(SQOpcode op, SQInteger p3=0)
Definition: sqcompiler.cpp:308
bool NeedGet()
Definition: sqcompiler.cpp:757
void LocalDeclStatement()
Definition: sqcompiler.cpp:842
void BitwiseXorExp()
Definition: sqcompiler.cpp:468
void ShiftExp()
Definition: sqcompiler.cpp:495
bool Compile(SQObjectPtr &o)
Definition: sqcompiler.cpp:156
void CleanStack(SQInteger stacksize)
char SQChar
SQLexer _lex
void UnaryOP(SQOpcode op)
Definition: sqcompiler.cpp:751
bool _raiseerror
void TryCatchStatement()
bool IsEndOfStatement()
Definition: sqcompiler.cpp:141
void FunctionCallArgs()
Definition: sqcompiler.cpp:767
#define DEREF_FIELD
Definition: sqcompiler.cpp:17
#define _exst
Definition: sqcompiler.cpp:36
SQInteger _deref
Definition: sqcompiler.cpp:31
void CompExp()
Definition: sqcompiler.cpp:482
void DelegateExpr()
#define NULL
Definition: prefix.cpp:59
bool _class_or_delete
Definition: sqcompiler.cpp:28
void ResolveBreaks(SQFuncState *funcstate, SQInteger ntoresolve)
void Lex()
Definition: sqcompiler.cpp:73
void EmitCompoundArith(SQInteger tok, bool deref)
Definition: sqcompiler.cpp:314
SQObjectPtr _sourcename