fix cr/lfs and remove trailing whitespaces...
[supertux.git] / src / squirrel / squirrel / sqlexer.cpp
index 7244e73..2552f7d 100644 (file)
-/*\r
-       see copyright notice in squirrel.h\r
-*/\r
-#include "sqpcheader.h"\r
-#include <ctype.h>\r
-#include <stdlib.h>\r
-#include "sqtable.h"\r
-#include "sqstring.h"\r
-#include "sqcompiler.h"\r
-#include "sqlexer.h"\r
-\r
-#define CUR_CHAR (_currdata)\r
-#define RETURN_TOKEN(t) { _prevtoken = _curtoken; _curtoken = t; return t;}\r
-#define IS_EOB() (CUR_CHAR <= SQUIRREL_EOB)\r
-#define NEXT() {Next();_currentcolumn++;}\r
-#define INIT_TEMP_STRING() { _longstr.resize(0);}\r
-#define APPEND_CHAR(c) { _longstr.push_back(c);}\r
-#define TERMINATE_BUFFER() {_longstr.push_back(_SC('\0'));}\r
-#define ADD_KEYWORD(key,id) _keywords->NewSlot( SQString::Create(ss, _SC(#key)) ,SQInteger(id))\r
-\r
-SQLexer::SQLexer(){}\r
-SQLexer::~SQLexer()\r
-{\r
-       _keywords->Release();\r
-}\r
-\r
-void SQLexer::Init(SQSharedState *ss, SQLEXREADFUNC rg, SQUserPointer up,CompilerErrorFunc efunc,void *ed)\r
-{\r
-       _errfunc = efunc;\r
-       _errtarget = ed;\r
-       _sharedstate = ss;\r
-       _keywords = SQTable::Create(ss, 26);\r
-       ADD_KEYWORD(while, TK_WHILE);\r
-       ADD_KEYWORD(do, TK_DO);\r
-       ADD_KEYWORD(if, TK_IF);\r
-       ADD_KEYWORD(else, TK_ELSE);\r
-       ADD_KEYWORD(break, TK_BREAK);\r
-       ADD_KEYWORD(continue, TK_CONTINUE);\r
-       ADD_KEYWORD(return, TK_RETURN);\r
-       ADD_KEYWORD(null, TK_NULL);\r
-       ADD_KEYWORD(function, TK_FUNCTION);\r
-       ADD_KEYWORD(local, TK_LOCAL);\r
-       ADD_KEYWORD(for, TK_FOR);\r
-       ADD_KEYWORD(foreach, TK_FOREACH);\r
-       ADD_KEYWORD(in, TK_IN);\r
-       ADD_KEYWORD(typeof, TK_TYPEOF);\r
-       ADD_KEYWORD(delegate, TK_DELEGATE);\r
-       ADD_KEYWORD(delete, TK_DELETE);\r
-       ADD_KEYWORD(try, TK_TRY);\r
-       ADD_KEYWORD(catch, TK_CATCH);\r
-       ADD_KEYWORD(throw, TK_THROW);\r
-       ADD_KEYWORD(clone, TK_CLONE);\r
-       ADD_KEYWORD(yield, TK_YIELD);\r
-       ADD_KEYWORD(resume, TK_RESUME);\r
-       ADD_KEYWORD(switch, TK_SWITCH);\r
-       ADD_KEYWORD(case, TK_CASE);\r
-       ADD_KEYWORD(default, TK_DEFAULT);\r
-       ADD_KEYWORD(this, TK_THIS);\r
-       ADD_KEYWORD(parent,TK_PARENT);\r
-       ADD_KEYWORD(class,TK_CLASS);\r
-       ADD_KEYWORD(extends,TK_EXTENDS);\r
-       ADD_KEYWORD(constructor,TK_CONSTRUCTOR);\r
-       ADD_KEYWORD(instanceof,TK_INSTANCEOF);\r
-       ADD_KEYWORD(vargc,TK_VARGC);\r
-       ADD_KEYWORD(vargv,TK_VARGV);\r
-       ADD_KEYWORD(true,TK_TRUE);\r
-       ADD_KEYWORD(false,TK_FALSE);\r
-       ADD_KEYWORD(static,TK_STATIC);\r
-\r
-       _readf = rg;\r
-       _up = up;\r
-       _lasttokenline = _currentline = 1;\r
-       _currentcolumn = 0;\r
-       _prevtoken = -1;\r
-       Next();\r
-}\r
-\r
-void SQLexer::Error(const SQChar *err)\r
-{\r
-       _errfunc(_errtarget,err);\r
-}\r
-\r
-void SQLexer::Next()\r
-{\r
-       SQInteger t = _readf(_up);\r
-       if(t > MAX_CHAR) Error(_SC("Invalid character"));\r
-       if(t != 0) {\r
-               _currdata = (LexChar)t;\r
-               return;\r
-       }\r
-       _currdata = SQUIRREL_EOB;\r
-}\r
-\r
-const SQChar *SQLexer::Tok2Str(SQInteger tok)\r
-{\r
-       SQObjectPtr itr, key, val;\r
-       SQInteger nitr;\r
-       while((nitr = _keywords->Next(false,itr, key, val)) != -1) {\r
-               itr = (SQInteger)nitr;\r
-               if(((SQInteger)_integer(val)) == tok)\r
-                       return _stringval(key);\r
-       }\r
-       return NULL;\r
-}\r
-\r
-void SQLexer::LexBlockComment()\r
-{\r
-       bool done = false;\r
-       while(!done) {\r
-               switch(CUR_CHAR) {\r
-                       case _SC('*'): { NEXT(); if(CUR_CHAR == _SC('/')) { done = true; NEXT(); }}; continue;\r
-                       case _SC('\n'): _currentline++; NEXT(); continue;\r
-                       case SQUIRREL_EOB: Error(_SC("missing \"*/\" in comment"));\r
-                       default: NEXT();\r
-               }\r
-       }\r
-}\r
-\r
-SQInteger SQLexer::Lex()\r
-{\r
-       _lasttokenline = _currentline;\r
-       while(CUR_CHAR != SQUIRREL_EOB) {\r
-               switch(CUR_CHAR){\r
-               case _SC('\t'): case _SC('\r'): case _SC(' '): NEXT(); continue;\r
-               case _SC('\n'):\r
-                       _currentline++;\r
-                       _prevtoken=_curtoken;\r
-                       _curtoken=_SC('\n');\r
-                       NEXT();\r
-                       _currentcolumn=1;\r
-                       continue;\r
-               case _SC('/'):\r
-                       NEXT();\r
-                       switch(CUR_CHAR){\r
-                       case _SC('*'):\r
-                               NEXT();\r
-                               LexBlockComment();\r
-                               continue;       \r
-                       case _SC('/'):\r
-                               do { NEXT(); } while (CUR_CHAR != _SC('\n') && (!IS_EOB()));\r
-                               continue;\r
-                       case _SC('='):\r
-                               NEXT();\r
-                               RETURN_TOKEN(TK_DIVEQ);\r
-                               continue;\r
-                       case _SC('>'):\r
-                               NEXT();\r
-                               RETURN_TOKEN(TK_ATTR_CLOSE);\r
-                               continue;\r
-                       default:\r
-                               RETURN_TOKEN('/');\r
-                       }\r
-               case _SC('='):\r
-                       NEXT();\r
-                       if (CUR_CHAR != _SC('=')){ RETURN_TOKEN('=') }\r
-                       else { NEXT(); RETURN_TOKEN(TK_EQ); }\r
-               case _SC('<'):\r
-                       NEXT();\r
-                       if ( CUR_CHAR == _SC('=') ) { NEXT(); RETURN_TOKEN(TK_LE) }\r
-                       else if ( CUR_CHAR == _SC('-') ) { NEXT(); RETURN_TOKEN(TK_NEWSLOT); }\r
-                       else if ( CUR_CHAR == _SC('<') ) { NEXT(); RETURN_TOKEN(TK_SHIFTL); }\r
-                       else if ( CUR_CHAR == _SC('/') ) { NEXT(); RETURN_TOKEN(TK_ATTR_OPEN); }\r
-                       //else if ( CUR_CHAR == _SC('[') ) { NEXT(); ReadMultilineString(); RETURN_TOKEN(TK_STRING_LITERAL); }\r
-                       else { RETURN_TOKEN('<') }\r
-               case _SC('>'):\r
-                       NEXT();\r
-                       if (CUR_CHAR == _SC('=')){ NEXT(); RETURN_TOKEN(TK_GE);}\r
-                       else if(CUR_CHAR == _SC('>')){ \r
-                               NEXT(); \r
-                               if(CUR_CHAR == _SC('>')){\r
-                                       NEXT();\r
-                                       RETURN_TOKEN(TK_USHIFTR);\r
-                               }\r
-                               RETURN_TOKEN(TK_SHIFTR);\r
-                       }\r
-                       else { RETURN_TOKEN('>') }\r
-               case _SC('!'):\r
-                       NEXT();\r
-                       if (CUR_CHAR != _SC('=')){ RETURN_TOKEN('!')}\r
-                       else { NEXT(); RETURN_TOKEN(TK_NE); }\r
-               case _SC('@'): {\r
-                       SQInteger stype;\r
-                       NEXT(); \r
-                       if(CUR_CHAR != _SC('"'))\r
-                               Error(_SC("string expected"));\r
-                       if((stype=ReadString('"',true))!=-1) {\r
-                               RETURN_TOKEN(stype);\r
-                       }\r
-                       Error(_SC("error parsing the string"));\r
-                                          }\r
-               case _SC('"'):\r
-               case _SC('\''): {\r
-                       SQInteger stype;\r
-                       if((stype=ReadString(CUR_CHAR,false))!=-1){\r
-                               RETURN_TOKEN(stype);\r
-                       }\r
-                       Error(_SC("error parsing the string"));\r
-                       }\r
-               case _SC('{'): case _SC('}'): case _SC('('): case _SC(')'): case _SC('['): case _SC(']'):\r
-               case _SC(';'): case _SC(','): case _SC('?'): case _SC('^'): case _SC('~'):\r
-                       {SQInteger ret = CUR_CHAR;\r
-                       NEXT(); RETURN_TOKEN(ret); }\r
-               case _SC('.'):\r
-                       NEXT();\r
-                       if (CUR_CHAR != _SC('.')){ RETURN_TOKEN('.') }\r
-                       NEXT();\r
-                       if (CUR_CHAR != _SC('.')){ Error(_SC("invalid token '..'")); }\r
-                       NEXT();\r
-                       RETURN_TOKEN(TK_VARPARAMS);\r
-               case _SC('&'):\r
-                       NEXT();\r
-                       if (CUR_CHAR != _SC('&')){ RETURN_TOKEN('&') }\r
-                       else { NEXT(); RETURN_TOKEN(TK_AND); }\r
-               case _SC('|'):\r
-                       NEXT();\r
-                       if (CUR_CHAR != _SC('|')){ RETURN_TOKEN('|') }\r
-                       else { NEXT(); RETURN_TOKEN(TK_OR); }\r
-               case _SC(':'):\r
-                       NEXT();\r
-                       if (CUR_CHAR != _SC(':')){ RETURN_TOKEN(':') }\r
-                       else { NEXT(); RETURN_TOKEN(TK_DOUBLE_COLON); }\r
-               case _SC('*'):\r
-                       NEXT();\r
-                       if (CUR_CHAR == _SC('=')){ NEXT(); RETURN_TOKEN(TK_MULEQ);}\r
-                       else RETURN_TOKEN('*');\r
-               case _SC('%'):\r
-                       NEXT();\r
-                       if (CUR_CHAR == _SC('=')){ NEXT(); RETURN_TOKEN(TK_MODEQ);}\r
-                       else RETURN_TOKEN('%');\r
-               case _SC('-'):\r
-                       NEXT();\r
-                       if (CUR_CHAR == _SC('=')){ NEXT(); RETURN_TOKEN(TK_MINUSEQ);}\r
-                       else if  (CUR_CHAR == _SC('-')){ NEXT(); RETURN_TOKEN(TK_MINUSMINUS);}\r
-                       else RETURN_TOKEN('-');\r
-               case _SC('+'):\r
-                       NEXT();\r
-                       if (CUR_CHAR == _SC('=')){ NEXT(); RETURN_TOKEN(TK_PLUSEQ);}\r
-                       else if (CUR_CHAR == _SC('+')){ NEXT(); RETURN_TOKEN(TK_PLUSPLUS);}\r
-                       else RETURN_TOKEN('+');\r
-               case SQUIRREL_EOB:\r
-                       return 0;\r
-               default:{\r
-                               if (scisdigit(CUR_CHAR)) {\r
-                                       SQInteger ret = ReadNumber();\r
-                                       RETURN_TOKEN(ret);\r
-                               }\r
-                               else if (scisalpha(CUR_CHAR) || CUR_CHAR == _SC('_')) {\r
-                                       SQInteger t = ReadID();\r
-                                       RETURN_TOKEN(t);\r
-                               }\r
-                               else {\r
-                                       SQInteger c = CUR_CHAR;\r
-                                       if (sciscntrl((int)c)) Error(_SC("unexpected character(control)"));\r
-                                       NEXT();\r
-                                       RETURN_TOKEN(c);  \r
-                               }\r
-                               RETURN_TOKEN(0);\r
-                       }\r
-               }\r
-       }\r
-       return 0;    \r
-}\r
-       \r
-SQInteger SQLexer::GetIDType(SQChar *s)\r
-{\r
-       SQObjectPtr t;\r
-       if(_keywords->Get(SQString::Create(_sharedstate, s), t)) {\r
-               return SQInteger(_integer(t));\r
-       }\r
-       return TK_IDENTIFIER;\r
-}\r
-\r
-\r
-SQInteger SQLexer::ReadString(SQInteger ndelim,bool verbatim)\r
-{\r
-       INIT_TEMP_STRING();\r
-       NEXT();\r
-       if(IS_EOB()) return -1;\r
-       for(;;) {\r
-               while(CUR_CHAR != ndelim) {\r
-                       switch(CUR_CHAR) {\r
-                       case SQUIRREL_EOB:\r
-                               Error(_SC("unfinished string"));\r
-                               return -1;\r
-                       case _SC('\n'): \r
-                               if(!verbatim) Error(_SC("newline in a constant")); \r
-                               APPEND_CHAR(CUR_CHAR); NEXT(); \r
-                               _currentline++;\r
-                               break;\r
-                       case _SC('\\'):\r
-                               if(verbatim) {\r
-                                       APPEND_CHAR('\\'); NEXT(); \r
-                               }\r
-                               else {\r
-                                       NEXT();\r
-                                       switch(CUR_CHAR) {\r
-                                       case _SC('x'): NEXT(); {\r
-                                               if(!isxdigit(CUR_CHAR)) Error(_SC("hexadecimal number expected")); \r
-                                               const SQInteger maxdigits = 4;\r
-                                               SQChar temp[maxdigits+1];\r
-                                               SQInteger n = 0;\r
-                                               while(isxdigit(CUR_CHAR) && n < maxdigits) {\r
-                                                       temp[n] = CUR_CHAR;\r
-                                                       n++;\r
-                                                       NEXT();\r
-                                               }\r
-                                               temp[n] = 0;\r
-                                               SQChar *sTemp;\r
-                                               APPEND_CHAR((SQChar)scstrtoul(temp,&sTemp,16));\r
-                                       }\r
-                                   break;\r
-                                       case _SC('t'): APPEND_CHAR(_SC('\t')); NEXT(); break;\r
-                                       case _SC('a'): APPEND_CHAR(_SC('\a')); NEXT(); break;\r
-                                       case _SC('b'): APPEND_CHAR(_SC('\b')); NEXT(); break;\r
-                                       case _SC('n'): APPEND_CHAR(_SC('\n')); NEXT(); break;\r
-                                       case _SC('r'): APPEND_CHAR(_SC('\r')); NEXT(); break;\r
-                                       case _SC('v'): APPEND_CHAR(_SC('\v')); NEXT(); break;\r
-                                       case _SC('f'): APPEND_CHAR(_SC('\f')); NEXT(); break;\r
-                                       case _SC('0'): APPEND_CHAR(_SC('\0')); NEXT(); break;\r
-                                       case _SC('\\'): APPEND_CHAR(_SC('\\')); NEXT(); break;\r
-                                       case _SC('"'): APPEND_CHAR(_SC('"')); NEXT(); break;\r
-                                       case _SC('\''): APPEND_CHAR(_SC('\'')); NEXT(); break;\r
-                                       default:\r
-                                               Error(_SC("unrecognised escaper char"));\r
-                                       break;\r
-                                       }\r
-                               }\r
-                               break;\r
-                       default:\r
-                               APPEND_CHAR(CUR_CHAR);\r
-                               NEXT();\r
-                       }\r
-               }\r
-               NEXT();\r
-               if(verbatim && CUR_CHAR == '"') { //double quotation\r
-                       APPEND_CHAR(CUR_CHAR);\r
-                       NEXT();\r
-               }\r
-               else {\r
-                       break;\r
-               }\r
-       }\r
-       TERMINATE_BUFFER();\r
-       SQInteger len = _longstr.size()-1;\r
-       if(ndelim == _SC('\'')) {\r
-               if(len == 0) Error(_SC("empty constant"));\r
-               if(len > 1) Error(_SC("constant too long"));\r
-               _nvalue = _longstr[0];\r
-               return TK_INTEGER;\r
-       }\r
-       _svalue = &_longstr[0];\r
-       return TK_STRING_LITERAL;\r
-}\r
-\r
-void LexHexadecimal(const SQChar *s,SQUnsignedInteger *res)\r
-{\r
-       *res = 0;\r
-       while(*s != 0)\r
-       {\r
-               if(scisdigit(*s)) *res = (*res)*16+((*s++)-'0');\r
-               else if(scisxdigit(*s)) *res = (*res)*16+(toupper(*s++)-'A'+10);\r
-               else { assert(0); }\r
-       }\r
-}\r
-\r
-void LexInteger(const SQChar *s,SQUnsignedInteger *res)\r
-{\r
-       *res = 0;\r
-       while(*s != 0)\r
-       {\r
-               *res = (*res)*10+((*s++)-'0');\r
-       }\r
-}\r
-\r
-SQInteger isexponent(SQInteger c) { return c == 'e' || c=='E'; }\r
-#define MAX_HEX_DIGITS (sizeof(SQInteger)*2)\r
-SQInteger SQLexer::ReadNumber()\r
-{\r
-#define TINT 1\r
-#define TFLOAT 2\r
-#define THEX 3\r
-#define TSCIENTIFIC 4\r
-       SQInteger type = TINT, firstchar = CUR_CHAR;\r
-       SQChar *sTemp;\r
-       INIT_TEMP_STRING();\r
-       NEXT();\r
-       if(firstchar == _SC('0') && toupper(CUR_CHAR) == _SC('X')) {\r
-               NEXT();\r
-               type = THEX;\r
-               while(isxdigit(CUR_CHAR)) {\r
-                       APPEND_CHAR(CUR_CHAR);\r
-                       NEXT();\r
-               }\r
-               if(_longstr.size() > MAX_HEX_DIGITS) Error(_SC("too many digits for an Hex number"));\r
-       }\r
-       else {\r
-               APPEND_CHAR((int)firstchar);\r
-               while (CUR_CHAR == _SC('.') || scisdigit(CUR_CHAR) || isexponent(CUR_CHAR)) {\r
-            if(CUR_CHAR == _SC('.')) type = TFLOAT;\r
-                       if(isexponent(CUR_CHAR)) {\r
-                               if(type != TFLOAT) Error(_SC("invalid numeric format"));\r
-                               type = TSCIENTIFIC;\r
-                               APPEND_CHAR(CUR_CHAR);\r
-                               NEXT();\r
-                               if(CUR_CHAR == '+' || CUR_CHAR == '-'){\r
-                                       APPEND_CHAR(CUR_CHAR);\r
-                                       NEXT();\r
-                               }\r
-                               if(!scisdigit(CUR_CHAR)) Error(_SC("exponent expected"));\r
-                       }\r
-                       \r
-                       APPEND_CHAR(CUR_CHAR);\r
-                       NEXT();\r
-               }\r
-       }\r
-       TERMINATE_BUFFER();\r
-       switch(type) {\r
-       case TSCIENTIFIC:\r
-       case TFLOAT:\r
-               _fvalue = (SQFloat)scstrtod(&_longstr[0],&sTemp);\r
-               return TK_FLOAT;\r
-       case TINT:\r
-               LexInteger(&_longstr[0],(SQUnsignedInteger *)&_nvalue);\r
-               return TK_INTEGER;\r
-       case THEX:\r
-               LexHexadecimal(&_longstr[0],(SQUnsignedInteger *)&_nvalue);\r
-               return TK_INTEGER;\r
-       }\r
-       return 0;\r
-}\r
-\r
-SQInteger SQLexer::ReadID()\r
-{\r
-       SQInteger res;\r
-       INIT_TEMP_STRING();\r
-       do {\r
-               APPEND_CHAR(CUR_CHAR);\r
-               NEXT();\r
-       } while(scisalnum(CUR_CHAR) || CUR_CHAR == _SC('_'));\r
-       TERMINATE_BUFFER();\r
-       res = GetIDType(&_longstr[0]);\r
-       if(res == TK_IDENTIFIER || res == TK_CONSTRUCTOR) {\r
-               _svalue = &_longstr[0];\r
-       }\r
-       return res;\r
-}\r
+/*
+       see copyright notice in squirrel.h
+*/
+#include "sqpcheader.h"
+#include <ctype.h>
+#include <stdlib.h>
+#include "sqtable.h"
+#include "sqstring.h"
+#include "sqcompiler.h"
+#include "sqlexer.h"
+
+#define CUR_CHAR (_currdata)
+#define RETURN_TOKEN(t) { _prevtoken = _curtoken; _curtoken = t; return t;}
+#define IS_EOB() (CUR_CHAR <= SQUIRREL_EOB)
+#define NEXT() {Next();_currentcolumn++;}
+#define INIT_TEMP_STRING() { _longstr.resize(0);}
+#define APPEND_CHAR(c) { _longstr.push_back(c);}
+#define TERMINATE_BUFFER() {_longstr.push_back(_SC('\0'));}
+#define ADD_KEYWORD(key,id) _keywords->NewSlot( SQString::Create(ss, _SC(#key)) ,SQInteger(id))
+
+SQLexer::SQLexer(){}
+SQLexer::~SQLexer()
+{
+       _keywords->Release();
+}
+
+void SQLexer::Init(SQSharedState *ss, SQLEXREADFUNC rg, SQUserPointer up,CompilerErrorFunc efunc,void *ed)
+{
+       _errfunc = efunc;
+       _errtarget = ed;
+       _sharedstate = ss;
+       _keywords = SQTable::Create(ss, 26);
+       ADD_KEYWORD(while, TK_WHILE);
+       ADD_KEYWORD(do, TK_DO);
+       ADD_KEYWORD(if, TK_IF);
+       ADD_KEYWORD(else, TK_ELSE);
+       ADD_KEYWORD(break, TK_BREAK);
+       ADD_KEYWORD(continue, TK_CONTINUE);
+       ADD_KEYWORD(return, TK_RETURN);
+       ADD_KEYWORD(null, TK_NULL);
+       ADD_KEYWORD(function, TK_FUNCTION);
+       ADD_KEYWORD(local, TK_LOCAL);
+       ADD_KEYWORD(for, TK_FOR);
+       ADD_KEYWORD(foreach, TK_FOREACH);
+       ADD_KEYWORD(in, TK_IN);
+       ADD_KEYWORD(typeof, TK_TYPEOF);
+       ADD_KEYWORD(delegate, TK_DELEGATE);
+       ADD_KEYWORD(delete, TK_DELETE);
+       ADD_KEYWORD(try, TK_TRY);
+       ADD_KEYWORD(catch, TK_CATCH);
+       ADD_KEYWORD(throw, TK_THROW);
+       ADD_KEYWORD(clone, TK_CLONE);
+       ADD_KEYWORD(yield, TK_YIELD);
+       ADD_KEYWORD(resume, TK_RESUME);
+       ADD_KEYWORD(switch, TK_SWITCH);
+       ADD_KEYWORD(case, TK_CASE);
+       ADD_KEYWORD(default, TK_DEFAULT);
+       ADD_KEYWORD(this, TK_THIS);
+       ADD_KEYWORD(parent,TK_PARENT);
+       ADD_KEYWORD(class,TK_CLASS);
+       ADD_KEYWORD(extends,TK_EXTENDS);
+       ADD_KEYWORD(constructor,TK_CONSTRUCTOR);
+       ADD_KEYWORD(instanceof,TK_INSTANCEOF);
+       ADD_KEYWORD(vargc,TK_VARGC);
+       ADD_KEYWORD(vargv,TK_VARGV);
+       ADD_KEYWORD(true,TK_TRUE);
+       ADD_KEYWORD(false,TK_FALSE);
+       ADD_KEYWORD(static,TK_STATIC);
+
+       _readf = rg;
+       _up = up;
+       _lasttokenline = _currentline = 1;
+       _currentcolumn = 0;
+       _prevtoken = -1;
+       Next();
+}
+
+void SQLexer::Error(const SQChar *err)
+{
+       _errfunc(_errtarget,err);
+}
+
+void SQLexer::Next()
+{
+       SQInteger t = _readf(_up);
+       if(t > MAX_CHAR) Error(_SC("Invalid character"));
+       if(t != 0) {
+               _currdata = (LexChar)t;
+               return;
+       }
+       _currdata = SQUIRREL_EOB;
+}
+
+const SQChar *SQLexer::Tok2Str(SQInteger tok)
+{
+       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;
+}
+
+void SQLexer::LexBlockComment()
+{
+       bool done = false;
+       while(!done) {
+               switch(CUR_CHAR) {
+                       case _SC('*'): { NEXT(); if(CUR_CHAR == _SC('/')) { done = true; NEXT(); }}; continue;
+                       case _SC('\n'): _currentline++; NEXT(); continue;
+                       case SQUIRREL_EOB: Error(_SC("missing \"*/\" in comment"));
+                       default: NEXT();
+               }
+       }
+}
+
+SQInteger SQLexer::Lex()
+{
+       _lasttokenline = _currentline;
+       while(CUR_CHAR != SQUIRREL_EOB) {
+               switch(CUR_CHAR){
+               case _SC('\t'): case _SC('\r'): case _SC(' '): NEXT(); continue;
+               case _SC('\n'):
+                       _currentline++;
+                       _prevtoken=_curtoken;
+                       _curtoken=_SC('\n');
+                       NEXT();
+                       _currentcolumn=1;
+                       continue;
+               case _SC('/'):
+                       NEXT();
+                       switch(CUR_CHAR){
+                       case _SC('*'):
+                               NEXT();
+                               LexBlockComment();
+                               continue;
+                       case _SC('/'):
+                               do { NEXT(); } while (CUR_CHAR != _SC('\n') && (!IS_EOB()));
+                               continue;
+                       case _SC('='):
+                               NEXT();
+                               RETURN_TOKEN(TK_DIVEQ);
+                               continue;
+                       case _SC('>'):
+                               NEXT();
+                               RETURN_TOKEN(TK_ATTR_CLOSE);
+                               continue;
+                       default:
+                               RETURN_TOKEN('/');
+                       }
+               case _SC('='):
+                       NEXT();
+                       if (CUR_CHAR != _SC('=')){ RETURN_TOKEN('=') }
+                       else { NEXT(); RETURN_TOKEN(TK_EQ); }
+               case _SC('<'):
+                       NEXT();
+                       if ( CUR_CHAR == _SC('=') ) { NEXT(); RETURN_TOKEN(TK_LE) }
+                       else if ( CUR_CHAR == _SC('-') ) { NEXT(); RETURN_TOKEN(TK_NEWSLOT); }
+                       else if ( CUR_CHAR == _SC('<') ) { NEXT(); RETURN_TOKEN(TK_SHIFTL); }
+                       else if ( CUR_CHAR == _SC('/') ) { NEXT(); RETURN_TOKEN(TK_ATTR_OPEN); }
+                       //else if ( CUR_CHAR == _SC('[') ) { NEXT(); ReadMultilineString(); RETURN_TOKEN(TK_STRING_LITERAL); }
+                       else { RETURN_TOKEN('<') }
+               case _SC('>'):
+                       NEXT();
+                       if (CUR_CHAR == _SC('=')){ NEXT(); RETURN_TOKEN(TK_GE);}
+                       else if(CUR_CHAR == _SC('>')){
+                               NEXT();
+                               if(CUR_CHAR == _SC('>')){
+                                       NEXT();
+                                       RETURN_TOKEN(TK_USHIFTR);
+                               }
+                               RETURN_TOKEN(TK_SHIFTR);
+                       }
+                       else { RETURN_TOKEN('>') }
+               case _SC('!'):
+                       NEXT();
+                       if (CUR_CHAR != _SC('=')){ RETURN_TOKEN('!')}
+                       else { NEXT(); RETURN_TOKEN(TK_NE); }
+               case _SC('@'): {
+                       SQInteger stype;
+                       NEXT();
+                       if(CUR_CHAR != _SC('"'))
+                               Error(_SC("string expected"));
+                       if((stype=ReadString('"',true))!=-1) {
+                               RETURN_TOKEN(stype);
+                       }
+                       Error(_SC("error parsing the string"));
+                                          }
+               case _SC('"'):
+               case _SC('\''): {
+                       SQInteger stype;
+                       if((stype=ReadString(CUR_CHAR,false))!=-1){
+                               RETURN_TOKEN(stype);
+                       }
+                       Error(_SC("error parsing the string"));
+                       }
+               case _SC('{'): case _SC('}'): case _SC('('): case _SC(')'): case _SC('['): case _SC(']'):
+               case _SC(';'): case _SC(','): case _SC('?'): case _SC('^'): case _SC('~'):
+                       {SQInteger ret = CUR_CHAR;
+                       NEXT(); RETURN_TOKEN(ret); }
+               case _SC('.'):
+                       NEXT();
+                       if (CUR_CHAR != _SC('.')){ RETURN_TOKEN('.') }
+                       NEXT();
+                       if (CUR_CHAR != _SC('.')){ Error(_SC("invalid token '..'")); }
+                       NEXT();
+                       RETURN_TOKEN(TK_VARPARAMS);
+               case _SC('&'):
+                       NEXT();
+                       if (CUR_CHAR != _SC('&')){ RETURN_TOKEN('&') }
+                       else { NEXT(); RETURN_TOKEN(TK_AND); }
+               case _SC('|'):
+                       NEXT();
+                       if (CUR_CHAR != _SC('|')){ RETURN_TOKEN('|') }
+                       else { NEXT(); RETURN_TOKEN(TK_OR); }
+               case _SC(':'):
+                       NEXT();
+                       if (CUR_CHAR != _SC(':')){ RETURN_TOKEN(':') }
+                       else { NEXT(); RETURN_TOKEN(TK_DOUBLE_COLON); }
+               case _SC('*'):
+                       NEXT();
+                       if (CUR_CHAR == _SC('=')){ NEXT(); RETURN_TOKEN(TK_MULEQ);}
+                       else RETURN_TOKEN('*');
+               case _SC('%'):
+                       NEXT();
+                       if (CUR_CHAR == _SC('=')){ NEXT(); RETURN_TOKEN(TK_MODEQ);}
+                       else RETURN_TOKEN('%');
+               case _SC('-'):
+                       NEXT();
+                       if (CUR_CHAR == _SC('=')){ NEXT(); RETURN_TOKEN(TK_MINUSEQ);}
+                       else if  (CUR_CHAR == _SC('-')){ NEXT(); RETURN_TOKEN(TK_MINUSMINUS);}
+                       else RETURN_TOKEN('-');
+               case _SC('+'):
+                       NEXT();
+                       if (CUR_CHAR == _SC('=')){ NEXT(); RETURN_TOKEN(TK_PLUSEQ);}
+                       else if (CUR_CHAR == _SC('+')){ NEXT(); RETURN_TOKEN(TK_PLUSPLUS);}
+                       else RETURN_TOKEN('+');
+               case SQUIRREL_EOB:
+                       return 0;
+               default:{
+                               if (scisdigit(CUR_CHAR)) {
+                                       SQInteger ret = ReadNumber();
+                                       RETURN_TOKEN(ret);
+                               }
+                               else if (scisalpha(CUR_CHAR) || CUR_CHAR == _SC('_')) {
+                                       SQInteger t = ReadID();
+                                       RETURN_TOKEN(t);
+                               }
+                               else {
+                                       SQInteger c = CUR_CHAR;
+                                       if (sciscntrl((int)c)) Error(_SC("unexpected character(control)"));
+                                       NEXT();
+                                       RETURN_TOKEN(c);
+                               }
+                               RETURN_TOKEN(0);
+                       }
+               }
+       }
+       return 0;
+}
+
+SQInteger SQLexer::GetIDType(SQChar *s)
+{
+       SQObjectPtr t;
+       if(_keywords->Get(SQString::Create(_sharedstate, s), t)) {
+               return SQInteger(_integer(t));
+       }
+       return TK_IDENTIFIER;
+}
+
+
+SQInteger SQLexer::ReadString(SQInteger ndelim,bool verbatim)
+{
+       INIT_TEMP_STRING();
+       NEXT();
+       if(IS_EOB()) return -1;
+       for(;;) {
+               while(CUR_CHAR != ndelim) {
+                       switch(CUR_CHAR) {
+                       case SQUIRREL_EOB:
+                               Error(_SC("unfinished string"));
+                               return -1;
+                       case _SC('\n'):
+                               if(!verbatim) Error(_SC("newline in a constant"));
+                               APPEND_CHAR(CUR_CHAR); NEXT();
+                               _currentline++;
+                               break;
+                       case _SC('\\'):
+                               if(verbatim) {
+                                       APPEND_CHAR('\\'); NEXT();
+                               }
+                               else {
+                                       NEXT();
+                                       switch(CUR_CHAR) {
+                                       case _SC('x'): NEXT(); {
+                                               if(!isxdigit(CUR_CHAR)) Error(_SC("hexadecimal number expected"));
+                                               const SQInteger maxdigits = 4;
+                                               SQChar temp[maxdigits+1];
+                                               SQInteger n = 0;
+                                               while(isxdigit(CUR_CHAR) && n < maxdigits) {
+                                                       temp[n] = CUR_CHAR;
+                                                       n++;
+                                                       NEXT();
+                                               }
+                                               temp[n] = 0;
+                                               SQChar *sTemp;
+                                               APPEND_CHAR((SQChar)scstrtoul(temp,&sTemp,16));
+                                       }
+                                   break;
+                                       case _SC('t'): APPEND_CHAR(_SC('\t')); NEXT(); break;
+                                       case _SC('a'): APPEND_CHAR(_SC('\a')); NEXT(); break;
+                                       case _SC('b'): APPEND_CHAR(_SC('\b')); NEXT(); break;
+                                       case _SC('n'): APPEND_CHAR(_SC('\n')); NEXT(); break;
+                                       case _SC('r'): APPEND_CHAR(_SC('\r')); NEXT(); break;
+                                       case _SC('v'): APPEND_CHAR(_SC('\v')); NEXT(); break;
+                                       case _SC('f'): APPEND_CHAR(_SC('\f')); NEXT(); break;
+                                       case _SC('0'): APPEND_CHAR(_SC('\0')); NEXT(); break;
+                                       case _SC('\\'): APPEND_CHAR(_SC('\\')); NEXT(); break;
+                                       case _SC('"'): APPEND_CHAR(_SC('"')); NEXT(); break;
+                                       case _SC('\''): APPEND_CHAR(_SC('\'')); NEXT(); break;
+                                       default:
+                                               Error(_SC("unrecognised escaper char"));
+                                       break;
+                                       }
+                               }
+                               break;
+                       default:
+                               APPEND_CHAR(CUR_CHAR);
+                               NEXT();
+                       }
+               }
+               NEXT();
+               if(verbatim && CUR_CHAR == '"') { //double quotation
+                       APPEND_CHAR(CUR_CHAR);
+                       NEXT();
+               }
+               else {
+                       break;
+               }
+       }
+       TERMINATE_BUFFER();
+       SQInteger len = _longstr.size()-1;
+       if(ndelim == _SC('\'')) {
+               if(len == 0) Error(_SC("empty constant"));
+               if(len > 1) Error(_SC("constant too long"));
+               _nvalue = _longstr[0];
+               return TK_INTEGER;
+       }
+       _svalue = &_longstr[0];
+       return TK_STRING_LITERAL;
+}
+
+void LexHexadecimal(const SQChar *s,SQUnsignedInteger *res)
+{
+       *res = 0;
+       while(*s != 0)
+       {
+               if(scisdigit(*s)) *res = (*res)*16+((*s++)-'0');
+               else if(scisxdigit(*s)) *res = (*res)*16+(toupper(*s++)-'A'+10);
+               else { assert(0); }
+       }
+}
+
+void LexInteger(const SQChar *s,SQUnsignedInteger *res)
+{
+       *res = 0;
+       while(*s != 0)
+       {
+               *res = (*res)*10+((*s++)-'0');
+       }
+}
+
+SQInteger isexponent(SQInteger c) { return c == 'e' || c=='E'; }
+#define MAX_HEX_DIGITS (sizeof(SQInteger)*2)
+SQInteger SQLexer::ReadNumber()
+{
+#define TINT 1
+#define TFLOAT 2
+#define THEX 3
+#define TSCIENTIFIC 4
+       SQInteger type = TINT, firstchar = CUR_CHAR;
+       SQChar *sTemp;
+       INIT_TEMP_STRING();
+       NEXT();
+       if(firstchar == _SC('0') && toupper(CUR_CHAR) == _SC('X')) {
+               NEXT();
+               type = THEX;
+               while(isxdigit(CUR_CHAR)) {
+                       APPEND_CHAR(CUR_CHAR);
+                       NEXT();
+               }
+               if(_longstr.size() > MAX_HEX_DIGITS) Error(_SC("too many digits for an Hex number"));
+       }
+       else {
+               APPEND_CHAR((int)firstchar);
+               while (CUR_CHAR == _SC('.') || scisdigit(CUR_CHAR) || isexponent(CUR_CHAR)) {
+            if(CUR_CHAR == _SC('.')) type = TFLOAT;
+                       if(isexponent(CUR_CHAR)) {
+                               if(type != TFLOAT) Error(_SC("invalid numeric format"));
+                               type = TSCIENTIFIC;
+                               APPEND_CHAR(CUR_CHAR);
+                               NEXT();
+                               if(CUR_CHAR == '+' || CUR_CHAR == '-'){
+                                       APPEND_CHAR(CUR_CHAR);
+                                       NEXT();
+                               }
+                               if(!scisdigit(CUR_CHAR)) Error(_SC("exponent expected"));
+                       }
+
+                       APPEND_CHAR(CUR_CHAR);
+                       NEXT();
+               }
+       }
+       TERMINATE_BUFFER();
+       switch(type) {
+       case TSCIENTIFIC:
+       case TFLOAT:
+               _fvalue = (SQFloat)scstrtod(&_longstr[0],&sTemp);
+               return TK_FLOAT;
+       case TINT:
+               LexInteger(&_longstr[0],(SQUnsignedInteger *)&_nvalue);
+               return TK_INTEGER;
+       case THEX:
+               LexHexadecimal(&_longstr[0],(SQUnsignedInteger *)&_nvalue);
+               return TK_INTEGER;
+       }
+       return 0;
+}
+
+SQInteger SQLexer::ReadID()
+{
+       SQInteger res;
+       INIT_TEMP_STRING();
+       do {
+               APPEND_CHAR(CUR_CHAR);
+               NEXT();
+       } while(scisalnum(CUR_CHAR) || CUR_CHAR == _SC('_'));
+       TERMINATE_BUFFER();
+       res = GetIDType(&_longstr[0]);
+       if(res == TK_IDENTIFIER || res == TK_CONSTRUCTOR) {
+               _svalue = &_longstr[0];
+       }
+       return res;
+}