Browse Source

Add examples of C++ code that can be parsed/run by SquiLu

mingodad 9 years ago
parent
commit
57ce8960c1
3 changed files with 3983 additions and 0 deletions
  1. 64 0
      SquiLu/samples/binary-tree-cpp.nut
  2. 1402 0
      SquiLu/samples/sqlexer.nut
  3. 2517 0
      SquiLu/samples/sqparser.nut

+ 64 - 0
SquiLu/samples/binary-tree-cpp.nut

@@ -0,0 +1,64 @@
+// The Computer Language Benchmarks Game
+// http://benchmarksgame.alioth.debian.org/
+// contributed by Mike Pall
+
+array_t BottomUpTree(int_t item, int_t depth){
+  //array_t ary = [];//array(3);
+  //ary.clear();
+   //ary.push_back(item);
+  if (depth > 0){
+    int_t i = item + item;
+    --depth;
+    //ary.push_back(BottomUpTree(i-1, depth));
+    //ary.push_back(BottomUpTree(i, depth));
+    return [ item, BottomUpTree(i-1, depth),  BottomUpTree(i, depth) ];
+  }
+  //return ary;
+  return [ item ];
+}
+
+int_t ItemCheck(array_t tree){
+  //if (tree.get(1, false))  return tree[0] + ItemCheck(tree[1]) - ItemCheck(tree[2])
+  if (tree.len() > 1)  return tree[0] + ItemCheck(tree[1]) - ItemCheck(tree[2])
+  return tree[0]
+}
+
+int_t main()
+{
+	double_t start = os.clock()
+	//check_delayed_release_hooks(false);
+
+	int_t N = vargv.get(1, 14).tointeger();
+	int_t mindepth = 4
+	int_t maxdepth = mindepth + 2
+	if (maxdepth < N) maxdepth = N
+
+	{
+	  int_t stretchdepth = maxdepth + 1
+	  array_t stretchtree = BottomUpTree(0, stretchdepth)
+	  printf("stretch tree of depth %d\t check: %d\n",
+	    stretchdepth, ItemCheck(stretchtree));
+	}
+
+	array_t longlivedtree = BottomUpTree(0, maxdepth)
+
+	for(int_t depth=mindepth; depth <= maxdepth; depth += 2){
+	  int_t iterations = math.pow(2, (maxdepth - depth + mindepth)).tointeger()
+	  int_t check = 0
+	  for(int_t i=0; i < iterations; ++i){
+	    check += (ItemCheck(BottomUpTree(1, depth))) +
+		    (ItemCheck(BottomUpTree(-1, depth)));
+	  }
+	  printf("%d\t trees of depth %d\t check: %d\n",
+	    iterations*2, depth, check);
+	}
+
+	printf("long lived tree of depth %d\t check: %d\n",
+	  maxdepth, ItemCheck(longlivedtree));
+
+	printf("binary-tree \t%d \t%f\n", N, os.clock()-start);
+
+	return 0;
+}
+
+main();

+ 1402 - 0
SquiLu/samples/sqlexer.nut

@@ -0,0 +1,1402 @@
+//__max_print_stack_str_size <- 256;
+const TK_FIRST_ENUM_TOKEN = 258;
+const TK_3WAYSCMP = 259;
+const TK_AND = 260;
+const TK_ARROW = 261;
+const TK_AS = 262;
+const TK_ATTR_CLOSE = 263;
+const TK_ATTR_OPEN = 264;
+const TK_BASE = 265;
+const TK_BIT_AND_EQ = 266;
+const TK_BIT_OR_EQ = 267;
+const TK_BIT_SHIFT_LEFT_EQ = 268;
+const TK_BIT_SHIFT_RIGHT_EQ = 269;
+const TK_BIT_XOR_EQ = 270;
+const TK_BREAK = 271;
+const TK_CASE = 272;
+const TK_CATCH = 273;
+const TK_CLASS = 274;
+const TK_CLONE = 275;
+const TK_CONST = 276;
+const TK_COMMENT_BLOCK = 277;
+const TK_COMMENT_LINE = 278;
+const TK_CONSTRUCTOR = 279;
+const TK_CONTINUE = 280;
+const TK_DECLARE = 281;
+const TK_DEFAULT = 282;
+const TK_DELETE = 283;
+const TK_DESTRUCTOR = 284;
+const TK_DIVEQ = 285;
+const TK_DO = 286;
+const TK_DOUBLE_COLON = 287;
+const TK_ELSE = 288;
+const TK_ENUM = 289;
+const TK_EQ = 290;
+const TK_EQ_IDENTITY = 291;
+const TK_EXTENDS = 292;
+const TK_EXTERN = 293;
+const TK_FALSE = 294;
+const TK___FILE__ = 295;
+const TK_FLOAT = 296;
+const TK_FOR = 297;
+const TK_FOREACH = 298;
+const TK_FRIEND = 299;
+const TK___FUNCTION__ = 300;
+const TK_FUNCTION = 301;
+const TK_GE = 302;
+const TK_IDENTIFIER = 303;
+const TK_IF = 304;
+const TK_IGNORE = 305;
+const TK_IN = 306;
+const TK_INSTANCEOF = 307;
+const TK_INTEGER = 308;
+const TK_LE = 309;
+const TK___LINE__ = 310;
+const TK_LOCAL = 311;
+const TK_LOCAL_ANY_T = 312;
+const TK_LOCAL_ARRAY_T = 313;
+const TK_LOCAL_BOOL_T = 314;
+const TK_LOCAL_CHAR_T = 315;
+const TK_LOCAL_DOUBLE_T = 316;
+const TK_LOCAL_FLOAT_T = 317;
+const TK_LOCAL_INT16_T = 318;
+const TK_LOCAL_INT32_T = 319;
+const TK_LOCAL_INT64_T = 320;
+const TK_LOCAL_INT8_T = 321;
+const TK_LOCAL_INT_T = 322;
+const TK_LOCAL_LONG_DOUBLE_T = 323;
+const TK_LOCAL_NUMBER_T = 324;
+const TK_LOCAL_SIZE_T = 325;
+const TK_LOCAL_SSIZE_T = 326;
+const TK_LOCAL_STRING_T = 327;
+const TK_LOCAL_TABLE_T = 328;
+const TK_LOCAL_UINT16_T = 329;
+const TK_LOCAL_UINT32_T = 330;
+const TK_LOCAL_UINT64_T = 331;
+const TK_LOCAL_UINT8_T = 332;
+const TK_LOCAL_UINT_T = 333;
+const TK_LOCAL_VOIDPTR_T = 334;
+const TK_LOCAL_WCHAR_T = 335;
+const TK_LOCAL_WEAKREF_T = 336;
+const TK_MINUSEQ = 337;
+const TK_MINUSMINUS = 338;
+const TK_MODEQ = 339;
+const TK_MODULO = 340;
+const TK_MULEQ = 341;
+const TK_NE = 342;
+const TK_NE_IDENTITY = 343;
+const TK_NEWSLOT = 344;
+const TK_NOEXCEPT = 345;
+const TK_NULL = 346;
+const TK_OR = 347;
+const TK_PLUSEQ = 348;
+const TK_PLUSPLUS = 349;
+const TK_PRAGMA = 350;
+const TK_PRIVATE = 351;
+const TK_PUBLIC = 352;
+const TK_RESUME = 353;
+const TK_RETURN = 354;
+const TK_SHIFTL = 355;
+const TK_SHIFTR = 356;
+const TK_STATIC = 357;
+const TK_STRING_LITERAL = 358;
+const TK_STRUCT = 359;
+const TK_SWITCH = 360;
+const TK_THIS = 361;
+const TK_THROW = 362;
+const TK_TYPEDEF = 363;
+const TK_TRUE = 364;
+const TK_TRY = 365;
+const TK_TYPEOF = 366;
+const TK_UMINUS = 367;
+const TK_UNSAFE = 368;
+const TK_USING = 369;
+const TK_USHIFTR = 370;
+const TK_VARPARAMS = 371;
+const TK_VIRTUAL = 372;
+const TK_VOID = 373;
+const TK_VOLATILE = 374;
+const TK_WHILE = 375;
+const TK_YIELD = 376;
+const TK_INLINE = 377;
+const TK_CONSTEXPR = 378;
+const TK_LAST_ENUM_TOKEN = 379;
+
+//typedefs to allow parse/compile
+typedef char_t SQChar;
+typedef char_ptr_t SQChar_ptr_t;
+typedef class_t SQObject;
+typedef var_t SQObjectPtr;
+typedef bool_t bool;
+typedef bool_t SQBool;
+typedef int_t int;
+typedef int_t SQInteger;
+typedef class_t SQLex;
+typedef enum_t SQOpcode;
+typedef float_t SQFloat;
+typedef void_ptr_t SQObjectPtr_ptr_t;
+typedef class_t SQFuncState;
+typedef void_ptr_t SQFuncState_ptr_t;
+typedef class_t SQVM;
+typedef class_ptr_t SQVM_ptr_t;
+typedef struct_t jmp_buf;
+typedef array_t SQObjectPtrVec;
+typedef void_ptr_t SQUserPointer;
+typedef array_t SQInstructionVec;
+typedef param_t T;
+typedef func_ptr_t SQLEXREADFUNC;
+typedef class_ptr_t SQCompiler_ptr_t;
+typedef void_ptr_t va_list;
+typedef enum_t SQObjectType;
+typedef char_t LexChar;
+typedef class_ptr_t SQSharedState_ptr_t;
+typedef func_ptr_t CompilerErrorFunc;
+typedef table_ptr_t SQTable_ptr_t;
+typedef array_t sqvector_SQChar;
+typedef uint_t SQUnsignedInteger;
+typedef uint_ptr_t SQUnsignedInteger_ptr_t;
+typedef string_ptr_t SQString_ptr_t;
+
+const SQFalse = 0;
+const SQTrue = 1;
+const SQUIRREL_EOB = -1;
+const EOF = -1;
+const MAX_CHAR = 0xFF;
+
+const MAX_HEX_DIGITS = 12;
+const TINT =1;
+const TFLOAT = 2;
+const THEX = 3;
+const TSCIENTIFIC = 4;
+const TOCTAL = 5;
+
+SQInteger isexponent(SQInteger c)
+{
+    return c == 'e' || c=='E';
+}
+SQInteger scisdigit(SQInteger c)
+{
+    return c >= '0' && c <= '9';
+}
+SQInteger scdigitvalue(SQInteger c)
+{
+    if(c >= '0' && c <= '9') return c - '0';
+    assert(0);
+    return 0;
+}
+SQInteger scisodigit(SQInteger c)
+{
+    return c >= '0' && c <= '7';
+}
+SQInteger scodigitvalue(SQInteger c)
+{
+    if(c >= '0' && c <= '7') return c - '0';
+    assert(0);
+    return 0;
+}
+SQInteger scisxdigit(SQInteger c)
+{
+    return (c >= '0' && c <= '9') || (c >= 'a' && c <= 'f') || (c >= 'A' && c <= 'F');
+}
+SQInteger scxdigitvalue(SQInteger c)
+{
+    if(c >= '0' && c <= '9') return (c - '0');
+    if(c >= 'a' && c <= 'f') return (c - 'a') + 10;
+    if(c >= 'A' && c <= 'F') return (c - 'A') + 10;
+    assert(0);
+    return 0;
+}
+
+SQInteger scisalpha(SQInteger c)
+{
+    return (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z');
+}
+
+SQInteger scisalnum(SQInteger c)
+{
+    return (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || (c >= '0' && c <= '9');
+}
+
+SQInteger sctoupper(SQInteger c)
+{
+	if((c >= 'a' && c <= 'z')) return c - ('a'-'A');
+	return c;
+}
+
+SQUnsignedInteger LexHexadecimal(const SQChar_ptr_t s, SQInteger sz)
+{
+    SQUnsignedInteger res = 0;
+    //for(char c : s)
+    foreach(c in s)
+    {
+        res = res * 16 + scxdigitvalue(c);
+    }
+    return res;
+}
+
+SQUnsignedInteger LexInteger(const SQChar_ptr_t s, SQInteger sz)
+{
+    SQUnsignedInteger res = 0;
+    //for(char c : s)
+    foreach(c in s)
+    {
+        res = res * 10 + scdigitvalue(c);
+    }
+    return res;
+}
+
+SQUnsignedInteger LexOctal(const SQChar_ptr_t s, SQInteger sz)
+{
+    SQUnsignedInteger res = 0;
+    //for(char c : s)
+    foreach(c in s)
+    {
+        res = res * 8 + scodigitvalue(c);
+    }
+    return res;
+}
+
+
+class SQSharedState
+{
+};
+
+struct FILE
+{
+    string_t data;
+    int_t cursor, size;
+    FILE(string_t dt)
+    {
+        data = dt;
+        cursor = 0;
+	size = data.size();
+    }
+};
+typedef class_ptr_t FILE_ptr_t;
+
+SQInteger fgetc(FILE_ptr_t fp)
+{
+    if(fp->cursor < fp->size)
+    {
+        return fp->data[fp->cursor++];
+    }
+    return EOF;
+}
+
+static SQInteger compilerReadFunc(SQUserPointer fp)
+{
+    SQInteger c = fgetc(/*(FILE *)*/fp);
+    if(c == EOF)
+    {
+        return 0;
+    }
+    return c;
+}
+
+struct SQString
+{
+    static SQString_ptr_t Create(SQSharedState_ptr_t ss, string_t s)
+    {
+        return s;
+    }
+};
+
+struct SQTable
+{
+    table_t _tbl;
+
+    SQTable()
+    {
+        _tbl = {};
+    }
+
+    static SQTable_ptr_t Create(SQSharedState_ptr_t ss, SQInteger n)
+    {
+        return SQTable();
+    }
+    bool NewSlot(const SQObjectPtr &key,const SQObjectPtr &val)
+    {
+        table_rawset(_tbl, key, val);
+        return true;
+    }
+    /*inline*/ bool GetStr(const SQChar_ptr_t key,SQInteger keylen,SQObjectPtr /*&*/val)
+    {
+	val = table_rawget(_tbl, key, NULL);
+	return val;
+    }
+    
+    SQInteger Next(bool getweakrefs,const SQObjectPtr &refpos, SQObjectPtr &outkey, SQObjectPtr &outval)
+    {
+	    return -1;
+    }
+};
+
+struct SQLexerNut
+{
+    SQInteger CUR_CHAR;
+
+    SQLexerNut()
+    {
+        _keywords=0;
+        _longstr = blob(0, 8192);
+    }
+    virtual ~SQLexerNut()
+    {
+        _keywords->Release();
+    }
+
+    void INIT_TEMP_STRING()
+    {
+        _longstr.clear();
+    }
+    
+    void  TERMINATE_BUFFER()
+    {
+	   // _longstr.push_back('\0'));
+    }
+
+    void APPEND_CHAR(SQInteger c)
+    {
+        _longstr.writen(c, 'c');
+    }
+
+    SQInteger NEXT()
+    {
+        SQInteger rc = Next();if(rc < 0) return rc;_currentcolumn++;
+    }
+    
+    SQInteger RETURN_TOKEN(SQInteger t)
+    {
+	     _prevtoken = _curtoken; _curtoken = t; return t;
+    }
+    
+    bool IS_EOB(){return CUR_CHAR <= SQUIRREL_EOB;}
+
+    SQInteger Init(SQSharedState_ptr_t ss,SQLEXREADFUNC rg,SQUserPointer up,
+                   CompilerErrorFunc efunc,void_ptr_t ed, SQBool want_comments=SQFalse)
+    {
+        _want_comments = want_comments;
+        //_lasterror[0] = '\0';
+        _svalue = NULL;
+        _errfunc = efunc;
+        _errtarget = ed;
+        _sharedstate = ss;
+        if(_keywords) _keywords->Release();
+        _keywords = GetKeywords();
+        return ResetReader(rg, up, 1);
+    }
+
+    SQInteger ResetReader(SQLEXREADFUNC rg, SQUserPointer up, SQInteger line)
+    {
+        _readf = rg;
+        _up = up;
+        _lasttokenline = _currentline = line;
+        _lasttokencolumn = 0;
+        _currentcolumn = 0;
+        _prevtoken = -1;
+        _reached_eof = SQFalse;
+        return Next();
+    }
+
+    void ADD_KEYWORD(SQTable_ptr_t tbl, string_t &key, SQInteger id)
+    {
+        tbl->NewSlot( SQString.Create(_sharedstate, key), id);
+    }
+
+    SQTable_ptr_t GetKeywords()
+    {
+        SQTable_ptr_t tbl = SQTable.Create(_sharedstate, (TK_LAST_ENUM_TOKEN - TK_FIRST_ENUM_TOKEN - 1) /*26*/);
+        ADD_KEYWORD(tbl, "any_t", TK_LOCAL_ANY_T);
+        ADD_KEYWORD(tbl, "array_t", TK_LOCAL_ARRAY_T);
+        ADD_KEYWORD(tbl, "as", TK_AS);
+        ADD_KEYWORD(tbl, "auto", TK_LOCAL);
+        ADD_KEYWORD(tbl, "base", TK_BASE);
+        ADD_KEYWORD(tbl, "bool_t", TK_LOCAL_BOOL_T);
+        ADD_KEYWORD(tbl, "break", TK_BREAK);
+        ADD_KEYWORD(tbl, "case", TK_CASE);
+        ADD_KEYWORD(tbl, "catch", TK_CATCH);
+        ADD_KEYWORD(tbl, "char_t", TK_LOCAL_CHAR_T);
+        ADD_KEYWORD(tbl, "class",TK_CLASS);
+        ADD_KEYWORD(tbl, "clone", TK_CLONE);
+        ADD_KEYWORD(tbl, "constructor",TK_CONSTRUCTOR);
+        ADD_KEYWORD(tbl, "const",TK_CONST);
+        ADD_KEYWORD(tbl, "constexpr",TK_CONSTEXPR);
+        ADD_KEYWORD(tbl, "continue", TK_CONTINUE);
+        ADD_KEYWORD(tbl, "declare", TK_DECLARE);
+        ADD_KEYWORD(tbl, "default", TK_DEFAULT);
+        ADD_KEYWORD(tbl, "delete", TK_DELETE);
+        ADD_KEYWORD(tbl, "destructor",TK_DESTRUCTOR);
+        ADD_KEYWORD(tbl, "do", TK_DO);
+        ADD_KEYWORD(tbl, "double_t", TK_LOCAL_DOUBLE_T);
+        ADD_KEYWORD(tbl, "else", TK_ELSE);
+        ADD_KEYWORD(tbl, "enum",TK_ENUM);
+        ADD_KEYWORD(tbl, "extends",TK_EXTENDS);
+        ADD_KEYWORD(tbl, "extern",TK_EXTERN);
+        ADD_KEYWORD(tbl, "false",TK_FALSE);
+        ADD_KEYWORD(tbl, "__FILE__",TK___FILE__);
+        ADD_KEYWORD(tbl, "float_t", TK_LOCAL_FLOAT_T);
+        ADD_KEYWORD(tbl, "foreach", TK_FOREACH);
+        ADD_KEYWORD(tbl, "for", TK_FOR);
+        ADD_KEYWORD(tbl, "friend", TK_FRIEND);
+        ADD_KEYWORD(tbl, "function", TK_FUNCTION);
+        ADD_KEYWORD(tbl, "__FUNCTION__",TK___FUNCTION__);
+        ADD_KEYWORD(tbl, "if", TK_IF);
+        ADD_KEYWORD(tbl, "instanceof",TK_INSTANCEOF);
+        ADD_KEYWORD(tbl, "int16_t", TK_LOCAL_INT16_T);
+        ADD_KEYWORD(tbl, "int32_t", TK_LOCAL_INT32_T);
+        ADD_KEYWORD(tbl, "int64_t", TK_LOCAL_INT64_T);
+        ADD_KEYWORD(tbl, "int8_t", TK_LOCAL_INT8_T);
+        ADD_KEYWORD(tbl, "in", TK_IN);
+        ADD_KEYWORD(tbl, "inline", TK_INLINE);
+        ADD_KEYWORD(tbl, "int_t", TK_LOCAL_INT_T);
+        ADD_KEYWORD(tbl, "let", TK_LOCAL);
+        ADD_KEYWORD(tbl, "__LINE__",TK___LINE__);
+        ADD_KEYWORD(tbl, "local", TK_LOCAL);
+        ADD_KEYWORD(tbl, "long_double_t", TK_LOCAL_LONG_DOUBLE_T);
+        ADD_KEYWORD(tbl, "new",TK_IGNORE);
+        ADD_KEYWORD(tbl, "noexcept",TK_NOEXCEPT);
+        ADD_KEYWORD(tbl, "number_t", TK_LOCAL_NUMBER_T);
+        ADD_KEYWORD(tbl, "null", TK_NULL);
+        ADD_KEYWORD(tbl, "NULL", TK_NULL);
+        ADD_KEYWORD(tbl, "private",TK_PRIVATE);
+        ADD_KEYWORD(tbl, "public",TK_PUBLIC);
+        ADD_KEYWORD(tbl, "resume", TK_RESUME);
+        ADD_KEYWORD(tbl, "return", TK_RETURN);
+        ADD_KEYWORD(tbl, "size_t",TK_LOCAL_SIZE_T);
+        ADD_KEYWORD(tbl, "ssize_t",TK_LOCAL_SSIZE_T);
+        ADD_KEYWORD(tbl, "static",TK_STATIC);
+        ADD_KEYWORD(tbl, "string_t", TK_LOCAL_STRING_T);
+        ADD_KEYWORD(tbl, "struct",TK_STRUCT);
+        ADD_KEYWORD(tbl, "switch", TK_SWITCH);
+        ADD_KEYWORD(tbl, "table_t", TK_LOCAL_TABLE_T);
+        ADD_KEYWORD(tbl, "this", TK_THIS);
+        ADD_KEYWORD(tbl, "throw", TK_THROW);
+        ADD_KEYWORD(tbl, "typedef", TK_TYPEDEF);
+        ADD_KEYWORD(tbl, "true",TK_TRUE);
+        ADD_KEYWORD(tbl, "try", TK_TRY);
+        ADD_KEYWORD(tbl, "typeof", TK_TYPEOF);
+        ADD_KEYWORD(tbl, "uint16_t", TK_LOCAL_UINT16_T);
+        ADD_KEYWORD(tbl, "uint32_t", TK_LOCAL_UINT32_T);
+        ADD_KEYWORD(tbl, "uint64_t", TK_LOCAL_UINT64_T);
+        ADD_KEYWORD(tbl, "uint8_t", TK_LOCAL_UINT8_T);
+        ADD_KEYWORD(tbl, "uint_t", TK_LOCAL_UINT_T);
+        ADD_KEYWORD(tbl, "unsafe", TK_UNSAFE);
+        ADD_KEYWORD(tbl, "using", TK_USING);
+        ADD_KEYWORD(tbl, "var", TK_LOCAL);
+        ADD_KEYWORD(tbl, "virtual", TK_VIRTUAL);
+        ADD_KEYWORD(tbl, "void_ptr_t", TK_LOCAL_VOIDPTR_T);
+        ADD_KEYWORD(tbl, "void", TK_VOID);
+        ADD_KEYWORD(tbl, "volatile", TK_VOLATILE);
+        ADD_KEYWORD(tbl, "wchar_t", TK_LOCAL_WCHAR_T);
+        ADD_KEYWORD(tbl, "weakref_t", TK_LOCAL_WEAKREF_T);
+        ADD_KEYWORD(tbl, "while", TK_WHILE);
+        ADD_KEYWORD(tbl, "yield", TK_YIELD);
+
+        return tbl;
+    }
+
+    SQInteger Error(const SQChar_ptr_t err, ...)
+    {
+	throw err;
+        va_list vl;
+        va_start(vl, fmt);
+        scvsprintf(_lasterror, sizeof(_lasterror), fmt, vl);
+        va_end(vl);
+        if(_errfunc) _errfunc(_errtarget,_lasterror);
+        return -1;
+    }
+
+    SQInteger Lex()
+    {
+//print("Lex", __LINE__, _currentline, _currentcolumn, CUR_CHAR);
+        _lasttokenline = _currentline;
+        _lasttokencolumn = _currentcolumn;
+        while(CUR_CHAR != SQUIRREL_EOB)
+        {
+            switch(CUR_CHAR)
+            {
+            case '\t':
+            case '\r':
+            case ' ':
+                /*NEXT()*/{SQInteger rc = Next();if(rc < 0) return rc;_currentcolumn++;};
+                continue;
+            case '\n':
+                _currentline++;
+                _prevtoken=_curtoken;
+                _curtoken='\n';
+                /*NEXT()*/{SQInteger rc = Next();if(rc < 0) return rc;_currentcolumn++;};
+                _currentcolumn=1;
+                continue;
+            case '#':
+                /*NEXT()*/{SQInteger rc = Next();if(rc < 0) return rc;_currentcolumn++;};
+                if(CUR_CHAR == '!') //shell shebang
+                {
+                    if(LexLineComment()) return -1;
+                    if(_want_comments) return RETURN_TOKEN(TK_COMMENT_LINE)
+                        continue;
+                }
+                return RETURN_TOKEN(TK_PRAGMA);
+                continue;
+            case '/':
+                /*NEXT()*/{SQInteger rc = Next();if(rc < 0) return rc;_currentcolumn++;};
+                switch(CUR_CHAR)
+                {
+                case '*':
+                    if(LexBlockComment()) return -1;
+                    if(_want_comments) return RETURN_TOKEN(TK_COMMENT_BLOCK)
+                        continue;
+                case '/':
+                    if(LexLineComment()) return -1;
+                    if(_want_comments) return RETURN_TOKEN(TK_COMMENT_LINE)
+                        continue;
+                case '=':
+                    /*NEXT()*/{SQInteger rc = Next();if(rc < 0) return rc;_currentcolumn++;};
+                    return RETURN_TOKEN(TK_DIVEQ);
+                    continue;
+                case '>':
+                    /*NEXT()*/{SQInteger rc = Next();if(rc < 0) return rc;_currentcolumn++;};
+                    return RETURN_TOKEN(TK_ATTR_CLOSE);
+                    continue;
+                default:
+                    return RETURN_TOKEN('/');
+                }
+            case '=':
+                /*NEXT()*/{SQInteger rc = Next();if(rc < 0) return rc;_currentcolumn++;};
+                if (CUR_CHAR != '=')
+                {
+                    return RETURN_TOKEN('=')
+                }
+                else
+                {
+                    /*NEXT()*/{SQInteger rc = Next();if(rc < 0) return rc;_currentcolumn++;};
+                    if (CUR_CHAR == '=')
+                    {
+                        /*NEXT()*/{SQInteger rc = Next();if(rc < 0) return rc;_currentcolumn++;};
+                        return RETURN_TOKEN(TK_EQ_IDENTITY)
+                    }
+                    else
+                    {
+                        return RETURN_TOKEN(TK_EQ);
+                    }
+                }
+            case '<':
+                /*NEXT()*/{SQInteger rc = Next();if(rc < 0) return rc;_currentcolumn++;};
+                switch(CUR_CHAR)
+                {
+                case '=':
+                    /*NEXT()*/{SQInteger rc = Next();if(rc < 0) return rc;_currentcolumn++;};
+                    if(CUR_CHAR == '>')
+                    {
+                        /*NEXT()*/{SQInteger rc = Next();if(rc < 0) return rc;_currentcolumn++;};
+                        return RETURN_TOKEN(TK_3WAYSCMP);
+                    }
+                    return RETURN_TOKEN(TK_LE)
+                    break;
+                case '-':
+                    /*NEXT()*/{SQInteger rc = Next();if(rc < 0) return rc;_currentcolumn++;};
+                    return RETURN_TOKEN(TK_NEWSLOT);
+                    break;
+                case '<':
+                    /*NEXT()*/{SQInteger rc = Next();if(rc < 0) return rc;_currentcolumn++;};
+                    return RETURN_TOKEN(TK_SHIFTL);
+                    break;
+                case '/':
+                    /*NEXT()*/{SQInteger rc = Next();if(rc < 0) return rc;_currentcolumn++;};
+                    return RETURN_TOKEN(TK_ATTR_OPEN);
+                    break;
+                }
+                return RETURN_TOKEN('<');
+            case '>':
+                /*NEXT()*/{SQInteger rc = Next();if(rc < 0) return rc;_currentcolumn++;};
+                if (CUR_CHAR == '=')
+                {
+                    /*NEXT()*/{SQInteger rc = Next();if(rc < 0) return rc;_currentcolumn++;};
+                    return RETURN_TOKEN(TK_GE);
+                }
+                else if(CUR_CHAR == '>')
+                {
+                    /*NEXT()*/{SQInteger rc = Next();if(rc < 0) return rc;_currentcolumn++;};
+                    if(CUR_CHAR == '>')
+                    {
+                        /*NEXT()*/{SQInteger rc = Next();if(rc < 0) return rc;_currentcolumn++;};
+                        return RETURN_TOKEN(TK_USHIFTR);
+                    }
+                    return RETURN_TOKEN(TK_SHIFTR);
+                }
+                else
+                {
+                    return RETURN_TOKEN('>')
+                }
+            case '!':
+                /*NEXT()*/{SQInteger rc = Next();if(rc < 0) return rc;_currentcolumn++;};
+                if (CUR_CHAR != '=')
+                {
+                    return RETURN_TOKEN('!')
+                }
+                else
+                {
+                    /*NEXT()*/{SQInteger rc = Next();if(rc < 0) return rc;_currentcolumn++;};
+                    if (CUR_CHAR == '=')
+                    {
+                        /*NEXT()*/{SQInteger rc = Next();if(rc < 0) return rc;_currentcolumn++;};
+                        return RETURN_TOKEN(TK_NE_IDENTITY)
+                    }
+                    else
+                    {
+                        return RETURN_TOKEN(TK_NE);
+                    }
+                }
+            case '@':
+            {
+                SQInteger stype;
+                /*NEXT()*/{SQInteger rc = Next();if(rc < 0) return rc;_currentcolumn++;};
+                if(CUR_CHAR != '"')
+                {
+                    return RETURN_TOKEN('@');
+                }
+                if((stype=ReadString('"',true))!=-1)
+                {
+                    return RETURN_TOKEN(stype);
+                }
+                return Error("error parsing the string");
+            }
+            case '"':
+            case '\'':
+            {
+                SQInteger stype;
+                if((stype=ReadString(CUR_CHAR,false))!=-1)
+                {
+                    return RETURN_TOKEN(stype);
+                }
+                return Error("error parsing the string");
+            }
+            case '{':
+            case '}':
+            case '(':
+            case ')':
+            case '[':
+            case ']':
+            case ';':
+            case ',':
+            case '?':
+            case '~':
+            {
+                SQInteger ret = CUR_CHAR;
+                /*NEXT()*/{SQInteger rc = Next();if(rc < 0) return rc;_currentcolumn++;};
+                if((ret == '[' || ret == '{' || ret == '(') && CUR_CHAR == '=')
+                {
+                    //lets try lua literal delimiters
+                    SQInteger stype;
+                    if((stype=ReadString(ret,true))!=-1)
+                    {
+                        return RETURN_TOKEN(stype);
+                    }
+                    return Error("error parsing the string");
+                }
+                else return RETURN_TOKEN(ret);
+            }
+            case '.':
+                /*NEXT()*/{SQInteger rc = Next();if(rc < 0) return rc;_currentcolumn++;};
+                if (CUR_CHAR != '.')
+                {
+                    return RETURN_TOKEN('.')
+                }
+                /*NEXT()*/{SQInteger rc = Next();if(rc < 0) return rc;_currentcolumn++;};
+                if (CUR_CHAR != '.')
+                {
+                    return Error("invalid token '..'");
+                }
+                /*NEXT()*/{SQInteger rc = Next();if(rc < 0) return rc;_currentcolumn++;};
+                return RETURN_TOKEN(TK_VARPARAMS);
+            case '^':
+                /*NEXT()*/{SQInteger rc = Next();if(rc < 0) return rc;_currentcolumn++;};
+                //if (CUR_CHAR == '='){ /*NEXT()*/{SQInteger rc = Next();if(rc < 0) return rc;_currentcolumn++;}; return RETURN_TOKEN(TK_BIT_XOR_EQ);}
+                return RETURN_TOKEN('^');
+            case '&':
+                /*NEXT()*/{SQInteger rc = Next();if(rc < 0) return rc;_currentcolumn++;};
+                //if (CUR_CHAR == '='){ /*NEXT()*/{SQInteger rc = Next();if(rc < 0) return rc;_currentcolumn++;}; return RETURN_TOKEN(TK_BIT_AND_EQ);}
+                if (CUR_CHAR != '&')
+                {
+                    return RETURN_TOKEN('&')
+                }
+                else
+                {
+                    /*NEXT()*/{SQInteger rc = Next();if(rc < 0) return rc;_currentcolumn++;};
+                    return RETURN_TOKEN(TK_AND);
+                }
+            case '|':
+                /*NEXT()*/{SQInteger rc = Next();if(rc < 0) return rc;_currentcolumn++;};
+                //if (CUR_CHAR == '='){ /*NEXT()*/{SQInteger rc = Next();if(rc < 0) return rc;_currentcolumn++;}; return RETURN_TOKEN(TK_BIT_OR_EQ);}
+                if (CUR_CHAR != '|')
+                {
+                    return RETURN_TOKEN('|')
+                }
+                else
+                {
+                    /*NEXT()*/{SQInteger rc = Next();if(rc < 0) return rc;_currentcolumn++;};
+                    return RETURN_TOKEN(TK_OR);
+                }
+            case ':':
+                /*NEXT()*/{SQInteger rc = Next();if(rc < 0) return rc;_currentcolumn++;};
+                if (CUR_CHAR != ':')
+                {
+                    return RETURN_TOKEN(':')
+                }
+                else
+                {
+                    /*NEXT()*/{SQInteger rc = Next();if(rc < 0) return rc;_currentcolumn++;};
+                    return RETURN_TOKEN(TK_DOUBLE_COLON);
+                }
+            case '*':
+                /*NEXT()*/{SQInteger rc = Next();if(rc < 0) return rc;_currentcolumn++;};
+                if (CUR_CHAR == '=')
+                {
+                    /*NEXT()*/{SQInteger rc = Next();if(rc < 0) return rc;_currentcolumn++;};
+                    return RETURN_TOKEN(TK_MULEQ);
+                }
+                else return RETURN_TOKEN('*');
+            case '%':
+                /*NEXT()*/{SQInteger rc = Next();if(rc < 0) return rc;_currentcolumn++;};
+                if (CUR_CHAR == '=')
+                {
+                    /*NEXT()*/{SQInteger rc = Next();if(rc < 0) return rc;_currentcolumn++;};
+                    return RETURN_TOKEN(TK_MODEQ);
+                }
+                else return RETURN_TOKEN('%');
+            case '-':
+                /*NEXT()*/{SQInteger rc = Next();if(rc < 0) return rc;_currentcolumn++;};
+                if (CUR_CHAR == '=')
+                {
+                    /*NEXT()*/{SQInteger rc = Next();if(rc < 0) return rc;_currentcolumn++;};
+                    return RETURN_TOKEN(TK_MINUSEQ);
+                }
+                else if  (CUR_CHAR == '-')
+                {
+                    /*NEXT()*/{SQInteger rc = Next();if(rc < 0) return rc;_currentcolumn++;};
+                    return RETURN_TOKEN(TK_MINUSMINUS);
+                }
+                else if  (CUR_CHAR == '>')
+                {
+                    /*NEXT()*/{SQInteger rc = Next();if(rc < 0) return rc;_currentcolumn++;};    //accept C/C++ like pointers
+                    return RETURN_TOKEN('.');
+                }
+                else return RETURN_TOKEN('-');
+            case '+':
+                /*NEXT()*/{SQInteger rc = Next();if(rc < 0) return rc;_currentcolumn++;};
+                if (CUR_CHAR == '=')
+                {
+                    /*NEXT()*/{SQInteger rc = Next();if(rc < 0) return rc;_currentcolumn++;};
+                    return RETURN_TOKEN(TK_PLUSEQ);
+                }
+                else if (CUR_CHAR == '+')
+                {
+                    /*NEXT()*/{SQInteger rc = Next();if(rc < 0) return rc;_currentcolumn++;};
+                    return RETURN_TOKEN(TK_PLUSPLUS);
+                }
+                else return RETURN_TOKEN('+');
+            case SQUIRREL_EOB:
+                return 0;
+            default:
+            {
+                if (scisdigit(CUR_CHAR))
+                {
+                    SQInteger ret = ReadNumber();
+                    if(ret < 0) return -1;
+                    return RETURN_TOKEN(ret);
+                }
+                else if (scisalpha(CUR_CHAR) || CUR_CHAR == '_')
+                {
+                    SQInteger t = ReadID();
+                    if(t < 0) return -1;
+                    return RETURN_TOKEN(t);
+                }
+                else
+                {
+                    SQInteger c = CUR_CHAR;
+                    if (sciscntrl((int)c)) return Error("unexpected character(control)");
+                    /*NEXT()*/{SQInteger rc = Next();if(rc < 0) return rc;_currentcolumn++;};
+                    return RETURN_TOKEN(c);
+                }
+                return RETURN_TOKEN(0);
+            }
+            }
+        }
+        return 0;
+    }
+
+    /*const*/ SQChar_ptr_t Tok2Str(SQInteger tok)
+    {
+	foreach(k,v in _keywords->_tbl)
+	{
+		if(v == tok) return k;
+	}
+	if(0)
+	{
+		SQObjectPtr itr, key, val;
+		SQInteger nitr;
+		while((nitr = _keywords->Next(false,itr, key, val)) != -1)
+		{
+		    itr = /*(SQInteger)*/nitr;
+		    if(/*((SQInteger)_integer(*/val/*))*/ == tok)
+			return /*_stringval(*/key/*)*/;
+		}
+	}
+        return NULL;
+    }
+
+    /*const*/ SQChar_ptr_t GetTokenName(int tk_code)
+    {
+	foreach(k,v in getconsttable())
+	{
+		if(v == tk_code) return k;
+	}
+
+	    /*const*/ SQChar_ptr_t str_tk;
+
+        switch(tk_code)
+        {
+        //#define ENUM_TK(a) case TK_##a: str_tk = "TK_" #a); break;
+        //SQ_KEYWORDS_LIST()
+        //#undef ENUM_TK
+        default:
+            str_tk = "()";
+        }
+        return str_tk;
+    }
+
+//private:
+    SQInteger GetIDType(const SQChar_ptr_t s,SQInteger len)
+    {
+	foreach(k,v in _keywords->_tbl)
+	{
+		if(k == s) return v;
+	}
+	    
+        SQObjectPtr t;
+        if(_keywords->GetStr(s,len, t))
+        {
+            return /*SQInteger(_integer(*/t/*))*/;
+        }
+        return TK_IDENTIFIER;
+    }
+
+    SQInteger ReadString(SQInteger ndelim,bool verbatim)
+    {
+        INIT_TEMP_STRING();
+        SQInteger start_equals = 0;
+        SQChar cdelim1, cdelim2;
+        if(ndelim == '{')
+        {
+            cdelim1 = '{';
+            cdelim2 = '}';
+        }
+        else if(ndelim == '(')
+        {
+            cdelim1 = '(';
+            cdelim2 = ')';
+        }
+        else
+        {
+            cdelim1 = '[';
+            cdelim2 = ']';
+        }
+        if(CUR_CHAR == '=')
+        {
+            //lua like literal
+            while(!IS_EOB() && CUR_CHAR == '=')
+            {
+                ++start_equals;
+                /*NEXT()*/{SQInteger rc = Next();if(rc < 0) return rc;_currentcolumn++;};
+            }
+            if(CUR_CHAR != cdelim1)
+            {
+                //it's not a lua literal delimiter
+                return Error("expect '%c' on literal delimiter", cdelim1);
+            }
+            ndelim = cdelim2;
+        }
+        /*NEXT()*/{SQInteger rc = Next();if(rc < 0) return rc;_currentcolumn++;};
+        if(IS_EOB()) return -1;
+        if(start_equals)
+        {
+            int cr_nl = CUR_CHAR == '\r';
+            if(cr_nl) /*NEXT()*/{SQInteger rc = Next();if(rc < 0) return rc;_currentcolumn++;};
+            cr_nl = CUR_CHAR == '\n';
+            if(cr_nl) /*NEXT()*/{SQInteger rc = Next();if(rc < 0) return rc;_currentcolumn++;};
+            if(cr_nl)  //if a new line follows the start of delimiter drop it
+            {
+                ++_currentline;
+                if(IS_EOB())
+                {
+                    return Error("unfinished string");
+                }
+            }
+        }
+        for(;;)
+        {
+            while(CUR_CHAR != ndelim)
+            {
+                SQInteger x = CUR_CHAR;
+                switch(x)
+                {
+                case SQUIRREL_EOB:
+                    return Error("unfinished string");
+                case '\n':
+                    if(!verbatim) return Error("newline in a constant");
+                    APPEND_CHAR(CUR_CHAR);
+                    /*NEXT()*/{SQInteger rc = Next();if(rc < 0) return rc;_currentcolumn++;};
+                    _currentline++;
+                    break;
+                case '\\':
+                    if(verbatim)
+                    {
+                        APPEND_CHAR('\\');
+                        /*NEXT()*/{SQInteger rc = Next();if(rc < 0) return rc;_currentcolumn++;};
+                    }
+                    else
+                    {
+                        /*NEXT()*/{SQInteger rc = Next();if(rc < 0) return rc;_currentcolumn++;};
+                        switch(CUR_CHAR)
+                        {
+                        case 'x':
+                        {
+                            /*const*/ SQInteger maxdigits = sizeof(SQChar) * 2;
+                            SQChar temp; //[maxdigits + 1];
+                            if(ProcessStringHexEscape(temp, maxdigits) < 0) return -1;
+                            SQChar_ptr_t stemp;
+                            APPEND_CHAR((SQChar)scstrtoul(temp, /*&*/stemp, 16));
+                        }
+                        break;
+                        case 'U':
+                        case 'u':
+                        {
+                            /*const*/ SQInteger maxdigits = x == 'u' ? 4 : 8;
+                            SQChar temp; //[8 + 1];
+                            if(ProcessStringHexEscape(temp, maxdigits) < 0) return -1;
+                            SQChar_ptr_t stemp;
+                            /*
+                            #ifdef SQUNICODE
+                            #if WCHAR_SIZE == 2
+                            			AddUTF16(scstrtoul(temp, &stemp, 16));
+                            #else
+                            			ADD_CHAR((SQChar)scstrtoul(temp, &stemp, 16));
+                            #endif
+                            #else
+                            */
+                            AddUTF8(scstrtoul(temp, /*&*/stemp, 16));
+                            //#endif
+                        }
+                        break;
+                        case 't':
+                            APPEND_CHAR('\t');
+                            /*NEXT()*/{SQInteger rc = Next();if(rc < 0) return rc;_currentcolumn++;};
+                            break;
+                        case 'a':
+                            APPEND_CHAR('\a');
+                            /*NEXT()*/{SQInteger rc = Next();if(rc < 0) return rc;_currentcolumn++;};
+                            break;
+                        case 'b':
+                            APPEND_CHAR('\b');
+                            /*NEXT()*/{SQInteger rc = Next();if(rc < 0) return rc;_currentcolumn++;};
+                            break;
+                        case 'n':
+                            APPEND_CHAR('\n');
+                            /*NEXT()*/{SQInteger rc = Next();if(rc < 0) return rc;_currentcolumn++;};
+                            break;
+                        case 'r':
+                            APPEND_CHAR('\r');
+                            /*NEXT()*/{SQInteger rc = Next();if(rc < 0) return rc;_currentcolumn++;};
+                            break;
+                        case 'v':
+                            APPEND_CHAR('\v');
+                            /*NEXT()*/{SQInteger rc = Next();if(rc < 0) return rc;_currentcolumn++;};
+                            break;
+                        case 'f':
+                            APPEND_CHAR('\f');
+                            /*NEXT()*/{SQInteger rc = Next();if(rc < 0) return rc;_currentcolumn++;};
+                            break;
+                        case '0':
+                            APPEND_CHAR('\0');
+                            /*NEXT()*/{SQInteger rc = Next();if(rc < 0) return rc;_currentcolumn++;};
+                            break;
+                        case '\\':
+                            APPEND_CHAR('\\');
+                            /*NEXT()*/{SQInteger rc = Next();if(rc < 0) return rc;_currentcolumn++;};
+                            break;
+                        case '"':
+                            APPEND_CHAR('"');
+                            /*NEXT()*/{SQInteger rc = Next();if(rc < 0) return rc;_currentcolumn++;};
+                            break;
+                        case '\'':
+                            APPEND_CHAR('\'');
+                            /*NEXT()*/{SQInteger rc = Next();if(rc < 0) return rc;_currentcolumn++;};
+                            break;
+                        default:
+                            return Error("unrecognised escaper char");
+                            break;
+                        }
+                    }
+                    break;
+                default:
+                    APPEND_CHAR(CUR_CHAR);
+                    /*NEXT()*/{SQInteger rc = Next();if(rc < 0) return rc;_currentcolumn++;};
+                }
+            }
+            /*NEXT()*/{SQInteger rc = Next();if(rc < 0) return rc;_currentcolumn++;};
+            if(start_equals)
+            {
+                bool lastBraceAdded = false;
+                if(CUR_CHAR == '=')
+                {
+                    SQInteger end_equals = start_equals;
+                    /*NEXT()*/{SQInteger rc = Next();if(rc < 0) return rc;_currentcolumn++;};
+                    if(CUR_CHAR == '=' || CUR_CHAR == cdelim2)
+                    {
+                        --end_equals;
+                        while(!IS_EOB() && CUR_CHAR == '=')
+                        {
+                            --end_equals;
+                            /*NEXT()*/{SQInteger rc = Next();if(rc < 0) return rc;_currentcolumn++;};
+                        }
+                        if(end_equals) return Error("expect same number of '=' on literal delimiter");
+                        if(CUR_CHAR != cdelim2) return Error("expect '%c' to close literal delimiter", cdelim2);
+                        /*NEXT()*/{SQInteger rc = Next();if(rc < 0) return rc;_currentcolumn++;};
+                        break;
+                    }
+                    APPEND_CHAR(cdelim2); //the first NEXT() after break the while loop
+                    APPEND_CHAR('=');
+                    lastBraceAdded = true;
+                }
+                if(!lastBraceAdded) APPEND_CHAR(cdelim2); //the first NEXT() after break the while loop
+                APPEND_CHAR(CUR_CHAR);
+                /*NEXT()*/{SQInteger rc = Next();if(rc < 0) return rc;_currentcolumn++;};
+            }
+            else if(verbatim && CUR_CHAR == '"')   //double quotation
+            {
+                APPEND_CHAR(CUR_CHAR);
+                /*NEXT()*/{SQInteger rc = Next();if(rc < 0) return rc;_currentcolumn++;};
+            }
+            else
+            {
+                break;
+            }
+        }
+        TERMINATE_BUFFER();
+        SQInteger len = _longstr.size()/*-1*/;
+        if(ndelim == '\'')
+        {
+            if(len == 0) return Error("empty constant");
+            if(len > 1) return Error("constant too long");
+            _nvalue = _longstr.tostring()/*[0]*/;
+            return TK_INTEGER;
+        }
+        _svalue = /*&*/_longstr.tostring()/*[0]*/;
+        return TK_STRING_LITERAL;
+    }
+
+    //#define MAX_HEX_DIGITS (sizeof(SQInteger)*2)
+    SQInteger ReadNumber()
+    {
+        //#define TINT 1
+        //#define TFLOAT 2
+        //#define THEX 3
+        //#define TSCIENTIFIC 4
+        //#define TOCTAL 5
+        SQInteger type = TINT, firstchar = CUR_CHAR;
+        SQUnsignedInteger itmp=0;
+        SQChar_ptr_t sTemp;
+        INIT_TEMP_STRING();
+        /*NEXT()*/{SQInteger rc = Next();if(rc < 0) return rc;_currentcolumn++;};
+        if(firstchar == '0' && (sctoupper(CUR_CHAR) == 'X' || scisodigit(CUR_CHAR)) )
+        {
+            if(scisodigit(CUR_CHAR))
+            {
+                type = TOCTAL;
+                while(scisodigit(CUR_CHAR))
+                {
+                    APPEND_CHAR(CUR_CHAR);
+                    /*NEXT()*/{SQInteger rc = Next();if(rc < 0) return rc;_currentcolumn++;};
+                }
+                if(scisdigit(CUR_CHAR)) return Error("invalid octal number");
+            }
+            else
+            {
+                /*NEXT()*/{SQInteger rc = Next();if(rc < 0) return rc;_currentcolumn++;};
+                type = THEX;
+                while(scisxdigit(CUR_CHAR))
+                {
+                    APPEND_CHAR(CUR_CHAR);
+                    /*NEXT()*/{SQInteger rc = Next();if(rc < 0) return rc;_currentcolumn++;};
+                }
+                if(_longstr.size() > MAX_HEX_DIGITS) return Error("too many digits for an Hex number");
+            }
+        }
+        else
+        {
+            APPEND_CHAR(/*(int)*/firstchar);
+            while (CUR_CHAR == '.' || scisdigit(CUR_CHAR) || isexponent(CUR_CHAR))
+            {
+                if(CUR_CHAR == '.' || isexponent(CUR_CHAR)) type = TFLOAT;
+                if(isexponent(CUR_CHAR))
+                {
+                    if(type != TFLOAT) return Error("invalid numeric format");
+                    type = TSCIENTIFIC;
+                    APPEND_CHAR(CUR_CHAR);
+                    /*NEXT()*/{SQInteger rc = Next();if(rc < 0) return rc;_currentcolumn++;};
+                    if(CUR_CHAR == '+' || CUR_CHAR == '-')
+                    {
+                        APPEND_CHAR(CUR_CHAR);
+                        /*NEXT()*/{SQInteger rc = Next();if(rc < 0) return rc;_currentcolumn++;};
+                    }
+                    if(!scisdigit(CUR_CHAR)) return Error("exponent expected");
+                }
+
+                APPEND_CHAR(CUR_CHAR);
+                /*NEXT()*/{SQInteger rc = Next();if(rc < 0) return rc;_currentcolumn++;};
+            }
+        }
+        TERMINATE_BUFFER();
+        switch(type)
+        {
+        case TSCIENTIFIC:
+        case TFLOAT:
+            _fvalue = /*(SQFloat)*/scstrtod(/*&*/_longstr.tostring()/*[0]*/,/*&*/sTemp);
+            return TK_FLOAT;
+        case TINT:
+            itmp = LexInteger(/*&*/_longstr.tostring()/*[0]*/,/*&*/itmp);
+            break;
+        case THEX:
+            itmp = LexHexadecimal(/*&*/_longstr.tostring()/*[0]*/,/*&*/itmp);
+            break;
+        case TOCTAL:
+            itmp = LexOctal(/*&*/_longstr.tostring()/*[0]*/,/*&*/itmp);
+            break;
+        }
+        switch(type)
+        {
+        case TINT:
+        case THEX:
+        case TOCTAL:
+            //to allow 64 bits integers comment bellow
+            //if(itmp > INT_MAX) return Error("integer overflow %ulld %d"));
+            _nvalue = /*(SQInteger)*/ itmp;
+            return TK_INTEGER;
+        }
+        return 0;
+    }
+
+    SQInteger LexBlockComment()
+    {
+        /*
+            if(CUR_CHAR == '*')
+            {
+        	NEXT();
+        	if(CUR_CHAR != '*'){ //document comment
+        	    printf("Doument comment found at line %d\n", _currentline);
+        	}
+            }
+        */
+        bool done = false;
+        if(_want_comments) INIT_TEMP_STRING();
+        /*NEXT()*/{SQInteger rc = Next();if(rc < 0) return rc;_currentcolumn++;}; //remove the comment token '*'
+        while(!done)
+        {
+            switch(CUR_CHAR)
+            {
+            case '*':
+            {
+                /*NEXT()*/{SQInteger rc = Next();if(rc < 0) return rc;_currentcolumn++;};
+                if(CUR_CHAR == '/')
+                {
+                    done = true;
+                    /*NEXT()*/{SQInteger rc = Next();if(rc < 0) return rc;_currentcolumn++;};
+                    continue;
+                }
+            };
+            break;
+            case '\n':
+                _currentline++;
+                break;
+            case SQUIRREL_EOB:
+                return Error("missing \"*/\" in comment");
+            }
+            if(_want_comments) APPEND_CHAR(CUR_CHAR);
+            /*NEXT()*/{SQInteger rc = Next();if(rc < 0) return rc;_currentcolumn++;};
+        }
+        if(_want_comments)
+        {
+            TERMINATE_BUFFER();
+            if(_longstr.size() > 0) _longstr./*pop_back()*/setLen(_longstr.size()-1); //remove the last '*'
+            _svalue = /*&*/_longstr.tostring()/*[0]*/;
+        }
+        return 0;
+    }
+
+    SQInteger LexLineComment()
+    {
+        if(_want_comments) INIT_TEMP_STRING();
+        /*NEXT()*/{SQInteger rc = Next();if(rc < 0) return rc;_currentcolumn++;}; //remove the comment token
+        while (CUR_CHAR != '\n' && (!IS_EOB()))
+        {
+            if(_want_comments) APPEND_CHAR(CUR_CHAR);
+            /*NEXT()*/{SQInteger rc = Next();if(rc < 0) return rc;_currentcolumn++;};
+        }
+        if(_want_comments)
+        {
+            TERMINATE_BUFFER();
+            _svalue = /*&*/_longstr.tostring()/*[0]*/;
+        }
+        return 0;
+    }
+
+    SQInteger ReadID()
+    {
+        SQInteger res;
+        INIT_TEMP_STRING();
+        do
+        {
+            APPEND_CHAR(CUR_CHAR);
+            /*NEXT()*/{SQInteger rc = Next();if(rc < 0) return rc;_currentcolumn++;};
+        }
+        while(scisalnum(CUR_CHAR) || CUR_CHAR == '_');
+        TERMINATE_BUFFER();	
+        res = GetIDType(/*&*/_longstr.tostring()/*[0]*/,_longstr.size() - 1);
+        if(res == TK_IDENTIFIER || res == TK_CONSTRUCTOR || res == TK_DESTRUCTOR)
+        {
+            _svalue = /*&*/_longstr.tostring()/*[0]*/;
+        }
+        return res;
+    }
+
+    SQInteger Next()
+    {
+        SQInteger t = _readf(_up);
+        if(t > MAX_CHAR) return Error("Invalid character");
+        if(t != 0)
+        {
+            CUR_CHAR = _currdata = /*(LexChar)*/t;
+            return 0;
+        }
+        CUR_CHAR = _currdata = SQUIRREL_EOB;
+        _reached_eof = SQTrue;
+        return 0;
+    }
+
+    /*
+    #ifdef SQUNICODE
+    #if WCHAR_SIZE == 2
+        SQInteger AddUTF16(SQUnsignedInteger ch);
+    #endif
+    #else
+        SQInteger AddUTF8(SQUnsignedInteger ch);
+    #endif
+    */
+    SQInteger AddUTF8(SQUnsignedInteger ch)
+    {
+        if (ch < 0x80)
+        {
+            APPEND_CHAR((char)ch);
+            return 1;
+        }
+        if (ch < 0x800)
+        {
+            APPEND_CHAR((SQChar)((ch >> 6) | 0xC0));
+            APPEND_CHAR((SQChar)((ch & 0x3F) | 0x80));
+            return 2;
+        }
+        if (ch < 0x10000)
+        {
+            APPEND_CHAR((SQChar)((ch >> 12) | 0xE0));
+            APPEND_CHAR((SQChar)(((ch >> 6) & 0x3F) | 0x80));
+            APPEND_CHAR((SQChar)((ch & 0x3F) | 0x80));
+            return 3;
+        }
+        if (ch < 0x110000)
+        {
+            APPEND_CHAR((SQChar)((ch >> 18) | 0xF0));
+            APPEND_CHAR((SQChar)(((ch >> 12) & 0x3F) | 0x80));
+            APPEND_CHAR((SQChar)(((ch >> 6) & 0x3F) | 0x80));
+            APPEND_CHAR((SQChar)((ch & 0x3F) | 0x80));
+            return 4;
+        }
+        return 0;
+    }
+
+    SQInteger ProcessStringHexEscape(SQChar_ptr_t dest, SQInteger maxdigits)
+    {
+        /*NEXT()*/{SQInteger rc = Next();if(rc < 0) return rc;_currentcolumn++;};
+        if (!isxdigit(CUR_CHAR)) return Error("hexadecimal number expected");
+        SQInteger n = 0;
+        while (isxdigit(CUR_CHAR) && n < maxdigits)
+        {
+            dest[n] = CUR_CHAR;
+            n++;
+            /*NEXT()*/{SQInteger rc = Next();if(rc < 0) return rc;_currentcolumn++;};
+        }
+        dest[n] = 0;
+        return n;
+    }
+
+    SQInteger _curtoken;
+    SQTable_ptr_t _keywords;
+    SQBool _reached_eof;
+//public:
+    SQInteger _prevtoken;
+    SQInteger _currentline;
+    SQInteger _lasttokenline;
+    SQInteger _lasttokencolumn;
+    SQInteger _currentcolumn;
+    /*const*/ SQChar_ptr_t _svalue;
+    SQInteger _nvalue;
+    SQFloat _fvalue;
+    SQLEXREADFUNC _readf;
+    SQUserPointer _up;
+    LexChar _currdata;
+    SQSharedState_ptr_t _sharedstate;
+    sqvector_SQChar _longstr;
+    CompilerErrorFunc _errfunc;
+    void_ptr_t _errtarget;
+    SQChar_ptr_t _lasterror/*[256]*/;
+    SQBool _want_comments;
+};
+
+SQSharedState ss;
+SQUserPointer up;
+CompilerErrorFunc efunc;
+void_ptr_t ed;
+
+string_t cpp_code = readfile(__FILE__);
+print(__FILE__, cpp_code.len());
+//cpp_code = "int main(){return 0;}";
+
+FILE source = FILE(cpp_code);
+
+SQLexerNut lex = SQLexerNut();
+lex.Init(ss, compilerReadFunc, source, efunc, ed, SQTrue);
+
+int_t tok;
+
+double_t start_time = os.clock();
+while((tok = lex.Lex()) > 0)
+{
+	//printf("Token = %d\n", tok);
+
+	string_t tkstr;
+	if(tok > TK_FIRST_ENUM_TOKEN && tok < TK_LAST_ENUM_TOKEN) tkstr = lex.Tok2Str(tok);
+	else tkstr = tok.tochar();
+	
+	print(
+		tok,
+		tkstr || "",
+		lex.GetTokenName(tok),
+		lex._svalue || "",
+		lex._nvalue,
+		//lex._lasttokenline,
+		//lex._lasttokencolumn,
+		lex._currentline,
+		lex._currentcolumn
+		);
+
+}
+
+print("Time spent", os.clock() - start_time);

+ 2517 - 0
SquiLu/samples/sqparser.nut

@@ -0,0 +1,2517 @@
+const TK_FIRST_ENUM_TOKEN = 258;
+const TK_3WAYSCMP = 259;
+const TK_AND = 260;
+const TK_ARROW = 261;
+const TK_AS = 262;
+const TK_ATTR_CLOSE = 263;
+const TK_ATTR_OPEN = 264;
+const TK_BASE = 265;
+const TK_BIT_AND_EQ = 266;
+const TK_BIT_OR_EQ = 267;
+const TK_BIT_SHIFT_LEFT_EQ = 268;
+const TK_BIT_SHIFT_RIGHT_EQ = 269;
+const TK_BIT_XOR_EQ = 270;
+const TK_BREAK = 271;
+const TK_CASE = 272;
+const TK_CATCH = 273;
+const TK_CLASS = 274;
+const TK_CLONE = 275;
+const TK_CONST = 276;
+const TK_COMMENT_BLOCK = 277;
+const TK_COMMENT_LINE = 278;
+const TK_CONSTRUCTOR = 279;
+const TK_CONTINUE = 280;
+const TK_DECLARE = 281;
+const TK_DEFAULT = 282;
+const TK_DELETE = 283;
+const TK_DESTRUCTOR = 284;
+const TK_DIVEQ = 285;
+const TK_DO = 286;
+const TK_DOUBLE_COLON = 287;
+const TK_ELSE = 288;
+const TK_ENUM = 289;
+const TK_EQ = 290;
+const TK_EQ_IDENTITY = 291;
+const TK_EXTENDS = 292;
+const TK_EXTERN = 293;
+const TK_FALSE = 294;
+const TK___FILE__ = 295;
+const TK_FLOAT = 296;
+const TK_FOR = 297;
+const TK_FOREACH = 298;
+const TK_FRIEND = 299;
+const TK___FUNCTION__ = 300;
+const TK_FUNCTION = 301;
+const TK_GE = 302;
+const TK_IDENTIFIER = 303;
+const TK_IF = 304;
+const TK_IGNORE = 305;
+const TK_IN = 306;
+const TK_INSTANCEOF = 307;
+const TK_INTEGER = 308;
+const TK_LE = 309;
+const TK___LINE__ = 310;
+const TK_LOCAL = 311;
+const TK_LOCAL_ANY_T = 312;
+const TK_LOCAL_ARRAY_T = 313;
+const TK_LOCAL_BOOL_T = 314;
+const TK_LOCAL_CHAR_T = 315;
+const TK_LOCAL_DOUBLE_T = 316;
+const TK_LOCAL_FLOAT_T = 317;
+const TK_LOCAL_INT16_T = 318;
+const TK_LOCAL_INT32_T = 319;
+const TK_LOCAL_INT64_T = 320;
+const TK_LOCAL_INT8_T = 321;
+const TK_LOCAL_INT_T = 322;
+const TK_LOCAL_LONG_DOUBLE_T = 323;
+const TK_LOCAL_NUMBER_T = 324;
+const TK_LOCAL_SIZE_T = 325;
+const TK_LOCAL_SSIZE_T = 326;
+const TK_LOCAL_STRING_T = 327;
+const TK_LOCAL_TABLE_T = 328;
+const TK_LOCAL_UINT16_T = 329;
+const TK_LOCAL_UINT32_T = 330;
+const TK_LOCAL_UINT64_T = 331;
+const TK_LOCAL_UINT8_T = 332;
+const TK_LOCAL_UINT_T = 333;
+const TK_LOCAL_VOIDPTR_T = 334;
+const TK_LOCAL_WCHAR_T = 335;
+const TK_LOCAL_WEAKREF_T = 336;
+const TK_MINUSEQ = 337;
+const TK_MINUSMINUS = 338;
+const TK_MODEQ = 339;
+const TK_MODULO = 340;
+const TK_MULEQ = 341;
+const TK_NE = 342;
+const TK_NE_IDENTITY = 343;
+const TK_NEWSLOT = 344;
+const TK_NOEXCEPT = 345;
+const TK_NULL = 346;
+const TK_OR = 347;
+const TK_PLUSEQ = 348;
+const TK_PLUSPLUS = 349;
+const TK_PRAGMA = 350;
+const TK_PRIVATE = 351;
+const TK_PUBLIC = 352;
+const TK_RESUME = 353;
+const TK_RETURN = 354;
+const TK_SHIFTL = 355;
+const TK_SHIFTR = 356;
+const TK_STATIC = 357;
+const TK_STRING_LITERAL = 358;
+const TK_STRUCT = 359;
+const TK_SWITCH = 360;
+const TK_THIS = 361;
+const TK_THROW = 362;
+const TK_TYPEDEF = 363;
+const TK_TRUE = 364;
+const TK_TRY = 365;
+const TK_TYPEOF = 366;
+const TK_UMINUS = 367;
+const TK_UNSAFE = 368;
+const TK_USING = 369;
+const TK_USHIFTR = 370;
+const TK_VARPARAMS = 371;
+const TK_VIRTUAL = 372;
+const TK_VOID = 373;
+const TK_VOLATILE = 374;
+const TK_WHILE = 375;
+const TK_YIELD = 376;
+const TK_INLINE = 377;
+const TK_CONSTEXPR = 378;
+const TK_LAST_ENUM_TOKEN = 379;
+
+//typedefs to allow parse/compile
+typedef char_ptr_t SQChar_ptr_t;
+typedef class_t SQObject;
+typedef var_t SQObjectPtr;
+typedef bool_t bool;
+typedef int_t int;
+typedef int_t SQInteger;
+typedef class_t SQLex;
+typedef enum_t SQOpcode;
+typedef float_t SQFloat;
+typedef void_ptr_t SQObjectPtr_ptr_t;
+typedef class_t SQFuncState;
+typedef void_ptr_t SQFuncState_ptr_t;
+typedef class_t SQVM;
+typedef class_ptr_t SQVM_ptr_t;
+typedef struct_t jmp_buf;
+typedef array_t SQObjectPtrVec;
+typedef void_ptr_t SQUserPointer;
+typedef array_t SQInstructionVec;
+typedef param_t T;
+typedef func_ptr_t SQLEXREADFUNC;
+typedef class_ptr_t SQCompiler_ptr_t;
+typedef void_ptr_t va_list;
+typedef enum_t SQObjectType;
+
+
+//const SQUIRREL_VERSION	= _SC("SquiLu based on Squirrel 3.1 stable and Lua 5.1.5");
+//const SQUIRREL_COPYRIGHT	= _SC("Copyright (C) 2003-2016 Alberto Demichelis, Domingo Alvarez Duarte");
+//const SQUIRREL_AUTHOR	= _SC("Alberto Demichelis, Domingo Alvarez Duarte");
+const SQUIRREL_VERSION_NUMBER	= 310;
+
+const SQ_VMSTATE_IDLE			= 0;
+const SQ_VMSTATE_RUNNING		= 1;
+const SQ_VMSTATE_SUSPENDED	= 2;
+
+const SQUIRREL_EOB = 0;
+const SQ_BYTECODE_STREAM_TAG	= 0xFAFA;
+
+const SQOBJECT_REF_COUNTED	= 0x08000000;
+const SQOBJECT_NUMERIC		= 0x04000000;
+const SQOBJECT_DELEGABLE		= 0x02000000;
+const SQOBJECT_CANBEFALSE		= 0x01000000;
+
+const SQ_MATCHTYPEMASKSTRING = /*(*/-99999;
+
+const _RT_MASK = 0x00FFFFFF;
+//const _RAW_TYPE(type) (type&_RT_MASK);
+
+const _RT_NULL			= 0x00000001;
+const _RT_INTEGER			= 0x00000002;
+const _RT_FLOAT			= 0x00000004;
+const _RT_BOOL			= 0x00000008;
+const _RT_STRING			= 0x00000010;
+const _RT_TABLE			= 0x00000020;
+const _RT_ARRAY			= 0x00000040;
+const _RT_USERDATA		= 0x00000080;
+const _RT_CLOSURE			= 0x00000100;
+const _RT_NATIVECLOSURE	= 0x00000200;
+const _RT_GENERATOR		= 0x00000400;
+const _RT_USERPOINTER		= 0x00000800;
+const _RT_THREAD			= 0x00001000;
+const _RT_FUNCPROTO		= 0x00002000;
+const _RT_CLASS			= 0x00004000;
+const _RT_INSTANCE		= 0x00008000;
+const _RT_WEAKREF		= 0x00010000;
+const _RT_OUTER			= 0x00020000;
+
+/*
+//typedef 
+//enum tagSQObjectType {
+int_t OT_NULL =			(_RT_NULL|SQOBJECT_CANBEFALSE);
+int_t OT_INTEGER =		(_RT_INTEGER|SQOBJECT_NUMERIC|SQOBJECT_CANBEFALSE);
+int_t OT_FLOAT =			(_RT_FLOAT|SQOBJECT_NUMERIC|SQOBJECT_CANBEFALSE);
+int_t OT_BOOL =			(_RT_BOOL|SQOBJECT_CANBEFALSE);
+int_t OT_STRING =			(_RT_STRING|SQOBJECT_REF_COUNTED);
+int_t OT_TABLE =			(_RT_TABLE|SQOBJECT_REF_COUNTED|SQOBJECT_DELEGABLE);
+int_t OT_ARRAY =			(_RT_ARRAY|SQOBJECT_REF_COUNTED);
+int_t OT_USERDATA =		(_RT_USERDATA|SQOBJECT_REF_COUNTED|SQOBJECT_DELEGABLE);
+int_t OT_CLOSURE =		(_RT_CLOSURE|SQOBJECT_REF_COUNTED);
+int_t OT_NATIVECLOSURE =	(_RT_NATIVECLOSURE|SQOBJECT_REF_COUNTED);
+int_t OT_GENERATOR =		(_RT_GENERATOR|SQOBJECT_REF_COUNTED);
+int_t OT_USERPOINTER =	_RT_USERPOINTER;
+int_t OT_THREAD =			(_RT_THREAD|SQOBJECT_REF_COUNTED);
+int_t OT_FUNCPROTO =		(_RT_FUNCPROTO|SQOBJECT_REF_COUNTED); //internal usage only
+int_t OT_CLASS =			(_RT_CLASS|SQOBJECT_REF_COUNTED);
+int_t OT_INSTANCE =		(_RT_INSTANCE|SQOBJECT_REF_COUNTED|SQOBJECT_DELEGABLE);
+int_t OT_WEAKREF =		(_RT_WEAKREF|SQOBJECT_REF_COUNTED);
+int_t OT_OUTER =			(_RT_OUTER|SQOBJECT_REF_COUNTED); //internal usage only
+//}SQObjectType;
+*/
+
+const OT_NULL	= 1;
+const OT_INTEGER	= 2;
+const OT_FLOAT	= 3;
+const OT_BOOL	= 4;
+const OT_STRING	= 5;
+const OT_TABLE	= 6;
+const OT_ARRAY	= 7;
+const OT_USERDATA	= 8;
+const OT_CLOSURE	= 9;
+const OT_NATIVECLOSURE	= 10;
+const OT_GENERATOR	= 11;
+const OT_USERPOINTER	= 12;
+const OT_THREAD	= 13;
+const OT_FUNCPROTO	= 14;
+const OT_CLASS	= 15;
+const OT_INSTANCE	= 16;
+const OT_WEAKREF	= 17;
+const OT_OUTER	= 18;
+
+enum eFunctionType
+{
+    fn_global = 1,
+    fn_local,
+    fn_lambda,
+    fn_member,
+    fn_anonymous
+};
+
+const EXPR =  1;
+const OBJECT = 2;
+const BASE =  3;
+const LOCAL = 4;
+const OUTER = 5;
+const EXPR_STATEMENT = 6; //we start from statement state
+
+struct SQExpState
+{
+    SQInteger  etype;       /* expr. type; one of EXPR, OBJECT, BASE, OUTER, LOCAL or EXPR_STATEMENT */
+    SQInteger  epos;        /* expr. location on stack; -1 for OBJECT and BASE */
+    bool       donot_get;   /* signal not to deref the next value */
+};
+
+const MAX_COMPILER_ERROR_LEN = 256;
+
+struct SQScope
+{
+    SQInteger outers;
+    SQInteger stacksize;
+    SQInteger nested;
+};
+
+static SQInteger compilerReadFunc(SQUserPointer fp)
+{
+    SQInteger c = fgetc(/*(FILE *)*/fp);
+    if(c == EOF)
+    {
+        return 0;
+    }
+    return c;
+}
+
+class SQCompiler
+{
+//private:
+    SQInteger _token;
+    SQFuncState_ptr_t _fs;
+    SQObjectPtr _sourcename;
+    SQLex _lex;
+    bool _lineinfo;
+    bool _raiseerror;
+    bool _show_warnings;
+    bool _is_parsing_extern;
+    SQInteger _debugline;
+    SQInteger _debugop;
+    SQExpState   _es;
+    SQScope _scope;
+    SQChar_ptr_t _compilererror;
+    jmp_buf _errorjmp;
+    SQVM_ptr_t _vm;
+    SQObjectPtrVec _scope_consts;
+    SQObjectPtr _globals;
+    SQObjectPtr _type_names; //to allow C/C++ style instance declarations
+    SQObjectPtr _extern_names; //to allow C/C++ style extern declarations
+    //SQChar error_buf[MAX_COMPILER_ERROR_LEN];
+    SQInteger _max_nested_includes, _nested_includes_count;
+
+//public:
+
+    SQCompiler()
+    {
+        _vm=v;
+        _lex.Init(_ss(v), rg, up,ThrowError,this);
+        //_sourcename = SQString::Create(_ss(v), sourcename);
+        _lineinfo = lineinfo;
+        _raiseerror = raiseerror;
+        _show_warnings = show_warnings;
+        _scope.outers = 0;
+        _scope.stacksize = 0;
+        _scope.nested = 0;
+        _compilererror = NULL;
+        _globals = {}; //SQTable::Create(_ss(_vm),0);
+        _type_names = {}; //SQTable::Create(_ss(_vm),0);
+        _extern_names = {}; //SQTable::Create(_ss(_vm),0);
+        _max_nested_includes = max_nested_includes;
+        _nested_includes_count = 0;
+        _is_parsing_extern = false;
+    }
+    ~SQCompiler()
+    {
+        //_table(_globals)->Finalize();
+        //_globals.Null();
+    }
+
+    static void ThrowError(void_ptr_t ud, const SQChar_ptr_t s)
+    {
+        SQCompiler_ptr_t c = /*(SQCompiler *)*/ud;
+        c->Error(s);
+    }
+
+    void Error(const SQChar_ptr_t s, ...) //__attribute__((format(printf, 2, 3)))
+    {
+        va_list vl;
+        va_start(vl, s);
+        scvsprintf(error_buf, sizeof(error_buf), s, vl);
+        va_end(vl);
+        _compilererror = error_buf;
+        longjmp(_errorjmp,1);
+    }
+
+    void Warning(const SQChar_ptr_t s, ...) //__attribute__((format(printf, 2, 3)))
+    {
+        if(!_show_warnings) return;
+        va_list vl;
+        va_start(vl, s);
+        scvfprintf(stderr, s, vl);
+        va_end(vl);
+    }
+
+    bool CheckNameIsType(const SQObject &name)
+    {
+        return _table(_type_names)->Exists(name);
+    }
+
+    bool CheckTypeName(const SQObject &name, bool addIfNotExists=false)
+    {
+        bool found = _table(_type_names)->Exists(name);
+        if(addIfNotExists && !found)
+        {
+            SQObjectPtr oname = name, otrue = true;
+            _table(_type_names)->NewSlot(oname, otrue);
+        }
+        return found;
+    }
+
+    bool TypesGet(const SQObjectPtr &key,SQObjectPtr &val)
+    {
+        return _table(_type_names)->Get(key,val);
+    }
+
+    bool TypesNewSlot(const SQObjectPtr &key, const SQObjectPtr &val)
+    {
+        return _table(_type_names)->NewSlot(key,val);
+    }
+
+    int CheckExternName(const SQObject &name, bool addIfNotExists=false)
+    {
+        SQObjectPtr orefcount;
+        int found = _table(_extern_names)->Get(name, orefcount);
+        if(addIfNotExists && !found)
+        {
+            SQObjectPtr oname = name;
+            //_integer(orefcount) = 1; //1 means only declared, 2 declared and assigned
+            _table(_extern_names)->NewSlot(oname, orefcount);
+            _table(_globals)->NewSlot(oname, orefcount);
+        }
+        return found ? _integer(orefcount) : 0;
+    }
+
+    int ExternNameSetRefCount(const SQObject &name)
+    {
+        int ref_count = CheckExternName(name);
+        if(ref_count == 1)
+        {
+            SQObjectPtr orefcount;
+            //_integer(orefcount) = ref_count = 2;
+            _table(_extern_names)->Set(name, orefcount);
+        }
+        return ref_count;
+    }
+
+    void AddGlobalName(const SQObject &name)
+    {
+        SQObjectPtr oname = name, otrue = true;
+        _table(_globals)->NewSlot(oname, otrue);
+    }
+
+    void CheckGlobalName(const SQObject &name, bool addIfNotExists=false, bool checkLocals=true)
+    {
+        /*const*/ SQChar_ptr_t found = NULL;
+        if(CheckExternName(name))
+        {
+            found = _SC("extern");
+        }
+        else if(_table(_globals)->Exists(name))
+        {
+            found = _SC("global");
+        }
+        if(found)
+        {
+            if(checkLocals) Error(_SC("%s '%s' already declared"), found, _stringval(name));
+            else Warning(_SC("%s:%d:%d warning %s '%s' already declared will be shadowed\n"),
+                             _stringval(_sourcename), _lex._currentline, _lex._currentcolumn,
+                             found, _stringval(name));
+        }
+        else if(checkLocals) CheckLocalNameScope(name, -1, false);
+        if(addIfNotExists)
+        {
+            AddGlobalName(name);
+        }
+    }
+
+    void CheckLocalNameScope(const SQObject &name, SQInteger scope, bool checkGlobals=true)
+    {
+        SQInteger found = _fs->GetLocalVariable(name);
+        if(found >= 0)
+        {
+            SQLocalVarInfo &lvi = _fs->_vlocals[found];
+            if(lvi._scope == scope)
+                Error(_SC("local '%s' already declared"), _stringval(name));
+            else
+                Warning(_SC("%s:%d:%d warning local '%s' already declared will be shadowed\n"),
+                        _stringval(_sourcename), _lex._currentline, _lex._currentcolumn, _stringval(name));
+        }
+        else
+        {
+            found = _fs->FindOuterVariable(name);
+            if(found >= 0) Warning(_SC("%s:%d:%d warning outer variable '%s' already declared will be shadowed\n"),
+                                       _stringval(_sourcename), _lex._currentline, _lex._currentcolumn, _stringval(name));
+        }
+        if(checkGlobals) CheckGlobalName(name, false, false);
+        SQObjectPtr strongid = name;
+        CheckConstsExists(strongid);
+    }
+
+    bool IsConstant(const SQObject &name,SQObject &e)
+    {
+        SQObjectPtr val;
+        for(int i=_scope.nested-1; i >= 0; --i)
+        {
+            if(_table(_scope_consts[i])->Get(name,val))
+            {
+                e = val;
+                return true;
+            }
+        }
+        if(_table(_ss(_vm)->_consts)->Get(name,val))
+        {
+            e = val;
+            return true;
+        }
+        return false;
+    }
+
+    SQInteger ExpressionConstant(SQObject id)
+    {
+        SQObject constant;
+        SQInteger epos;
+        if(IsConstant(id, constant))
+        {
+            /* Handle named constant */
+            SQObjectPtr constval;
+            SQObject    constid;
+            if(type(constant) == OT_TABLE)
+            {
+                Expect('.');
+                constid = Expect(TK_IDENTIFIER);
+                if(!_table(constant)->Get(constid, constval))
+                {
+                    constval.Null();
+                    Error(_SC("invalid constant [%s.%s]"), _stringval(id), _stringval(constid));
+                }
+            }
+            else
+            {
+                constval = constant;
+            }
+            epos = _fs->PushTarget();
+
+            /* generate direct or literal function depending on size */
+            SQObjectType ctype = type(constval);
+            switch(ctype)
+            {
+            case OT_INTEGER:
+                EmitLoadConstInt(_integer(constval),epos);
+                break;
+            case OT_FLOAT:
+                EmitLoadConstFloat(_float(constval),epos);
+                break;
+            default:
+                _fs->AddInstruction(_OP_LOAD,epos,_fs->GetConstant(constval));
+                break;
+            }
+        }
+        else
+        {
+            Error(_SC("invalid constant [%s]"), _stringval(id));
+        }
+        return epos;
+    }
+
+    void CheckConstsExists(const SQObjectPtr &key)
+    {
+        int found = -1;
+        for(int i=_scope.nested-1; i >= 0; --i)
+        {
+            if(_table(_scope_consts[i])->Exists(key))
+            {
+                found = i+1;
+                break;
+            }
+        }
+        if(found < 0 && _table(_ss(_vm)->_consts)->Exists(key)) found = 0;
+        if(found == _scope.nested)
+        {
+            Error(_SC("constant '%s' already exists\n"), _stringval(key));
+        }
+        if(found >= 0) Warning(_SC("%s:%d:%d warning an already defined constant '%s' will be shadowed\n"),
+                                   _stringval(_sourcename), _lex._currentline, _lex._currentcolumn,  _stringval(key));
+    }
+
+    bool ConstsGet(const SQObjectPtr &key,SQObjectPtr &val)
+    {
+        for(int i=_scope.nested-1; i >= 0; --i)
+        {
+            if(_table(_scope_consts[i])->Get(key,val)) return true;
+        }
+        return _table(_ss(_vm)->_consts)->Get(key,val);
+    }
+
+    bool ConstsNewSlot(const SQObjectPtr &key, const SQObjectPtr &val)
+    {
+        if(_scope.nested) return _table(_scope_consts[_scope.nested-1])->NewSlot(key,val);
+        return _table(_ss(_vm)->_consts)->NewSlot(key,val);
+    }
+
+    void Lex()
+    {
+        _token = _lex.Lex();
+    }
+
+    SQObjectPtr GetTokenObject(SQInteger tok)
+    {
+        SQObjectPtr ret;
+        switch(tok)
+        {
+        case TK_IDENTIFIER:
+            ret = _fs->CreateString(_lex._svalue);
+            break;
+        case TK_STRING_LITERAL:
+            ret = _fs->CreateString(_lex._svalue,_lex._longstr.size()-1);
+            break;
+        case TK_INTEGER:
+            ret = SQObjectPtr(_lex._nvalue);
+            break;
+        case TK_FLOAT:
+            ret = SQObjectPtr(_lex._fvalue);
+            break;
+        default:
+            ret = _fs->CreateString(_lex.GetTokenName(_token));
+        }
+        Lex();
+        return ret;
+    }
+
+    void ErrorIfNotToken(SQInteger tok)
+    {
+        if(_token != tok)
+        {
+            if(((_token == TK_CONSTRUCTOR) || (_token == TK_DESTRUCTOR)) && tok == TK_IDENTIFIER)
+            {
+                //do nothing
+            }
+            else
+            {
+                /*const*/ SQChar_ptr_t etypename;
+                if(tok > 255)
+                {
+                    switch(tok)
+                    {
+                    case TK_IDENTIFIER:
+                        etypename = _SC("IDENTIFIER");
+                        break;
+                    case TK_STRING_LITERAL:
+                        etypename = _SC("STRING_LITERAL");
+                        break;
+                    case TK_INTEGER:
+                        etypename = _SC("INTEGER");
+                        break;
+                    case TK_FLOAT:
+                        etypename = _SC("FLOAT");
+                        break;
+                    default:
+                        etypename = _lex.Tok2Str(tok);
+                    }
+                    Error(_SC("expected '%s'"), etypename);
+                }
+                Error(_SC("expected '%c'"), tok);
+            }
+        }
+    }
+
+    SQObject Expect(SQInteger tok)
+    {
+        ErrorIfNotToken(tok);
+        return GetTokenObject(tok);
+    }
+
+    SQObject ExpectTypeToken()
+    {
+        switch(_token)
+        {
+        //CASE_TK_LOCAL_TYPES:
+        case TK_IDENTIFIER:
+            break;
+        default:
+            ErrorIfNotToken(TK_IDENTIFIER);
+        }
+        return GetTokenObject(TK_IDENTIFIER);
+    }
+
+    bool IsEndOfStatement()
+    {
+        return ((_lex._prevtoken == '\n') || (_token == SQUIRREL_EOB) || (_token == '}') || (_token == ';'));
+    }
+
+    void OptionalSemicolon()
+    {
+        if(_token == ';')
+        {
+            Lex();
+            return;
+        }
+        if(!IsEndOfStatement())
+        {
+            Error(_SC("end of statement expected (; or lf) found (%d)"), _token);
+        }
+    }
+
+    void MoveIfCurrentTargetIsLocal()
+    {
+        SQInteger trg = _fs->TopTarget();
+        if(_fs->IsLocal(trg))
+        {
+            trg = _fs->PopTarget(); //pops the target and moves it
+            _fs->AddInstruction(_OP_MOVE, _fs->PushTarget(), trg);
+        }
+    }
+
+    void Pragma()
+    {
+        int line = _lex._currentline;
+        //int column = _lex._currentcolumn;
+        Lex();
+        SQObject id = Expect(TK_IDENTIFIER);
+        if(scstrcmp(_stringval(id), _SC("include")) == 0)
+        {
+//#if SQ_ENABLE_INCLUDES
+            SQInteger nested_count = _nested_includes_count + 1;
+            if((_max_nested_includes <= 0) || (nested_count > _max_nested_includes))
+            {
+                Error(_SC("Error: too many nested includes %d %s\n"), nested_count, _stringval(id));
+            }
+
+            id = Expect(TK_STRING_LITERAL);
+            //Warning(_SC("%s:%d:%d warning pragma include %s\n"),
+            //        _stringval(_sourcename), line, column, _stringval(id));
+
+            FILE *fp = scfopen(_stringval(id), "r");
+            if(fp != NULL)
+            {
+                //increment nested count
+                ++_nested_includes_count;
+                //save current source file and lex state
+                SQUserPointer saved_up = _lex._up; //current userpointer
+                SQLEXREADFUNC saved_readf = _lex._readf; //current readfunction
+                SQInteger saved_line = _lex._currentline;
+                SQInteger saved_column = _lex._currentcolumn;
+                SQInteger saved_curdata = _lex._currdata;
+                SQInteger saved_prevtoken = _lex._prevtoken;
+                SQInteger saved_token = _token;
+                SQObjectPtr saved_source_name = _sourcename;
+
+                //set new source file
+                _fs->_sourcename = id;
+                _sourcename = id;
+                _lex.ResetReader(compilerReadFunc, fp, 1);
+
+                //compile the include file
+                Lex();
+                while(_token > 0)
+                {
+                    Statement();
+                    if(_lex._prevtoken != '}' && _lex._prevtoken != ';') OptionalSemicolon();
+                }
+
+                //close file
+                fclose(fp);
+                //restore saved source file and lex state
+                _fs->_sourcename = saved_source_name;
+                _sourcename = saved_source_name;
+                _token = saved_token;
+                _lex._currdata = saved_curdata;
+                _lex._prevtoken = saved_prevtoken;
+                _lex._currentcolumn = saved_column;
+                _lex._currentline = saved_line;
+                _lex._readf = saved_readf;
+                _lex._up = saved_up;
+
+                --_nested_includes_count;
+                //done let's continue working
+
+            }
+            else
+            {
+                Error(_SC("Error: opening include file %s\n"), _stringval(id));
+            }
+//#else
+//                Error(_SC("Error: includes are not enabled\n"));
+//#endif
+        }
+        else
+        {
+            _lex._currentline = line;
+            Error(_SC("Error: unknown pragma %s\n"), _stringval(id));
+        }
+    }
+
+    bool Compile(SQObjectPtr &o)
+    {
+        _debugline = 1;
+        _debugop = 0;
+
+        //SQFuncState funcstate(_ss(_vm), NULL,ThrowError,this);
+        funcstate._name = SQString_Create(_ss(_vm), _SC("main"));
+        _fs = /*&*/funcstate;
+        _fs->AddParameter(_fs->CreateString(_SC("this")), _scope.nested+1);
+        _fs->AddParameter(_fs->CreateString(_SC("vargv")), _scope.nested+1);
+        _fs->_varparams = true;
+        _fs->_sourcename = _sourcename;
+
+        SQInteger stacksize = _fs->GetStackSize();
+        if(setjmp(_errorjmp) == 0)
+        {
+            Lex();
+            while(_token > 0)
+            {
+                Statement();
+                if(_lex._prevtoken != '}' && _lex._prevtoken != ';') OptionalSemicolon();
+            }
+            _fs->SetStackSize(stacksize);
+            _fs->AddLineInfos(_lex._currentline, _lineinfo, true);
+            _fs->AddInstruction(_OP_RETURN, 0xFF);
+            _fs->SetStackSize(0);
+            o =_fs->BuildProto();
+//#ifdef _DEBUG_DUMP
+//            _fs->Dump(_funcproto(o));
+//#endif
+        }
+        else
+        {
+            if(_raiseerror && _ss(_vm)->_compilererrorhandler)
+            {
+                _ss(_vm)->_compilererrorhandler(_vm, _compilererror, type(_sourcename) == OT_STRING?_stringval(_sourcename):_SC("unknown"),
+                                                _lex._currentline, _lex._currentcolumn);
+            }
+            _vm->_lasterror = SQString_Create(_ss(_vm), _compilererror, -1);
+            _vm->_lasterror_line = _lex._currentline;
+            _vm->_lasterror_column = _lex._currentcolumn;
+            return false;
+        }
+        return true;
+    }
+
+    void Statements()
+    {
+        while(_token != '}' && _token != TK_DEFAULT && _token != TK_CASE)
+        {
+            Statement();
+            if(_lex._prevtoken != '}' && _lex._prevtoken != ';') OptionalSemicolon();
+        }
+    }
+
+    void Statement(bool closeframe = true)
+    {
+        _es.etype = EXPR_STATEMENT;
+        SQObject id;
+        _fs->AddLineInfos(_lex._currentline, _lineinfo);
+        //start_again:
+        switch(_token)
+        {
+        case ';':
+            Lex();
+            break;
+        case TK_IF:
+            IfStatement();
+            break;
+        case TK_WHILE:
+            WhileStatement();
+            break;
+        case TK_DO:
+            DoWhileStatement();
+            break;
+        case TK_FOR:
+            ForStatement();
+            break;
+        case TK_FOREACH:
+            ForEachStatement();
+            break;
+        case TK_SWITCH:
+            SwitchStatement();
+            break;
+
+        case TK_LOCAL:
+            //case TK_CONST:
+            /*CASE_TK_LOCAL_TYPES:*/
+            LocalDeclStatement();
+            break;
+        case TK_RETURN:
+        case TK_YIELD:
+        {
+            SQOpcode op;
+            if(_token == TK_RETURN)
+            {
+                op = _OP_RETURN;
+            }
+            else
+            {
+                op = _OP_YIELD;
+                _fs->_bgenerator = true;
+            }
+            Lex();
+            if(!IsEndOfStatement())
+            {
+                SQInteger retexp = _fs->GetCurrentPos()+1;
+                CommaExpr(true);
+                if(op == _OP_RETURN && _fs->_traps > 0)
+                    _fs->AddInstruction(_OP_POPTRAP, _fs->_traps, 0);
+                _fs->_returnexp = retexp;
+                _fs->AddInstruction(op, 1, _fs->PopTarget(),_fs->GetStackSize());
+            }
+            else
+            {
+                if(op == _OP_RETURN && _fs->_traps > 0)
+                    _fs->AddInstruction(_OP_POPTRAP, _fs->_traps ,0);
+                _fs->_returnexp = -1;
+                _fs->AddInstruction(op, 0xFF,0,_fs->GetStackSize());
+            }
+            break;
+        }
+        case TK_BREAK:
+            if(_fs->_breaktargets.size() <= 0)Error(_SC("'break' has to be in a loop block"));
+            if(_fs->_breaktargets.top() > 0)
+            {
+                _fs->AddInstruction(_OP_POPTRAP, _fs->_breaktargets.top(), 0);
+            }
+            RESOLVE_OUTERS();
+            _fs->AddInstruction(_OP_JMP, 0, -1234);
+            _fs->_unresolvedbreaks.push_back(_fs->GetCurrentPos());
+            Lex();
+            break;
+        case TK_CONTINUE:
+            if(_fs->_continuetargets.size() <= 0)Error(_SC("'continue' has to be in a loop block"));
+            if(_fs->_continuetargets.top() > 0)
+            {
+                _fs->AddInstruction(_OP_POPTRAP, _fs->_continuetargets.top(), 0);
+            }
+            RESOLVE_OUTERS();
+            _fs->AddInstruction(_OP_JMP, 0, -1234);
+            _fs->_unresolvedcontinues.push_back(_fs->GetCurrentPos());
+            Lex();
+            break;
+        case TK_FUNCTION:
+            FunctionStatement();
+            break;
+        case TK_CLASS:
+        case TK_STRUCT:
+            ClassStatement();
+            break;
+        case TK_ENUM:
+            EnumStatement();
+            break;
+        case '{':
+        {
+            BEGIN_SCOPE();
+            Lex();
+            Statements();
+            Expect('}');
+            if(closeframe)
+            {
+                END_SCOPE();
+            }
+            else
+            {
+                END_SCOPE_NO_CLOSE();
+            }
+        }
+        break;
+        case TK_TRY:
+            TryCatchStatement();
+            break;
+        case TK_THROW:
+            Lex();
+            CommaExpr();
+            _fs->AddInstruction(_OP_THROW, _fs->PopTarget());
+            break;
+
+        case TK_CONST:
+        {
+            Lex();
+            id = Expect(TK_IDENTIFIER);
+            if(_token == ':')
+            {
+                //type specifier like typescript
+                Lex();
+                ExpectTypeToken(); //ignore for now
+            }
+            Expect('=');
+            SQObjectPtr strongid = id;
+            CheckLocalNameScope(id, _scope.nested);
+            //CheckConstsExists(strongid);
+            SQObject val = ExpectScalar();
+            OptionalSemicolon();
+            ConstsNewSlot(strongid,SQObjectPtr(val));
+        }
+        break;
+
+        case TK_INLINE: //accept and ignore
+        case TK_CONSTEXPR: //accept and ignore
+        case TK_FRIEND:
+        case TK_VOLATILE:
+            Lex();
+        //goto start_again;
+        case TK_STATIC:
+            if(_scope.nested)
+            {
+                Warning(_SC("%s:%d:%d warning static cualifier is ignored\n"),
+                        _stringval(_sourcename), _lex._currentline, _lex._currentcolumn);
+            }
+            Lex(); //ignore it only to allow run some C/C++ code
+            //goto start_again;
+
+        case TK_DECLARE: //parse as extern
+        case TK_EXTERN:
+            ExternDeclStatement();
+            break;
+
+        case TK_TYPEDEF:
+        {
+            Lex();
+            SQObject type_val = ExpectTypeToken();
+            id = ExpectTypeToken();
+            SQObjectPtr strongid = id;
+            CheckLocalNameScope(id, _scope.nested);
+            Expect(';');
+            TypesNewSlot(strongid,SQObjectPtr(type_val));
+        }
+        break;
+        case TK_USING:
+        {
+            Lex();
+            id = Expect(TK_IDENTIFIER);
+            Expect('=');
+            SQObjectPtr strongid = id;
+            CheckLocalNameScope(id, _scope.nested);
+            SQObject type_val = ExpectTypeToken();
+            Expect(';');
+            TypesNewSlot(strongid,SQObjectPtr(type_val));
+        }
+        break;
+
+        case TK_PRAGMA:
+            Pragma();
+            break;
+
+        case TK_UNSAFE:
+            Lex(); //ignore for now
+            //goto start_again;
+            break;
+
+        case TK_IDENTIFIER:
+            id = _fs->CreateString(_lex._svalue);
+            if(CheckTypeName(id)) //C/C++ type declaration;
+            {
+                LocalDeclStatement();
+                break;
+            }
+
+        default:
+            CommaExpr();
+            _fs->DiscardTarget();
+            /*
+            //Fagiano says that this is not a bug
+            //and with this modification stack grow by one lement all the time
+                        if(_token == TK_IDENTIFIER){
+                            CommaExpr();
+                            if(_token == TK_IDENTIFIER){
+                                Error(_SC(" '=' expected near '%s'"), _lex._svalue);
+                            }
+                        }
+            */
+            //_fs->PopTarget();
+            break;
+        }
+        _fs->SnoozeOpt();
+    }
+
+    void EmitDerefOp(SQOpcode op)
+    {
+        SQInteger val = _fs->PopTarget();
+        SQInteger key = _fs->PopTarget();
+        SQInteger src = _fs->PopTarget();
+        _fs->AddInstruction(op,_fs->PushTarget(),src,key,val);
+    }
+
+    void Emit2ArgsOP(SQOpcode op, SQInteger p3 = 0)
+    {
+        SQInteger p2 = _fs->PopTarget(); //src in OP_GET
+        SQInteger p1 = _fs->PopTarget(); //key in OP_GET
+        _fs->AddInstruction(op,_fs->PushTarget(), p1, p2, p3);
+    }
+
+    void EmitCompoundArith(SQInteger tok, SQInteger etype, SQInteger pos)
+    {
+        /* Generate code depending on the expression type */
+        switch(etype)
+        {
+        case LOCAL:
+        {
+            SQInteger p2 = _fs->PopTarget(); //src in OP_GET
+            SQInteger p1 = _fs->PopTarget(); //key in OP_GET
+            _fs->PushTarget(p1);
+            //EmitCompArithLocal(tok, p1, p1, p2);
+            _fs->AddInstruction(ChooseArithOpByToken(tok),p1, p2, p1, 0);
+            _fs->SnoozeOpt(); //FIX: stop optimizer in retargeting opcode
+        }
+        break;
+        case OBJECT:
+        case BASE:
+        {
+            SQInteger val = _fs->PopTarget();
+            SQInteger key = _fs->PopTarget();
+            SQInteger src = _fs->PopTarget();
+            /* _OP_COMPARITH mixes dest obj and source val in the arg1 */
+            _fs->AddInstruction(_OP_COMPARITH, _fs->PushTarget(), (src<<16)|val, key, ChooseCompArithCharByToken(tok));
+        }
+        break;
+        case OUTER:
+        {
+            SQInteger val = _fs->TopTarget();
+            SQInteger tmp = _fs->PushTarget();
+            _fs->AddInstruction(_OP_GETOUTER,   tmp, pos);
+            _fs->AddInstruction(ChooseArithOpByToken(tok), tmp, val, tmp, 0);
+            _fs->PopTarget();
+            _fs->PopTarget();
+            _fs->AddInstruction(_OP_SETOUTER, _fs->PushTarget(), pos, tmp);
+        }
+        break;
+        }
+    }
+
+    void CommaExpr(bool warningAssign=false)
+    {
+        //for(Expression(warningAssign); _token == ','; _fs->PopTarget(), Lex(), CommaExpr(warningAssign));
+    }
+
+    void ErrorIfConst()
+    {
+        SQLocalVarInfo &vsrc = _fs->_vlocals[_fs->TopTarget()];
+//printf("%d %d %d %d %s\n", __LINE__, vsrc._scope, vsrc._type, vsrc._pos, vsrc._name._unVal.pString ? _stringval(vsrc._name) : "?");
+        if(vsrc._type & _VAR_CONST) Error(_SC("can't assign to a const variable"));
+    }
+
+    void Expression(bool warningAssign=false)
+    {
+        SQExpState es = _es;
+        _es.etype     = EXPR;
+        _es.epos      = -1;
+        _es.donot_get = false;
+        SQObject id;
+        if((_token == TK_IDENTIFIER) && (es.etype == EXPR_STATEMENT))
+        {
+            id = _fs->CreateString(_lex._svalue);
+        }
+        //else id = {}; //old compilers do not allow this
+
+        LogicalOrExp();
+        switch(_token)
+        {
+        case '=':
+        case TK_NEWSLOT:
+        case TK_MINUSEQ:
+        case TK_PLUSEQ:
+        case TK_MULEQ:
+        case TK_DIVEQ:
+        case TK_MODEQ:
+        {
+            SQInteger op = _token;
+            SQInteger ds = _es.etype;
+            SQInteger pos = _es.epos;
+
+            if(ds == EXPR) Error(_SC("can't assign expression"));
+            else if(ds == BASE) Error(_SC("'base' cannot be modified"));
+            Lex();
+            Expression();
+
+            switch(op)
+            {
+            case TK_NEWSLOT:
+                if(ds == OBJECT || ds == BASE)
+                {
+                    EmitDerefOp(_OP_NEWSLOT);
+                    if((_es.epos == -1) && (es.etype == EXPR_STATEMENT)
+                            && (type(id) == OT_STRING) ) AddGlobalName(id);
+                }
+                else //if _derefstate != DEREF_NO_DEREF && DEREF_FIELD so is the index of a local
+                    Error(_SC("can't 'create' a local slot"));
+                break;
+            case '=': //ASSIGN
+                if(warningAssign) Warning(_SC("%s:%d:%d warning making assignment, maybe it's not what you want\n"),
+                                              _stringval(_sourcename), _lex._currentline, _lex._currentcolumn);
+                switch(ds)
+                {
+                case LOCAL:
+                {
+                    SQInteger src = _fs->PopTarget();
+                    SQInteger dst = _fs->TopTarget();
+                    _fs->AddInstruction(_OP_MOVE, dst, src);
+                }
+                break;
+                case OBJECT:
+                case BASE:
+                    EmitDerefOp(_OP_SET);
+                    break;
+                case OUTER:
+                {
+                    SQInteger src = _fs->PopTarget();
+                    SQInteger dst = _fs->PushTarget();
+                    _fs->AddInstruction(_OP_SETOUTER, dst, pos, src);
+                }
+                }
+                break;
+            case TK_MINUSEQ:
+            case TK_PLUSEQ:
+            case TK_MULEQ:
+            case TK_DIVEQ:
+            case TK_MODEQ:
+                EmitCompoundArith(op, ds, pos);
+                break;
+            }
+        }
+        break;
+        case '?':
+        {
+            Lex();
+            _fs->AddInstruction(_OP_JZ, _fs->PopTarget());
+            SQInteger jzpos = _fs->GetCurrentPos();
+            SQInteger trg = _fs->PushTarget();
+            Expression();
+            SQInteger first_exp = _fs->PopTarget();
+            if(trg != first_exp) _fs->AddInstruction(_OP_MOVE, trg, first_exp);
+            SQInteger endfirstexp = _fs->GetCurrentPos();
+            _fs->AddInstruction(_OP_JMP, 0, 0);
+            Expect(':');
+            SQInteger jmppos = _fs->GetCurrentPos();
+            Expression();
+            SQInteger second_exp = _fs->PopTarget();
+            if(trg != second_exp) _fs->AddInstruction(_OP_MOVE, trg, second_exp);
+            _fs->SetIntructionParam(jmppos, 1, _fs->GetCurrentPos() - jmppos);
+            _fs->SetIntructionParam(jzpos, 1, endfirstexp - jzpos + 1);
+            _fs->SnoozeOpt();
+        }
+        break;
+        }
+        _es = es;
+    }
+
+    //template<typename T>
+    void INVOKE_EXP(T f)
+    {
+        SQExpState es = _es;
+        _es.etype     = EXPR;
+        _es.epos      = -1;
+        _es.donot_get = false;
+        //(this->*f)();
+        _es = es;
+    }
+    //template<typename T>
+    void BIN_EXP(SQOpcode op, T f,SQInteger op3 = 0)
+    {
+        Lex();
+        INVOKE_EXP(f);
+        SQInteger op1 = _fs->PopTarget();
+        SQInteger op2 = _fs->PopTarget();
+        _fs->AddInstruction(op, _fs->PushTarget(), op1, op2, op3);
+    }
+
+    void LogicalOrExp()
+    {
+        LogicalAndExp();
+        for(;;) if(_token == TK_OR)
+            {
+                SQInteger first_exp = _fs->PopTarget();
+                SQInteger trg = _fs->PushTarget();
+                _fs->AddInstruction(_OP_OR, trg, 0, first_exp, 0);
+                SQInteger jpos = _fs->GetCurrentPos();
+                if(trg != first_exp) _fs->AddInstruction(_OP_MOVE, trg, first_exp);
+                Lex();
+                INVOKE_EXP(/*&*/SQCompiler_LogicalOrExp);
+                _fs->SnoozeOpt();
+                SQInteger second_exp = _fs->PopTarget();
+                if(trg != second_exp) _fs->AddInstruction(_OP_MOVE, trg, second_exp);
+                _fs->SnoozeOpt();
+                _fs->SetIntructionParam(jpos, 1, (_fs->GetCurrentPos() - jpos));
+                break;
+            }
+            else return;
+    }
+
+    void LogicalAndExp()
+    {
+        BitwiseOrExp();
+        for(;;) switch(_token)
+            {
+            case TK_AND:
+            {
+                SQInteger first_exp = _fs->PopTarget();
+                SQInteger trg = _fs->PushTarget();
+                _fs->AddInstruction(_OP_AND, trg, 0, first_exp, 0);
+                SQInteger jpos = _fs->GetCurrentPos();
+                if(trg != first_exp) _fs->AddInstruction(_OP_MOVE, trg, first_exp);
+                Lex();
+                INVOKE_EXP(/*&*/SQCompiler_LogicalAndExp);
+                _fs->SnoozeOpt();
+                SQInteger second_exp = _fs->PopTarget();
+                if(trg != second_exp) _fs->AddInstruction(_OP_MOVE, trg, second_exp);
+                _fs->SnoozeOpt();
+                _fs->SetIntructionParam(jpos, 1, (_fs->GetCurrentPos() - jpos));
+                break;
+            }
+
+            default:
+                return;
+            }
+    }
+
+    void BitwiseOrExp()
+    {
+        BitwiseXorExp();
+        for(;;) if(_token == '|')
+            {
+                BIN_EXP(_OP_BITW,/*&*/SQCompiler_BitwiseXorExp,BW_OR);
+            }
+            else return;
+    }
+
+    void BitwiseXorExp()
+    {
+        BitwiseAndExp();
+        for(;;) if(_token == '^')
+            {
+                BIN_EXP(_OP_BITW,/*&*/SQCompiler_BitwiseAndExp,BW_XOR);
+            }
+            else return;
+    }
+
+    void BitwiseAndExp()
+    {
+        EqExp();
+        for(;;) if(_token == '&')
+            {
+                BIN_EXP(_OP_BITW,/*&*/SQCompiler_EqExp,BW_AND);
+            }
+            else return;
+    }
+
+    void EqExp()
+    {
+        CompExp();
+        for(;;) switch(_token)
+            {
+            case TK_EQ:
+                BIN_EXP(_OP_EQ,/*&*/SQCompiler_CompExp);
+                break;
+            case TK_EQ_IDENTITY :
+                BIN_EXP(_OP_EQI,/*&*/SQCompiler_CompExp);
+                break;
+            case TK_NE:
+                BIN_EXP(_OP_NE,/*&*/SQCompiler_CompExp);
+                break;
+            case TK_NE_IDENTITY:
+                BIN_EXP(_OP_NEI,/*&*/SQCompiler_CompExp);
+                break;
+            case TK_3WAYSCMP:
+                BIN_EXP(_OP_CMP,/*&*/SQCompiler_CompExp,CMP_3W);
+                break;
+            default:
+                return;
+            }
+    }
+
+    void CompExp()
+    {
+        ShiftExp();
+        for(;;) switch(_token)
+            {
+            case '>':
+                BIN_EXP(_OP_CMP, /*&*/SQCompiler_ShiftExp,CMP_G);
+                break;
+            case '<':
+                BIN_EXP(_OP_CMP, /*&*/SQCompiler_ShiftExp,CMP_L);
+                break;
+            case TK_GE:
+                BIN_EXP(_OP_CMP, /*&*/SQCompiler_ShiftExp,CMP_GE);
+                break;
+            case TK_LE:
+                BIN_EXP(_OP_CMP, /*&*/SQCompiler_ShiftExp,CMP_LE);
+                break;
+            case TK_IN:
+                BIN_EXP(_OP_EXISTS, /*&*/SQCompiler_ShiftExp);
+                break;
+            case TK_INSTANCEOF:
+                BIN_EXP(_OP_INSTANCEOF, /*&*/SQCompiler_ShiftExp);
+                break;
+            default:
+                return;
+            }
+    }
+
+    void ShiftExp()
+    {
+        PlusExp();
+        for(;;) switch(_token)
+            {
+            case TK_USHIFTR:
+                BIN_EXP(_OP_BITW, /*&*/SQCompiler_PlusExp,BW_USHIFTR);
+                break;
+            case TK_SHIFTL:
+                BIN_EXP(_OP_BITW, /*&*/SQCompiler_PlusExp,BW_SHIFTL);
+                break;
+            case TK_SHIFTR:
+                BIN_EXP(_OP_BITW, /*&*/SQCompiler_PlusExp,BW_SHIFTR);
+                break;
+            default:
+                return;
+            }
+    }
+
+    SQOpcode ChooseArithOpByToken(SQInteger tok)
+    {
+        switch(tok)
+        {
+        case TK_PLUSEQ:
+        case '+':
+            return _OP_ADD;
+        case TK_MINUSEQ:
+        case '-':
+            return _OP_SUB;
+        case TK_MULEQ:
+        case '*':
+            return _OP_MUL;
+        case TK_DIVEQ:
+        case '/':
+            return _OP_DIV;
+        case TK_MODEQ:
+        case '%':
+            return _OP_MOD;
+        default:
+            assert(0);
+        }
+        return _OP_ADD;
+    }
+
+    SQInteger ChooseCompArithCharByToken(SQInteger tok)
+    {
+        SQInteger oper;
+        switch(tok)
+        {
+        case TK_MINUSEQ:
+            oper = '-';
+            break;
+        case TK_PLUSEQ:
+            oper = '+';
+            break;
+        case TK_MULEQ:
+            oper = '*';
+            break;
+        case TK_DIVEQ:
+            oper = '/';
+            break;
+        case TK_MODEQ:
+            oper = '%';
+            break;
+        default:
+            oper = 0; //shut up compiler
+            assert(0);
+            break;
+        };
+        return oper;
+    }
+
+    void PlusExp()
+    {
+        MultExp();
+        for(;;) switch(_token)
+            {
+            case '+':
+            case '-':
+                BIN_EXP(ChooseArithOpByToken(_token), /*&*/SQCompiler_MultExp);
+                break;
+            default:
+                return;
+            }
+    }
+
+    void MultExp()
+    {
+        PrefixedExpr();
+        for(;;) switch(_token)
+            {
+            case '*':
+            case '/':
+            case '%':
+                BIN_EXP(ChooseArithOpByToken(_token), /*&*/SQCompiler_PrefixedExpr);
+                break;
+            default:
+                return;
+            }
+    }
+    //if 'pos' != -1 the previous variable is a local variable
+
+    void PrefixedExpr()
+    {
+        SQInteger pos = Factor();
+        for(;;)
+        {
+            switch(_token)
+            {
+            case '.':
+                pos = -1;
+                Lex();
+
+                _fs->AddInstruction(_OP_LOAD, _fs->PushTarget(), _fs->GetConstant(Expect(TK_IDENTIFIER)));
+                if(_es.etype==BASE)
+                {
+                    Emit2ArgsOP(_OP_GET);
+                    pos = _fs->TopTarget();
+                    _es.etype = EXPR;
+                    _es.epos   = pos;
+                }
+                else
+                {
+                    if(NeedGet())
+                    {
+                        Emit2ArgsOP(_OP_GET);
+                    }
+                    _es.etype = OBJECT;
+                }
+                break;
+            case '[':
+                if(_lex._prevtoken == '\n') Error(_SC("cannot brake deref/or comma needed after [exp]=exp slot declaration"));
+                Lex();
+                Expression();
+                Expect(']');
+                pos = -1;
+                if(_es.etype==BASE)
+                {
+                    Emit2ArgsOP(_OP_GET);
+                    pos = _fs->TopTarget();
+                    _es.etype = EXPR;
+                    _es.epos   = pos;
+                }
+                else
+                {
+                    if(NeedGet())
+                    {
+                        Emit2ArgsOP(_OP_GET);
+                    }
+                    _es.etype = OBJECT;
+                }
+                break;
+            case TK_MINUSMINUS:
+            case TK_PLUSPLUS:
+            {
+                if(IsEndOfStatement()) return;
+                SQInteger diff = (_token==TK_MINUSMINUS) ? -1 : 1;
+                Lex();
+                switch(_es.etype)
+                {
+                case EXPR:
+                    Error(_SC("can't '++' or '--' an expression"));
+                    break;
+                case OBJECT:
+                case BASE:
+                    if(_es.donot_get == true)
+                    {
+                        Error(_SC("can't '++' or '--' an expression"));    //mmh dor this make sense?
+                        break;
+                    }
+                    Emit2ArgsOP(_OP_PINC, diff);
+                    break;
+                case LOCAL:
+                {
+                    SQInteger src = _fs->PopTarget();
+                    _fs->AddInstruction(_OP_PINCL, _fs->PushTarget(), src, 0, diff);
+                }
+                break;
+                case OUTER:
+                {
+                    SQInteger tmp1 = _fs->PushTarget();
+                    SQInteger tmp2 = _fs->PushTarget();
+                    _fs->AddInstruction(_OP_GETOUTER, tmp2, _es.epos);
+                    _fs->AddInstruction(_OP_PINCL,    tmp1, tmp2, 0, diff);
+                    _fs->AddInstruction(_OP_SETOUTER, tmp2, _es.epos, tmp2);
+                    _fs->PopTarget();
+                }
+                }
+            }
+            return;
+            break;
+            case '(':
+                switch(_es.etype)
+                {
+                case OBJECT:
+                {
+                    SQInteger key     = _fs->PopTarget();  /* location of the key */
+                    SQInteger table   = _fs->PopTarget();  /* location of the object */
+                    SQInteger closure = _fs->PushTarget(); /* location for the closure */
+                    SQInteger ttarget = _fs->PushTarget(); /* location for 'this' pointer */
+                    _fs->AddInstruction(_OP_PREPCALL, closure, key, table, ttarget);
+                }
+                break;
+                case BASE:
+                    //Emit2ArgsOP(_OP_GET);
+                    _fs->AddInstruction(_OP_MOVE, _fs->PushTarget(), 0);
+                    break;
+                case OUTER:
+                    _fs->AddInstruction(_OP_GETOUTER, _fs->PushTarget(), _es.epos);
+                    _fs->AddInstruction(_OP_MOVE,     _fs->PushTarget(), 0);
+                    break;
+                default:
+                    _fs->AddInstruction(_OP_MOVE, _fs->PushTarget(), 0);
+                }
+                _es.etype = EXPR;
+                Lex();
+                FunctionCallArgs();
+                break;
+
+            case TK_AS:
+            {
+                Lex();
+                ExpectTypeToken(); //ignore for now
+            }
+
+            default:
+                return;
+            }
+        }
+    }
+
+    SQInteger Factor() {}
+
+    void EmitLoadConstInt(SQInteger value,SQInteger target)
+    {
+        if(target < 0)
+        {
+            target = _fs->PushTarget();
+        }
+        //with the line bellow we get wrong result for -1
+        //if(value <= INT_MAX && value > INT_MIN) { //does it fit in 32 bits?
+        if((value & (~(/*(SQInteger)*/0xFFFFFFFF))) == 0)   //does it fit in 32 bits?
+        {
+            _fs->AddInstruction(_OP_LOADINT, target,value);
+        }
+        else
+        {
+            _fs->AddInstruction(_OP_LOAD, target, _fs->GetNumericConstant(value));
+        }
+    }
+
+
+    void EmitLoadConstFloat(SQFloat value,SQInteger target)
+    {
+        if(target < 0)
+        {
+            target = _fs->PushTarget();
+        }
+        if(sizeof(SQFloat) == sizeof(SQInt32))
+        {
+            _fs->AddInstruction(_OP_LOADFLOAT, target,/**((SQInt32 *)&*/value);
+        }
+        else
+        {
+            _fs->AddInstruction(_OP_LOAD, target, _fs->GetNumericConstant(value));
+        }
+    }
+
+    void UnaryOP(SQOpcode op)
+    {
+        PrefixedExpr();
+        SQInteger src = _fs->PopTarget();
+        _fs->AddInstruction(op, _fs->PushTarget(), src);
+    }
+
+    bool NeedGet()
+    {
+        switch(_token)
+        {
+        case '=':
+        case '(':
+        case TK_NEWSLOT:
+        case TK_MODEQ:
+        case TK_MULEQ:
+        case TK_DIVEQ:
+        case TK_MINUSEQ:
+        case TK_PLUSEQ:
+            return false;
+            1
+        case TK_PLUSPLUS:
+        case TK_MINUSMINUS:
+            if (!IsEndOfStatement())
+            {
+                return false;
+            }
+            break;
+        }
+        return (!_es.donot_get || ( _es.donot_get && (_token == '.' || _token == '[')));
+    }
+
+    void FunctionCallArgs()
+    {
+        SQInteger nargs = 1;//this
+        while(_token != ')')
+        {
+            Expression();
+            MoveIfCurrentTargetIsLocal();
+            nargs++;
+            if(_token == ',')
+            {
+                Lex();
+                if(_token == ')') Error(_SC("expression expected, found ')'"));
+            }
+        }
+        Lex();
+        for(SQInteger i = 0; i < (nargs - 1); i++) _fs->PopTarget();
+        SQInteger stackbase = _fs->PopTarget();
+        SQInteger closure = _fs->PopTarget();
+        _fs->AddInstruction(_OP_CALL, _fs->PushTarget(), closure, stackbase, nargs);
+    }
+
+    void AddClassMemberExists(SQObjectPtr &member_names, SQObject &name)
+    {
+        SQObjectPtr oname = name, otrue = true;
+        _table(member_names)->NewSlot(oname, otrue);
+    }
+
+    void CheckClassMemberExists(SQObjectPtr &member_names, SQObject &name, bool addIfNotExists=true)
+    {
+        if(_table(member_names)->Exists(name))
+        {
+            Error(_SC("class already has a member named: %s"), _stringval(name));
+        }
+        if(addIfNotExists) AddClassMemberExists(member_names, name);
+    }
+
+    //void CheckClassMemberExists(SQObjectPtr &member_names, const SQChar_ptr_t name){}
+
+    void ParseTableOrClass(SQInteger separator,SQInteger terminator, SQObjectPtr_ptr_t class_name=NULL) {}
+
+    void ExternDeclStatement()
+    {
+        _is_parsing_extern = true;
+        Lex();
+        LocalDeclStatement();
+        _is_parsing_extern = false;
+    }
+
+    void LocalDeclStatement() {}
+
+    void IfBlock()
+    {
+        if (_token == '{')
+        {
+            BEGIN_SCOPE();
+            Lex();
+            Statements();
+            Expect('}');
+            if (true)
+            {
+                END_SCOPE();
+            }
+            else
+            {
+                END_SCOPE_NO_CLOSE();
+            }
+        }
+        else
+        {
+            //BEGIN_SCOPE();
+            Statement();
+            if (_lex._prevtoken != '}' && _lex._prevtoken != ';') OptionalSemicolon();
+            //END_SCOPE();
+        }
+    }
+
+    void IfStatement()
+    {
+        SQInteger jmppos;
+        bool haselse = false;
+        Lex();
+        Expect('(');
+        CommaExpr(true);
+        Expect(')');
+        _fs->AddInstruction(_OP_JZ, _fs->PopTarget());
+        SQInteger jnepos = _fs->GetCurrentPos();
+        BEGIN_SCOPE();
+
+        //there is a situation where the if statement has a statement enclosed by {}
+        //and after the closing "}" there is no newline or semicolom
+        //it's a valid construction but the compiler was complaining about it
+        //for now added "&& _token != TK_IDENTIFIER" to the check after "Statement()" call
+        /*
+        local color = "blue";
+        if(color == "yellow"){
+        	print(color);
+        } print("Waht color is it ?");
+        */
+        Statement();
+        //
+        if(_token != '}' && _token != TK_ELSE && _token != TK_IDENTIFIER) OptionalSemicolon();
+
+        END_SCOPE();
+        SQInteger endifblock = _fs->GetCurrentPos();
+        if(_token == TK_ELSE)
+        {
+            haselse = true;
+            BEGIN_SCOPE();
+            _fs->AddInstruction(_OP_JMP);
+            jmppos = _fs->GetCurrentPos();
+            Lex();
+            Statement();
+            if(_token != TK_IDENTIFIER) OptionalSemicolon();
+            END_SCOPE();
+            _fs->SetIntructionParam(jmppos, 1, _fs->GetCurrentPos() - jmppos);
+        }
+        _fs->SetIntructionParam(jnepos, 1, endifblock - jnepos + (haselse?1:0));
+    }
+
+    void WhileStatement()
+    {
+        SQInteger jzpos, jmppos;
+        jmppos = _fs->GetCurrentPos();
+        Lex();
+        Expect('(');
+        CommaExpr(true);
+        Expect(')');
+
+        BEGIN_BREAKBLE_BLOCK();
+        _fs->AddInstruction(_OP_JZ, _fs->PopTarget());
+        jzpos = _fs->GetCurrentPos();
+        BEGIN_SCOPE();
+
+        Statement();
+
+        END_SCOPE();
+        _fs->AddInstruction(_OP_JMP, 0, jmppos - _fs->GetCurrentPos() - 1);
+        _fs->SetIntructionParam(jzpos, 1, _fs->GetCurrentPos() - jzpos);
+
+        END_BREAKBLE_BLOCK(jmppos);
+    }
+
+    void DoWhileStatement()
+    {
+        Lex();
+        SQInteger jmptrg = _fs->GetCurrentPos();
+        BEGIN_BREAKBLE_BLOCK()
+        BEGIN_SCOPE();
+        Statement();
+        END_SCOPE();
+        //fix proposed by frosch to correct line number info in stack dumps
+        _fs->AddLineInfos(_lex._currentline, _lineinfo, true);
+        Expect(TK_WHILE);
+        SQInteger continuetrg = _fs->GetCurrentPos();
+        Expect('(');
+        CommaExpr(true);
+        Expect(')');
+        _fs->AddInstruction(_OP_JZ, _fs->PopTarget(), 1);
+        _fs->AddInstruction(_OP_JMP, 0, jmptrg - _fs->GetCurrentPos() - 1);
+        END_BREAKBLE_BLOCK(continuetrg);
+    }
+
+    void ForStatement()
+    {
+        Lex();
+        BEGIN_SCOPE();
+        Expect('(');
+        switch(_token)
+        {
+        case TK_IDENTIFIER:
+        //ignore custom types for now
+        //fallthrough as local declaration
+        //CASE_TK_LOCAL_TYPES:
+        case TK_LOCAL:
+            LocalDeclStatement();
+            break;
+        default:
+            if(_token != ';')
+            {
+                CommaExpr();
+                _fs->PopTarget();
+            }
+        }
+
+        Expect(';');
+        _fs->SnoozeOpt();
+        SQInteger jmppos = _fs->GetCurrentPos();
+        SQInteger jzpos = -1;
+        if(_token != ';')
+        {
+            CommaExpr();
+            _fs->AddInstruction(_OP_JZ, _fs->PopTarget());
+            jzpos = _fs->GetCurrentPos();
+        }
+        Expect(';');
+        _fs->SnoozeOpt();
+        SQInteger expstart = _fs->GetCurrentPos() + 1;
+        if(_token != ')')
+        {
+            CommaExpr();
+            _fs->PopTarget();
+        }
+        Expect(')');
+        _fs->SnoozeOpt();
+        SQInteger expend = _fs->GetCurrentPos();
+        SQInteger expsize = (expend - expstart) + 1;
+        SQInstructionVec exp;
+        if(expsize > 0)
+        {
+            for(SQInteger i = 0; i < expsize; i++)
+                exp.push_back(_fs->GetInstruction(expstart + i));
+            _fs->PopInstructions(expsize);
+        }
+        BEGIN_BREAKBLE_BLOCK()
+        Statement();
+        SQInteger continuetrg = _fs->GetCurrentPos();
+        if(expsize > 0)
+        {
+            for(SQInteger i = 0; i < expsize; i++)
+                _fs->AddInstruction(exp[i]);
+        }
+        _fs->AddInstruction(_OP_JMP, 0, jmppos - _fs->GetCurrentPos() - 1, 0);
+        if(jzpos>  0) _fs->SetIntructionParam(jzpos, 1, _fs->GetCurrentPos() - jzpos);
+        END_SCOPE();
+
+        END_BREAKBLE_BLOCK(continuetrg);
+    }
+
+    void ForEachStatement()
+    {
+        SQObject idxname, valname;
+        Lex();
+        Expect('(');
+        valname = Expect(TK_IDENTIFIER);
+        if(_token == ',')
+        {
+            idxname = valname;
+            Lex();
+            valname = Expect(TK_IDENTIFIER);
+        }
+        else
+        {
+            idxname = _fs->CreateString(_SC("@INDEX@"));
+        }
+        Expect(TK_IN);
+
+        //save the stack size
+        BEGIN_SCOPE();
+        //put the table in the stack(evaluate the table expression)
+        Expression();
+        Expect(')');
+        SQInteger container = _fs->TopTarget();
+        //push the index local var
+        SQInteger indexpos = _fs->PushLocalVariable(idxname, _scope.nested);
+        _fs->AddInstruction(_OP_LOADNULLS, indexpos,1);
+        //push the value local var
+        SQInteger valuepos = _fs->PushLocalVariable(valname, _scope.nested);
+        _fs->AddInstruction(_OP_LOADNULLS, valuepos,1);
+        //push reference index
+        SQInteger itrpos = _fs->PushLocalVariable(_fs->CreateString(_SC("@ITERATOR@")), _scope.nested); //use invalid id to make it inaccessible
+        _fs->AddInstruction(_OP_LOADNULLS, itrpos,1);
+        SQInteger jmppos = _fs->GetCurrentPos();
+        _fs->AddInstruction(_OP_FOREACH, container, 0, indexpos);
+        SQInteger foreachpos = _fs->GetCurrentPos();
+        _fs->AddInstruction(_OP_POSTFOREACH, container, 0, indexpos);
+        //generate the statement code
+        BEGIN_BREAKBLE_BLOCK()
+        Statement();
+        _fs->AddInstruction(_OP_JMP, 0, jmppos - _fs->GetCurrentPos() - 1);
+        _fs->SetIntructionParam(foreachpos, 1, _fs->GetCurrentPos() - foreachpos);
+        _fs->SetIntructionParam(foreachpos + 1, 1, _fs->GetCurrentPos() - foreachpos);
+        END_BREAKBLE_BLOCK(foreachpos - 1);
+        //restore the local variable stack(remove index,val and ref idx)
+        _fs->PopTarget();
+        END_SCOPE();
+    }
+
+    void SwitchStatement()
+    {
+        Lex();
+        Expect('(');
+        CommaExpr(true);
+        Expect(')');
+        Expect('{');
+        SQInteger expr = _fs->TopTarget();
+        bool bfirst = true;
+        SQInteger tonextcondjmp = -1;
+        SQInteger skipcondjmp = -1;
+        SQInteger __nbreaks__ = _fs->_unresolvedbreaks.size();
+        _fs->_breaktargets.push_back(0);
+        while(_token == TK_CASE)
+        {
+            if(!bfirst)
+            {
+                _fs->AddInstruction(_OP_JMP, 0, 0);
+                skipcondjmp = _fs->GetCurrentPos();
+                _fs->SetIntructionParam(tonextcondjmp, 1, _fs->GetCurrentPos() - tonextcondjmp);
+            }
+            //condition
+            Lex();
+            ExpressionScalar() /*Expression()*/;
+            Expect(':');
+            SQInteger trg = _fs->PopTarget();
+            SQInteger eqtarget = trg;
+            bool vlocal = _fs->IsLocal(trg);
+            if(vlocal)
+            {
+                eqtarget = _fs->PushTarget(); //we need to allocate a extra reg
+            }
+            _fs->AddInstruction(_OP_EQ, eqtarget, trg, expr);
+            _fs->AddInstruction(_OP_JZ, eqtarget, 0);
+            if(vlocal)
+            {
+                _fs->PopTarget();
+            }
+
+            //end condition
+            if(skipcondjmp != -1)
+            {
+                _fs->SetIntructionParam(skipcondjmp, 1, (_fs->GetCurrentPos() - skipcondjmp));
+            }
+            tonextcondjmp = _fs->GetCurrentPos();
+            BEGIN_SCOPE();
+            Statements();
+            END_SCOPE();
+            bfirst = false;
+        }
+        if(tonextcondjmp != -1)
+            _fs->SetIntructionParam(tonextcondjmp, 1, _fs->GetCurrentPos() - tonextcondjmp);
+        if(_token == TK_DEFAULT)
+        {
+            Lex();
+            Expect(':');
+            BEGIN_SCOPE();
+            Statements();
+            END_SCOPE();
+        }
+        Expect('}');
+        _fs->PopTarget();
+        __nbreaks__ = _fs->_unresolvedbreaks.size() - __nbreaks__;
+        if(__nbreaks__ > 0)ResolveBreaks(_fs, __nbreaks__);
+        _fs->_breaktargets.pop_back();
+    }
+
+    void FunctionStatement()
+    {
+        SQObject id;
+        Lex();
+        id = Expect(TK_IDENTIFIER);
+        _fs->PushTarget(0);
+        _fs->AddInstruction(_OP_LOAD, _fs->PushTarget(), _fs->GetConstant(id));
+        if(_token == TK_DOUBLE_COLON) Emit2ArgsOP(_OP_GET);
+        else CheckGlobalName(id, true);
+
+        while(_token == TK_DOUBLE_COLON)
+        {
+            Lex();
+            id = Expect(TK_IDENTIFIER);
+            //todo check if class function already exists
+            _fs->AddInstruction(_OP_LOAD, _fs->PushTarget(), _fs->GetConstant(id));
+            if(_token == TK_DOUBLE_COLON) Emit2ArgsOP(_OP_GET);
+        }
+        Expect('(');
+        CreateFunction(id, eFunctionType_global);
+        _fs->AddInstruction(_OP_CLOSURE, _fs->PushTarget(), _fs->_functions.size() - 1, 0);
+        EmitDerefOp(_OP_NEWSLOT);
+        _fs->PopTarget();
+    }
+
+    void ClassStatement()
+    {
+        SQExpState es;
+        SQObjectPtr class_name;
+        Lex();
+        if(_token == TK_IDENTIFIER)
+        {
+            class_name = SQString_Create(_ss(_vm), _lex._svalue);
+            CheckGlobalName(class_name, true);
+            CheckTypeName(class_name, true); //to allow C/C++ style instance declarations
+        }
+        es = _es;
+        _es.donot_get = true;
+        PrefixedExpr();
+        if(_token == ';') //class forward declaration
+        {
+            //return;
+        }
+        if(_es.etype == EXPR)
+        {
+            Error(_SC("invalid class name"));
+        }
+        else if(_es.etype == OBJECT || _es.etype == BASE)
+        {
+            ClassExp(/*&*/class_name);
+            EmitDerefOp(_OP_NEWSLOT);
+            _fs->PopTarget();
+        }
+        else
+        {
+            Error(_SC("cannot create a class in a local with the syntax(class <local>)"));
+        }
+        _es = es;
+    }
+
+    SQObject ExpectScalar()
+    {
+        SQObject val;
+        val._type = OT_NULL;
+        val._unVal.nInteger = 0; //shut up GCC 4.x
+        switch(_token)
+        {
+        case TK_INTEGER:
+            val._type = OT_INTEGER;
+            val._unVal.nInteger = _lex._nvalue;
+            break;
+        case TK_FLOAT:
+            val._type = OT_FLOAT;
+            val._unVal.fFloat = _lex._fvalue;
+            break;
+        case TK_STRING_LITERAL:
+            val = _fs->CreateString(_lex._svalue,_lex._longstr.size()-1);
+            break;
+        case TK_TRUE:
+        case TK_FALSE:
+            val._type = OT_BOOL;
+            val._unVal.nInteger = _token == TK_TRUE ? 1 : 0;
+            break;
+        case '-':
+            Lex();
+            switch(_token)
+            {
+            case TK_INTEGER:
+                val._type = OT_INTEGER;
+                val._unVal.nInteger = -_lex._nvalue;
+                break;
+            case TK_FLOAT:
+                val._type = OT_FLOAT;
+                val._unVal.fFloat = -_lex._fvalue;
+                break;
+            default:
+                Error(_SC("scalar expected : integer, float"));
+            }
+            break;
+        default:
+            Error(_SC("scalar expected : integer, float or string"));
+        }
+        Lex();
+        return val;
+    }
+
+    SQInteger ExpressionScalar()
+    {
+        SQInteger tk_type = _token;
+        switch(_token)
+        {
+        case TK_INTEGER:
+            EmitLoadConstInt(_lex._nvalue,-1);
+            break;
+        case TK_FLOAT:
+            EmitLoadConstFloat(_lex._fvalue,-1);
+            break;
+        case TK_STRING_LITERAL:
+            _fs->AddInstruction(_OP_LOAD, _fs->PushTarget(), _fs->GetConstant(_fs->CreateString(_lex._svalue,_lex._longstr.size()-1)));
+            break;
+        case TK_IDENTIFIER:
+        {
+            SQObject id = _fs->CreateString(_lex._svalue);
+            Lex();
+            ExpressionConstant(id);
+            return tk_type;
+        }
+        break;
+        case '-':
+            Lex();
+            tk_type = _token;
+            switch(_token)
+            {
+            case TK_INTEGER:
+                EmitLoadConstInt(-_lex._nvalue,-1);
+                break;
+            case TK_FLOAT:
+                EmitLoadConstFloat(-_lex._fvalue,-1);
+                break;
+            default:
+                Error(_SC("scalar expected : integer, float"));
+            }
+            break;
+        default:
+            //goto error;
+        }
+        Lex();
+        return tk_type;
+//error:
+        Error(_SC("constant or scalar expected : integer, float or string"));
+        return 0;
+    }
+
+    void EnumStatement()
+    {
+        Lex();
+        SQObject id = Expect(TK_IDENTIFIER);
+        Expect('{');
+
+        //CheckLocalNameScope(id, _scope.nested);
+        SQObjectPtr strongid = id;
+        CheckLocalNameScope(id, _scope.nested);
+        SQObject table = _fs->CreateTable();
+        //_fs->AddInstruction(_OP_NEWOBJ, _fs->PushTarget(),0,NOT_TABLE);
+        SQInteger nval = 0;
+        while(_token != '}')
+        {
+            SQObject key = Expect(TK_IDENTIFIER);
+            SQObject val;
+            if(_token == '=')
+            {
+                Lex();
+                val = ExpectScalar();
+            }
+            else
+            {
+                val._type = OT_INTEGER;
+                val._unVal.nInteger = nval++;
+            }
+            //SQInteger table = _fs->TopTarget(); //<<BECAUSE OF THIS NO COMMON EMIT FUNC IS POSSIBLE
+            //_fs->AddInstruction(_OP_NEWSLOT, 0xFF, table, key, val);
+
+            _table(table)->NewSlot(SQObjectPtr(key),SQObjectPtr(val));
+            if(_token == ',') Lex();
+        }
+
+        ConstsNewSlot(SQObjectPtr(strongid),SQObjectPtr(table));
+        strongid.Null();
+        Lex();
+    }
+
+    void TryCatchStatement()
+    {
+        SQObject exid;
+        Lex();
+        _fs->AddInstruction(_OP_PUSHTRAP,0,0);
+        _fs->_traps++;
+        //if(_fs->_breaktargets.size()) _fs->_breaktargets.top()++;
+        //if(_fs->_continuetargets.size()) _fs->_continuetargets.top()++;
+        SQInteger trappos = _fs->GetCurrentPos();
+        {
+            BEGIN_SCOPE();
+            Statement();
+            END_SCOPE();
+        }
+        _fs->_traps--;
+        _fs->AddInstruction(_OP_POPTRAP, 1, 0);
+        //if(_fs->_breaktargets.size()) _fs->_breaktargets.top()--;
+        //if(_fs->_continuetargets.size()) _fs->_continuetargets.top()--;
+        _fs->AddInstruction(_OP_JMP, 0, 0);
+        SQInteger jmppos = _fs->GetCurrentPos();
+        _fs->SetIntructionParam(trappos, 1, (_fs->GetCurrentPos() - trappos));
+        Expect(TK_CATCH);
+        Expect('(');
+        exid = Expect(TK_IDENTIFIER);
+        Expect(')');
+        {
+            BEGIN_SCOPE();
+            SQInteger ex_target = _fs->PushLocalVariable(exid, _scope.nested);
+            _fs->SetIntructionParam(trappos, 0, ex_target);
+            Statement();
+            _fs->SetIntructionParams(jmppos, 0, (_fs->GetCurrentPos() - jmppos), 0);
+            END_SCOPE();
+        }
+    }
+
+    void FunctionExp(SQInteger ftype,bool lambda = false)
+    {
+        Lex();
+        Expect('(');
+        SQObjectPtr dummy;
+        CreateFunction(dummy, lambda ? eFunctionType_lambda : eFunctionType_anonymous);
+        _fs->AddInstruction(_OP_CLOSURE, _fs->PushTarget(), _fs->_functions.size() - 1, ftype == TK_FUNCTION?0:1);
+    }
+
+    void ClassExp(SQObjectPtr_ptr_t class_name)
+    {
+        SQInteger vbase = -1;
+        SQInteger attrs = -1;
+        bool hasInheritance = false;
+        switch(_token)
+        {
+        case ':': //C++ style class derivation
+        case TK_EXTENDS: //squirrel style class derivation
+            Lex();
+            hasInheritance = true;
+            switch(_token)
+            {
+            case TK_PRIVATE:
+            case TK_PUBLIC:
+                Lex(); //ignore, accepted only to compile a subset of C++
+            }
+        }
+        if(hasInheritance)
+        {
+            Expression();
+            vbase = _fs->TopTarget();
+        }
+        if(_token == TK_ATTR_OPEN)
+        {
+            Lex();
+            _fs->AddInstruction(_OP_NEWOBJ, _fs->PushTarget(),0,NOT_TABLE);
+            ParseTableOrClass(',',TK_ATTR_CLOSE);
+            attrs = _fs->TopTarget();
+        }
+        Expect('{');
+        if(attrs != -1) _fs->PopTarget();
+        if(vbase != -1) _fs->PopTarget();
+        _fs->AddInstruction(_OP_NEWOBJ, _fs->PushTarget(), vbase, attrs,NOT_CLASS);
+        ParseTableOrClass(';','}', class_name);
+    }
+
+    void DeleteExpr()
+    {
+        SQExpState es;
+        Lex();
+        es = _es;
+        _es.donot_get = true;
+        PrefixedExpr();
+        if(_es.etype==EXPR) Error(_SC("can't delete an expression"));
+        if(_es.etype==OBJECT || _es.etype==BASE)
+        {
+            Emit2ArgsOP(_OP_DELETE);
+        }
+        else
+        {
+            Error(_SC("cannot delete an (outer) local"));
+        }
+        _es = es;
+    }
+
+    void PrefixIncDec(SQInteger token)
+    {
+        SQExpState  es;
+        SQInteger diff = (token==TK_MINUSMINUS) ? -1 : 1;
+        Lex();
+        es = _es;
+        _es.donot_get = true;
+        PrefixedExpr();
+        if(_es.etype==EXPR)
+        {
+            Error(_SC("can't '++' or '--' an expression"));
+        }
+        else if(_es.etype==OBJECT || _es.etype==BASE)
+        {
+            Emit2ArgsOP(_OP_INC, diff);
+        }
+        else if(_es.etype==LOCAL)
+        {
+            SQInteger src = _fs->TopTarget();
+            _fs->AddInstruction(_OP_INCL, src, src, 0, diff);
+
+        }
+        else if(_es.etype==OUTER)
+        {
+            SQInteger tmp = _fs->PushTarget();
+            _fs->AddInstruction(_OP_GETOUTER, tmp, _es.epos);
+            _fs->AddInstruction(_OP_INCL,     tmp, tmp, 0, diff);
+            _fs->AddInstruction(_OP_SETOUTER, tmp, _es.epos, tmp);
+        }
+        _es = es;
+    }
+
+    void CreateFunction(SQObject &name, int ftype, int stack_offset=0)
+    {
+        SQFuncState_ptr_t funcstate = _fs->PushChildState(_ss(_vm));
+        funcstate->_name = name;
+        SQObject paramname, type_name;
+        funcstate->AddParameter(_fs->CreateString(_SC("this")), _scope.nested+1);
+        funcstate->_sourcename = _sourcename;
+        SQInteger defparams = 0;
+        bool is_reference_declaration = 0;
+        /*const*/ SQChar_ptr_t param_type_name = 0;
+        bool isVoid = false;
+        while(_token!=')')
+        {
+            if(isVoid)
+            {
+                Error(_SC("void type is invalid here"));
+            }
+            is_reference_declaration = 0; //reset is_reference_declaration
+            param_type_name = 0; //rest for each parameter
+            if(_token == TK_VOID)
+            {
+                isVoid = true;
+                Lex();
+                continue;
+            }
+            if(_token == TK_VARPARAMS)
+            {
+                if(defparams > 0) Error(_SC("function with default parameters cannot have variable number of parameters"));
+                funcstate->AddParameter(_fs->CreateString(_SC("vargv")), _scope.nested+1);
+                funcstate->_varparams = true;
+                Lex();
+                if(_token != ')') Error(_SC("expected ')'"));
+                break;
+            }
+            else
+            {
+                if(_token == TK_CONST) Lex(); //C/C++ const cualifiers for now
+                switch(_token)
+                {
+                    //CASE_TK_LOCAL_TYPES: //accept C/C++ type parameter declarations
+                    //        param_type_name = _lex.GetTokenName(_token);
+                    //        Lex();
+                }
+                CHECK_REF_DECLARATION(_token);
+                paramname = Expect(TK_IDENTIFIER);
+                if(CheckNameIsType(paramname))
+                {
+                    //ignore custom types for now
+                    param_type_name = _stringval(paramname);
+                    CHECK_REF_DECLARATION(_token);
+                    paramname = Expect(TK_IDENTIFIER);
+                }
+                funcstate->AddParameter(paramname, _scope.nested+1, is_reference_declaration ? _VAR_REFERENCE : _VAR_ANY);
+                if(param_type_name)
+                {
+                    funcstate->AddParameterTypeName(param_type_name);
+                }
+                if(_token == '=')
+                {
+                    if(is_reference_declaration) Error(_SC("parameter passed by reference can't have default value"));
+                    Lex();
+                    if(_token == '[' || _token == '{') Error(_SC("default parameter with array/table values not supported"));
+                    Expression();
+                    //stack_offset to compensate for local functions been relocated to allow recursion
+                    funcstate->AddDefaultParam(_fs->TopTarget()+stack_offset);
+                    defparams++;
+                }
+                else if(_token == ':')
+                {
+                    //param type specifier like typescript
+                    if(param_type_name)
+                    {
+                        Error(_SC("parameter type already declared before %s"), _string(paramname));
+                    }
+                    Lex();
+                    type_name = ExpectTypeToken();
+                    funcstate->AddParameterTypeName(type_name);
+                    //printf("%d %s\n", __LINE__, _stringval(type_name));
+                }
+                else
+                {
+                    if(defparams > 0) Error(_SC("expected '='"));
+                }
+                if(_token == ',') Lex();
+                else if(_token != ')') Error(_SC("expected ')' or ','"));
+            }
+        }
+        Expect(')');
+        switch(_token)
+        {
+        case ':':
+        {
+            //return type specifier like typescript
+            Lex();
+            type_name = ExpectTypeToken();
+            funcstate->_return_type = type_name;
+            //printf("%d %s\n", __LINE__, _stringval(type_name));
+        }
+        break;
+
+        case TK_CONST:
+        case TK_NOEXCEPT:
+        case TK_VOLATILE:
+            Lex(); //accept and ignore
+            break;
+
+        case TK_IDENTIFIER:
+            if(ftype == eFunctionType_member)
+            {
+                if(  (scstrcmp(_lex._svalue, _SC("final")) == 0) ||
+                        (scstrcmp(_lex._svalue, _SC("override")) == 0))
+                {
+                    Lex(); //accept but ignore then
+                }
+            }
+        }
+
+        for(SQInteger n = 0; n < defparams; n++)
+        {
+            _fs->PopTarget();
+        }
+
+        if(_is_parsing_extern)
+        {
+            if(_token == ';') //to parse thinscript
+            {
+                _fs->PopChildState();
+                return;
+            }
+            else _is_parsing_extern = false;
+        }
+
+        SQFuncState_ptr_t currchunk = _fs;
+        _fs = funcstate;
+        if(ftype == eFunctionType_lambda)
+        {
+            Expression();
+            _fs->AddInstruction(_OP_RETURN, 1, _fs->PopTarget());
+        }
+        else
+        {
+            Statement(false);
+        }
+        funcstate->AddLineInfos(_lex._prevtoken == '\n'?_lex._lasttokenline:_lex._currentline, _lineinfo, true);
+        funcstate->AddInstruction(_OP_RETURN, -1);
+        funcstate->SetStackSize(0);
+
+        SQFunctionProto *func = funcstate->BuildProto();
+//#ifdef _DEBUG_DUMP
+//		funcstate->Dump(func);
+//#endif
+        _fs = currchunk;
+        _fs->_functions.push_back(func);
+        _fs->PopChildState();
+    }
+
+    void ResolveBreaks(SQFuncState_ptr_t funcstate, SQInteger ntoresolve) {}
+
+    void ResolveContinues(SQFuncState_ptr_t funcstate, SQInteger ntoresolve, SQInteger targetpos) {}
+//private:
+};
+
+string_t txt = readfile("test-raii.nut")
+               var lex = new SQLexer(txt, true /*we want comments*/);
+
+var first_enum_token = lex.first_enum_token();
+var last_enum_token = lex.last_enum_token();
+
+var nest_level = 0;
+var tok =  lex.lex(); //lex.lex();
+while(tok > 0)
+{
+    local tkstr;
+    if(tok > first_enum_token && tok < last_enum_token) tkstr = lex.tok2str(tok); //lex.tok2str(tok);
+    else tkstr = tok.tochar();
+    /*
+    print(
+    	tok,
+    	tkstr || "",
+    	lex.token_name(tok), //lex.token_name(tok),
+    	lex.svalue() || "",
+    	lex.lasttokenline(),
+    	lex.lasttokencolumn(),
+    	lex.currentline(),
+    	lex.currentcolumn()
+    	);
+    */
+
+    switch(tok)
+    {
+    case '{':
+    case '}':
+    default:
+        print(tkstr);
+    }
+
+    tok = lex.lex();
+}