Sfoglia il codice sorgente

Add a SQLexer::LookaheadLex method to facilitate compile/run more C/C++ code

mingodad 9 anni fa
parent
commit
4901b63c83
4 ha cambiato i file con 672 aggiunte e 592 eliminazioni
  1. 20 11
      SquiLu/squirrel/sq_lexer.cpp
  2. 65 62
      SquiLu/squirrel/sqcompiler.cpp
  3. 491 471
      SquiLu/squirrel/sqlexer.cpp
  4. 96 48
      SquiLu/squirrel/sqlexer.h

+ 20 - 11
SquiLu/squirrel/sq_lexer.cpp

@@ -79,7 +79,7 @@ static SQRESULT sq_SQLexer_constructor(HSQUIRRELVM v){
 
     self->lex->Init(v->_sharedstate, sq_strbuf_lexfeed, &self->buf, NULL, NULL, want_comments);
 
-    sq_setinstanceup(v, 1, self);
+    sq_setinstanceup(v, 1, self);
     sq_setreleasehook(v,1, SQLexer_release_hook);
 
 	return 1;
@@ -98,7 +98,7 @@ static SQRESULT sq_SQLexer_lasterror(HSQUIRRELVM v){
 	SQ_FUNC_VARS_NO_TOP(v);
 	GET_SQLexer_INSTANCE();
 
-    sq_pushstring(v, self->lex->_lasterror, -1);
+    sq_pushstring(v, self->lex->data->lasterror, -1);
 	return 1;
 }
 
@@ -106,7 +106,7 @@ static SQRESULT sq_SQLexer_longstr(HSQUIRRELVM v){
 	SQ_FUNC_VARS_NO_TOP(v);
 	GET_SQLexer_INSTANCE();
 
-    sq_pushstring(v, &self->lex->_longstr[0], self->lex->_longstr.size());
+    sq_pushstring(v, &self->lex->data->longstr[0], self->lex->data->longstr.size());
 	return 1;
 }
 
@@ -136,7 +136,7 @@ static SQRESULT sq_SQLexer_svalue(HSQUIRRELVM v){
 	SQ_FUNC_VARS_NO_TOP(v);
 	GET_SQLexer_INSTANCE();
 
-    if(self->lex->_svalue) sq_pushstring(v, self->lex->_svalue, -1);
+    if(self->lex->data->svalue) sq_pushstring(v, self->lex->data->svalue, -1);
     else sq_pushnull(v);
 	return 1;
 }
@@ -145,7 +145,7 @@ static SQRESULT sq_SQLexer_nvalue(HSQUIRRELVM v){
 	SQ_FUNC_VARS_NO_TOP(v);
 	GET_SQLexer_INSTANCE();
 
-    sq_pushinteger(v, self->lex->_nvalue);
+    sq_pushinteger(v, self->lex->data->nvalue);
 	return 1;
 }
 
@@ -153,7 +153,7 @@ static SQRESULT sq_SQLexer_fvalue(HSQUIRRELVM v){
 	SQ_FUNC_VARS_NO_TOP(v);
 	GET_SQLexer_INSTANCE();
 
-    sq_pushfloat(v, self->lex->_fvalue);
+    sq_pushfloat(v, self->lex->data->fvalue);
 	return 1;
 }
 
@@ -161,7 +161,7 @@ static SQRESULT sq_SQLexer_prevtoken(HSQUIRRELVM v){
 	SQ_FUNC_VARS_NO_TOP(v);
 	GET_SQLexer_INSTANCE();
 
-    sq_pushinteger(v, self->lex->_prevtoken);
+    sq_pushinteger(v, self->lex->data->prevtoken);
 	return 1;
 }
 
@@ -169,7 +169,7 @@ static SQRESULT sq_SQLexer_lasttokenline(HSQUIRRELVM v){
 	SQ_FUNC_VARS_NO_TOP(v);
 	GET_SQLexer_INSTANCE();
 
-    sq_pushinteger(v, self->lex->_lasttokenline);
+    sq_pushinteger(v, self->lex->data->lasttokenline);
 	return 1;
 }
 
@@ -177,7 +177,7 @@ static SQRESULT sq_SQLexer_lasttokencolumn(HSQUIRRELVM v){
 	SQ_FUNC_VARS_NO_TOP(v);
 	GET_SQLexer_INSTANCE();
 
-    sq_pushinteger(v, self->lex->_lasttokencolumn);
+    sq_pushinteger(v, self->lex->data->lasttokencolumn);
 	return 1;
 }
 
@@ -185,7 +185,7 @@ static SQRESULT sq_SQLexer_currentline(HSQUIRRELVM v){
 	SQ_FUNC_VARS_NO_TOP(v);
 	GET_SQLexer_INSTANCE();
 
-    sq_pushinteger(v, self->lex->_currentline);
+    sq_pushinteger(v, self->lex->data->currentline);
 	return 1;
 }
 
@@ -193,7 +193,7 @@ static SQRESULT sq_SQLexer_currentcolumn(HSQUIRRELVM v){
 	SQ_FUNC_VARS_NO_TOP(v);
 	GET_SQLexer_INSTANCE();
 
-    sq_pushinteger(v, self->lex->_currentcolumn);
+    sq_pushinteger(v, self->lex->data->currentcolumn);
 	return 1;
 }
 
@@ -205,6 +205,14 @@ static SQRESULT sq_SQLexer_lex(HSQUIRRELVM v){
 	return 1;
 }
 
+static SQRESULT sq_SQLexer_lookaheadlex(HSQUIRRELVM v){
+	SQ_FUNC_VARS_NO_TOP(v);
+	GET_SQLexer_INSTANCE();
+
+    sq_pushinteger(v, self->lex->LookaheadLex());
+	return 1;
+}
+
 static SQRESULT sq_SQLexer_first_enum_token(HSQUIRRELVM v){
 	SQ_FUNC_VARS_NO_TOP(v);
 	GET_SQLexer_INSTANCE();
@@ -241,6 +249,7 @@ static SQRegFunction SQLexer_obj_funcs[]={
 	_DECL_SQLEXER_FUNC(first_enum_token, 1, _SC(".")),
 	_DECL_SQLEXER_FUNC(last_enum_token, 1, _SC(".")),
 	_DECL_SQLEXER_FUNC(lex, 1, _SC(".")),
+	_DECL_SQLEXER_FUNC(lookaheadlex, 1, _SC(".")),
 	{0,0}
 };
 #undef _DECL_SQLEXER_FUNC

+ 65 - 62
SquiLu/squirrel/sqcompiler.cpp

@@ -245,7 +245,7 @@ public:
 	    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,
+                        _stringval(_sourcename), _lex.data->currentline, _lex.data->currentcolumn,
                          found, _stringval(name));
 	    }
 	    else if(checkLocals) CheckLocalNameScope(name, -1, false);
@@ -262,13 +262,13 @@ public:
                 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));
+                        _stringval(_sourcename), _lex.data->currentline, _lex.data->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));
+                        _stringval(_sourcename), _lex.data->currentline, _lex.data->currentcolumn, _stringval(name));
 	    }
 	    if(checkGlobals) CheckGlobalName(name, false, false);
 	    SQObjectPtr strongid = name;
@@ -336,7 +336,7 @@ public:
             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));
+            _stringval(_sourcename), _lex.data->currentline, _lex.data->currentcolumn,  _stringval(key));
 	}
 
 	bool ConstsGet(const SQObjectPtr &key,SQObjectPtr &val){
@@ -361,16 +361,16 @@ public:
 		switch(tok)
 		{
 		case TK_IDENTIFIER:
-			ret = _fs->CreateString(_lex._svalue);
+			ret = _fs->CreateString(_lex.data->svalue);
 			break;
 		case TK_STRING_LITERAL:
-			ret = _fs->CreateString(_lex._svalue,_lex._longstr.size()-1);
+			ret = _fs->CreateString(_lex.data->svalue,_lex.data->longstr.size()-1);
 			break;
 		case TK_INTEGER:
-			ret = SQObjectPtr(_lex._nvalue);
+			ret = SQObjectPtr(_lex.data->nvalue);
 			break;
 		case TK_FLOAT:
-			ret = SQObjectPtr(_lex._fvalue);
+			ret = SQObjectPtr(_lex.data->fvalue);
 			break;
         default:
             ret = _fs->CreateString(_lex.GetTokenName(_token));
@@ -428,7 +428,7 @@ public:
 	    }
 		return GetTokenObject(TK_IDENTIFIER);
 	}
-	bool IsEndOfStatement() { return ((_lex._prevtoken == _SC('\n')) || (_token == SQUIRREL_EOB) || (_token == _SC('}')) || (_token == _SC(';'))); }
+	bool IsEndOfStatement() { return ((_lex.data->prevtoken == _SC('\n')) || (_token == SQUIRREL_EOB) || (_token == _SC('}')) || (_token == _SC(';'))); }
 	void OptionalSemicolon()
 	{
 		if(_token == _SC(';')) { Lex(); return; }
@@ -446,8 +446,8 @@ public:
 
     void Pragma()
     {
-        int line = _lex._currentline;
-        //int column = _lex._currentcolumn;
+        int line = _lex.data->currentline;
+        //int column = _lex.data->currentcolumn;
         Lex();
         SQObject id = Expect(TK_IDENTIFIER);
         if(scstrcmp(_stringval(id), _SC("include")) == 0)
@@ -471,10 +471,10 @@ public:
                 //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_line = _lex.data->currentline;
+                SQInteger saved_column = _lex.data->currentcolumn;
+                SQInteger saved_curdata = _lex.data->currdata;
+                SQInteger saved_prevtoken = _lex.data->prevtoken;
                 SQInteger saved_token = _token;
                 SQObjectPtr saved_source_name = _sourcename;
 
@@ -487,7 +487,7 @@ public:
                 Lex();
                 while(_token > 0){
                     Statement();
-                    if(_lex._prevtoken != _SC('}') && _lex._prevtoken != _SC(';')) OptionalSemicolon();
+                    if(_lex.data->prevtoken != _SC('}') && _lex.data->prevtoken != _SC(';')) OptionalSemicolon();
                 }
 
                 //close file
@@ -496,10 +496,10 @@ public:
                 _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.data->currdata = saved_curdata;
+                _lex.data->prevtoken = saved_prevtoken;
+                _lex.data->currentcolumn = saved_column;
+                _lex.data->currentline = saved_line;
                 _lex._readf = saved_readf;
                 _lex._up = saved_up;
 
@@ -517,7 +517,7 @@ public:
         }
         else
         {
-            _lex._currentline = line;
+            _lex.data->currentline = line;
             Error(_SC("Error: unknown pragma %s\n"), _stringval(id));
         }
     }
@@ -540,10 +540,10 @@ public:
 			Lex();
 			while(_token > 0){
 				Statement();
-				if(_lex._prevtoken != _SC('}') && _lex._prevtoken != _SC(';')) OptionalSemicolon();
+				if(_lex.data->prevtoken != _SC('}') && _lex.data->prevtoken != _SC(';')) OptionalSemicolon();
 			}
             _fs->SetStackSize(stacksize);
-            _fs->AddLineInfos(_lex._currentline, _lineinfo, true);
+            _fs->AddLineInfos(_lex.data->currentline, _lineinfo, true);
             _fs->AddInstruction(_OP_RETURN, 0xFF);
             _fs->SetStackSize(0);
             o =_fs->BuildProto();
@@ -554,11 +554,11 @@ public:
 		else {
 			if(_raiseerror && _ss(_vm)->_compilererrorhandler) {
 				_ss(_vm)->_compilererrorhandler(_vm, _compilererror, type(_sourcename) == OT_STRING?_stringval(_sourcename):_SC("unknown"),
-					_lex._currentline, _lex._currentcolumn);
+					_lex.data->currentline, _lex.data->currentcolumn);
 			}
 			_vm->_lasterror = SQString::Create(_ss(_vm), _compilererror, -1);
-			_vm->_lasterror_line = _lex._currentline;
-			_vm->_lasterror_column = _lex._currentcolumn;
+			_vm->_lasterror_line = _lex.data->currentline;
+			_vm->_lasterror_column = _lex.data->currentcolumn;
 			return false;
 		}
 		return true;
@@ -567,14 +567,14 @@ public:
 	{
 		while(_token != _SC('}') && _token != TK_DEFAULT && _token != TK_CASE) {
 			Statement();
-			if(_lex._prevtoken != _SC('}') && _lex._prevtoken != _SC(';')) OptionalSemicolon();
+			if(_lex.data->prevtoken != _SC('}') && _lex.data->prevtoken != _SC(';')) OptionalSemicolon();
 		}
 	}
 	void Statement(bool closeframe = true)
 	{
 	    _es.etype = EXPR_STATEMENT;
 	    SQObject id;
-		_fs->AddLineInfos(_lex._currentline, _lineinfo);
+		_fs->AddLineInfos(_lex.data->currentline, _lineinfo);
     start_again:
 		switch(_token){
 		case _SC(';'):	Lex();					break;
@@ -695,7 +695,7 @@ public:
             if(_scope.nested)
             {
                 Warning(_SC("%s:%d:%d warning static cualifier is ignored\n"),
-                                          _stringval(_sourcename), _lex._currentline, _lex._currentcolumn);
+                                          _stringval(_sourcename), _lex.data->currentline, _lex.data->currentcolumn);
             }
             Lex(); //ignore it only to allow run some C/C++ code
             goto start_again;
@@ -737,11 +737,14 @@ public:
 		    break;
 
         case TK_IDENTIFIER:
-            id = _fs->CreateString(_lex._svalue);
+            id = _fs->CreateString(_lex.data->svalue);
             if(CheckTypeName(id)) //C/C++ type declaration;
             {
-                LocalDeclStatement();
-                break;
+                if(_lex.LookaheadLex() != _SC('.'))
+                {
+                    LocalDeclStatement();
+                    break;
+                }
             }
 
 		default:
@@ -753,7 +756,7 @@ public:
             if(_token == TK_IDENTIFIER){
                 CommaExpr();
                 if(_token == TK_IDENTIFIER){
-                    Error(_SC(" '=' expected near '%s'"), _lex._svalue);
+                    Error(_SC(" '=' expected near '%s'"), _lex.data->svalue);
                 }
             }
 */
@@ -829,7 +832,7 @@ public:
 		SQObject id;
 		if((_token == TK_IDENTIFIER) && (es.etype == EXPR_STATEMENT))
         {
-            id = _fs->CreateString(_lex._svalue);
+            id = _fs->CreateString(_lex.data->svalue);
         }
         //else id = {}; //old compilers do not allow this
 
@@ -862,7 +865,7 @@ public:
 				break;
 			case _SC('='): //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);
+                                          _stringval(_sourcename), _lex.data->currentline, _lex.data->currentcolumn);
 				switch(ds) {
 				case LOCAL:
 					{
@@ -1099,7 +1102,7 @@ public:
 				}
 				break;
 			case _SC('['):
-				if(_lex._prevtoken == _SC('\n')) Error(_SC("cannot brake deref/or comma needed after [exp]=exp slot declaration"));
+				if(_lex.data->prevtoken == _SC('\n')) Error(_SC("cannot brake deref/or comma needed after [exp]=exp slot declaration"));
 				Lex(); Expression(); Expect(_SC(']'));
 				pos = -1;
 				if(_es.etype==BASE) {
@@ -1188,7 +1191,7 @@ public:
 		switch(_token)
 		{
 		case TK_STRING_LITERAL:
-			_fs->AddInstruction(_OP_LOAD, _fs->PushTarget(), _fs->GetConstant(_fs->CreateString(_lex._svalue,_lex._longstr.size()-1)));
+			_fs->AddInstruction(_OP_LOAD, _fs->PushTarget(), _fs->GetConstant(_fs->CreateString(_lex.data->svalue,_lex.data->longstr.size()-1)));
 			Lex();
 			break;
 		case TK_BASE:
@@ -1206,7 +1209,7 @@ public:
 				SQObject constant;
 
 				switch(_token) {
-					case TK_IDENTIFIER:  id = _fs->CreateString(_lex._svalue);       break;
+					case TK_IDENTIFIER:  id = _fs->CreateString(_lex.data->svalue);       break;
 					case TK_THIS:        id = _fs->CreateString(_SC("this"), 4);        break;
 					case TK_CONSTRUCTOR: id = _fs->CreateString(_SC("constructor"), 11); break;
 					case TK_DESTRUCTOR: id = _fs->CreateString(_SC("destructor"), 10); break;
@@ -1289,8 +1292,8 @@ public:
 			_fs->AddInstruction(_OP_LOADNULLS, _fs->PushTarget(),1);
 			Lex();
 			break;
-		case TK_INTEGER: EmitLoadConstInt(_lex._nvalue,-1); Lex();	break;
-		case TK_FLOAT: EmitLoadConstFloat(_lex._fvalue,-1); Lex(); break;
+		case TK_INTEGER: EmitLoadConstInt(_lex.data->nvalue,-1); Lex();	break;
+		case TK_FLOAT: EmitLoadConstFloat(_lex.data->fvalue,-1); Lex(); break;
 		case TK_TRUE: case TK_FALSE:
 			_fs->AddInstruction(_OP_LOADBOOL, _fs->PushTarget(),_token == TK_TRUE?1:0);
 			Lex();
@@ -1322,15 +1325,15 @@ public:
 		case _SC('-'):
 			Lex();
 			switch(_token) {
-			case TK_INTEGER: EmitLoadConstInt(-_lex._nvalue,-1); Lex(); break;
-			case TK_FLOAT: EmitLoadConstFloat(-_lex._fvalue,-1); Lex(); break;
+			case TK_INTEGER: EmitLoadConstInt(-_lex.data->nvalue,-1); Lex(); break;
+			case TK_FLOAT: EmitLoadConstFloat(-_lex.data->fvalue,-1); Lex(); break;
 			default: UnaryOP(_OP_NEG);
 			}
 			break;
 		case _SC('!'): Lex(); UnaryOP(_OP_NOT); break;
 		case _SC('~'):
 			Lex();
-			if(_token == TK_INTEGER)  { EmitLoadConstInt(~_lex._nvalue,-1); Lex(); break; }
+			if(_token == TK_INTEGER)  { EmitLoadConstInt(~_lex.data->nvalue,-1); Lex(); break; }
 			UnaryOP(_OP_BWNOT);
 			break;
 		case TK_TYPEOF : Lex() ;UnaryOP(_OP_TYPEOF); break;
@@ -1341,7 +1344,7 @@ public:
 		case TK_DELETE : DeleteExpr(); break;
 		case _SC('('): Lex(); CommaExpr(); Expect(_SC(')'));
 			break;
-		case TK___LINE__: EmitLoadConstInt(_lex._currentline,-1); Lex();	break;
+		case TK___LINE__: EmitLoadConstInt(_lex.data->currentline,-1); Lex();	break;
 		case TK___FILE__:
 			_fs->AddInstruction(_OP_LOAD, _fs->PushTarget(), _fs->GetConstant(_sourcename));
 			Lex();
@@ -1352,7 +1355,7 @@ public:
 			break;
 		case TK_IGNORE:
             //Warning("Keyword ignored \"%s\" at line %d:%d\n", _lex.Tok2Str(_token),
-            //        _lex._currentline, _lex._currentcolumn);
+            //        _lex.data->currentline, _lex.data->currentcolumn);
             Lex(); Factor();
             break;
 		default: Error(_SC("expression expected"));
@@ -1797,7 +1800,7 @@ function_params_decl:
 		else {
 			//BEGIN_SCOPE();
 			Statement();
-			if (_lex._prevtoken != _SC('}') && _lex._prevtoken != _SC(';')) OptionalSemicolon();
+			if (_lex.data->prevtoken != _SC('}') && _lex.data->prevtoken != _SC(';')) OptionalSemicolon();
 			//END_SCOPE();
 		}
 	}
@@ -1866,7 +1869,7 @@ if(color == "yellow"){
 		Statement();
 		END_SCOPE();
 		//fix proposed by frosch to correct line number info in stack dumps
-		_fs->AddLineInfos(_lex._currentline, _lineinfo, true);
+		_fs->AddLineInfos(_lex.data->currentline, _lineinfo, true);
 		Expect(TK_WHILE);
 		SQInteger continuetrg = _fs->GetCurrentPos();
 		Expect(_SC('(')); CommaExpr(true); Expect(_SC(')'));
@@ -2053,7 +2056,7 @@ if(color == "yellow"){
 		SQObjectPtr class_name;
 		Lex();
 		if(_token == TK_IDENTIFIER) {
-		    class_name = SQString::Create(_ss(_vm), _lex._svalue);
+		    class_name = SQString::Create(_ss(_vm), _lex.data->svalue);
 		    CheckGlobalName(class_name, true);
             CheckTypeName(class_name, true); //to allow C/C++ style instance declarations
 		}
@@ -2084,14 +2087,14 @@ if(color == "yellow"){
 		switch(_token) {
 			case TK_INTEGER:
 				val._type = OT_INTEGER;
-				val._unVal.nInteger = _lex._nvalue;
+				val._unVal.nInteger = _lex.data->nvalue;
 				break;
 			case TK_FLOAT:
 				val._type = OT_FLOAT;
-				val._unVal.fFloat = _lex._fvalue;
+				val._unVal.fFloat = _lex.data->fvalue;
 				break;
 			case TK_STRING_LITERAL:
-				val = _fs->CreateString(_lex._svalue,_lex._longstr.size()-1);
+				val = _fs->CreateString(_lex.data->svalue,_lex.data->longstr.size()-1);
 				break;
 			case TK_TRUE:
 			case TK_FALSE:
@@ -2104,11 +2107,11 @@ if(color == "yellow"){
 				{
 				case TK_INTEGER:
 					val._type = OT_INTEGER;
-					val._unVal.nInteger = -_lex._nvalue;
+					val._unVal.nInteger = -_lex.data->nvalue;
 				break;
 				case TK_FLOAT:
 					val._type = OT_FLOAT;
-					val._unVal.fFloat = -_lex._fvalue;
+					val._unVal.fFloat = -_lex.data->fvalue;
 				break;
 				default:
 					Error(_SC("scalar expected : integer, float"));
@@ -2125,16 +2128,16 @@ if(color == "yellow"){
 	    SQInteger tk_type = _token;
 		switch(_token) {
 			case TK_INTEGER:
-                EmitLoadConstInt(_lex._nvalue,-1);
+                EmitLoadConstInt(_lex.data->nvalue,-1);
 				break;
 			case TK_FLOAT:
-                EmitLoadConstFloat(_lex._fvalue,-1);
+                EmitLoadConstFloat(_lex.data->fvalue,-1);
 				break;
 			case TK_STRING_LITERAL:
-                _fs->AddInstruction(_OP_LOAD, _fs->PushTarget(), _fs->GetConstant(_fs->CreateString(_lex._svalue,_lex._longstr.size()-1)));
+                _fs->AddInstruction(_OP_LOAD, _fs->PushTarget(), _fs->GetConstant(_fs->CreateString(_lex.data->svalue,_lex.data->longstr.size()-1)));
 				break;
             case TK_IDENTIFIER: {
-                    SQObject id = _fs->CreateString(_lex._svalue);
+                    SQObject id = _fs->CreateString(_lex.data->svalue);
                     Lex();
                     ExpressionConstant(id);
                     return tk_type;
@@ -2146,10 +2149,10 @@ if(color == "yellow"){
 				switch(_token)
 				{
 				case TK_INTEGER:
-                    EmitLoadConstInt(-_lex._nvalue,-1);
+                    EmitLoadConstInt(-_lex.data->nvalue,-1);
 				break;
 				case TK_FLOAT:
-                    EmitLoadConstFloat(-_lex._fvalue,-1);
+                    EmitLoadConstFloat(-_lex.data->fvalue,-1);
 				break;
 				default:
 					Error(_SC("scalar expected : integer, float"));
@@ -2415,8 +2418,8 @@ error:
             case TK_IDENTIFIER:
                 if(ftype == eFunctionType_member)
                 {
-                    if(  (scstrcmp(_lex._svalue, _SC("final")) == 0) ||
-                         (scstrcmp(_lex._svalue, _SC("override")) == 0))
+                    if(  (scstrcmp(_lex.data->svalue, _SC("final")) == 0) ||
+                         (scstrcmp(_lex.data->svalue, _SC("override")) == 0))
                           {
                               Lex(); //accept but ignore then
                           }
@@ -2444,7 +2447,7 @@ error:
 		else {
 			Statement(false);
 		}
-		funcstate->AddLineInfos(_lex._prevtoken == _SC('\n')?_lex._lasttokenline:_lex._currentline, _lineinfo, true);
+		funcstate->AddLineInfos(_lex.data->prevtoken == _SC('\n')?_lex.data->lasttokenline:_lex.data->currentline, _lineinfo, true);
         funcstate->AddInstruction(_OP_RETURN, -1);
 		funcstate->SetStackSize(0);
 

+ 491 - 471
SquiLu/squirrel/sqlexer.cpp

@@ -1,56 +1,56 @@
-/*
-	see copyright notice in squirrel.h
-*/
-#include "sqpcheader.h"
-#include <ctype.h>
-#include <stdlib.h>
-#include <limits.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() {SQInteger rc = Next(); if(rc < 0) return rc; _currentcolumn++;}
-#define NEXT() {if(Next()) return -1;}
-#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) tbl->NewSlot( SQString::Create(_sharedstate, _SC(#key)) ,SQInteger(id))
-
-SQLexer::SQLexer(){_keywords=0;}
-SQLexer::~SQLexer()
-{
-	_keywords->Release();
-}
-
+/*
+	see copyright notice in squirrel.h
+*/
+#include "sqpcheader.h"
+#include <ctype.h>
+#include <stdlib.h>
+#include <limits.h>
+#include "sqtable.h"
+#include "sqstring.h"
+#include "sqcompiler.h"
+#include "sqlexer.h"
+
+#define CUR_CHAR (data->currdata)
+#define RETURN_TOKEN(t) { data->prevtoken = data->curtoken; data->curtoken = t; return t;}
+#define IS_EOB() (CUR_CHAR <= SQUIRREL_EOB)
+//#define NEXT() {SQInteger rc = Next(); if(rc < 0) return rc; data->currentcolumn++;}
+#define NEXT() {if(Next()) return -1;}
+#define INIT_TEMP_STRING() { data->longstr.resize(0);}
+#define APPEND_CHAR(c) { data->longstr.push_back(c);}
+#define TERMINATE_BUFFER() {data->longstr.push_back(_SC('\0'));}
+#define ADD_KEYWORD(key,id) tbl->NewSlot( SQString::Create(_sharedstate, _SC(#key)) ,SQInteger(id))
+
+SQLexer::SQLexer(){_keywords=0;}
+SQLexer::~SQLexer()
+{
+	_keywords->Release();
+}
+
 SQInteger SQLexer::Init(SQSharedState *ss, SQLEXREADFUNC rg,
-                        SQUserPointer up,CompilerErrorFunc efunc,void *ed, SQBool want_comments)
+                        SQUserPointer up,CompilerErrorFunc efunc,void *ed, SQBool want_comments)
 {
     _want_comments = want_comments;
-    _lasterror[0] = '\0';
-    _svalue = NULL;
-	_errfunc = efunc;
-	_errtarget = ed;
+    data = &_data;
+    _data_lookahead.currentline = -1;
+	_errfunc = efunc;
+	_errtarget = ed;
 	_sharedstate = ss;
-	if(_keywords) _keywords->Release();
-    _keywords = GetKeywords();
-	return ResetReader(rg, up, 1);
-}
+	if(_keywords) _keywords->Release();
+    _keywords = GetKeywords();
+	return ResetReader(rg, up, 1);
+}
 
-SQInteger SQLexer::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();
-}
+SQInteger SQLexer::ResetReader(SQLEXREADFUNC rg, SQUserPointer up, SQInteger line)
+{
+	_readf = rg;
+	_up = up;
+	data->lasttokenline = data->currentline = line;
+	data->lasttokencolumn = 0;
+	data->currentcolumn = 0;
+	data->prevtoken = -1;
+	data->reached_eof = SQFalse;
+	return Next();
+}
 
 SQTable * SQLexer::GetKeywords()
 {
@@ -143,41 +143,41 @@ SQTable * SQLexer::GetKeywords()
 
 	return tbl;
 }
-
-SQInteger SQLexer::Error(const SQChar *fmt, ...)
-{
-    va_list vl;
-    va_start(vl, fmt);
-    scvsprintf(_lasterror, sizeof(_lasterror), fmt, vl);
-    va_end(vl);
-	if(_errfunc) _errfunc(_errtarget,_lasterror);
-	return -1;
-}
-
-SQInteger SQLexer::Next()
-{
-	SQInteger t = _readf(_up);
-	if(t > MAX_CHAR) return Error(_SC("Invalid character"));
-	if(t != 0) {
-		_currdata = (LexChar)t;
-		++_currentcolumn;
-		return 0;
-	}
-	_currdata = SQUIRREL_EOB;
-	_reached_eof = SQTrue;
-	return 0;
-}
-
-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;
+
+SQInteger SQLexer::Error(const SQChar *fmt, ...)
+{
+    va_list vl;
+    va_start(vl, fmt);
+    scvsprintf(data->lasterror, sizeof(data->lasterror), fmt, vl);
+    va_end(vl);
+	if(_errfunc) _errfunc(_errtarget,data->lasterror);
+	return -1;
+}
+
+SQInteger SQLexer::Next()
+{
+	SQInteger t = _readf(_up);
+	if(t > MAX_CHAR) return Error(_SC("Invalid character"));
+	if(t != 0) {
+		data->currdata = (LexChar)t;
+		++data->currentcolumn;
+		return 0;
+	}
+	data->currdata = SQUIRREL_EOB;
+	data->reached_eof = SQTrue;
+	return 0;
+}
+
+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;
 }
 
 const SQChar *SQLexer::GetTokenName(int tk_code) {
@@ -192,72 +192,92 @@ const SQChar *SQLexer::GetTokenName(int tk_code) {
     }
     return str_tk;
 }
-
-
-SQInteger SQLexer::LexBlockComment()
+
+SQInteger SQLexer::LexBlockComment()
 {
 /*
     if(CUR_CHAR == _SC('*'))
     {
         NEXT();
         if(CUR_CHAR != _SC('*')){ //document comment
-            printf("Doument comment found at line %d\n", _currentline);
+            printf("Doument comment found at line %d\n", data->currentline);
         }
     }
-*/
+*/
 	bool done = false;
 	if(_want_comments) INIT_TEMP_STRING();
-	NEXT(); //remove the comment token '*'
-	while(!done) {
-		switch(CUR_CHAR) {
+	NEXT(); //remove the comment token '*'
+	while(!done) {
+		switch(CUR_CHAR) {
 			case _SC('*'): {
 			    NEXT();
 			    if(CUR_CHAR == _SC('/')) { done = true; NEXT(); continue;}
 			    if(_want_comments) APPEND_CHAR(CUR_CHAR);
 			    continue;
 			    };
-			break;
-			case _SC('\n'): _currentline++; break;
-			case SQUIRREL_EOB: return Error(_SC("missing \"*/\" in comment"));
+			break;
+			case _SC('\n'): data->currentline++; break;
+			case SQUIRREL_EOB: return Error(_SC("missing \"*/\" in comment"));
 		}
 		if(_want_comments) APPEND_CHAR(CUR_CHAR);
-		NEXT();
+		NEXT();
 	}
     if(_want_comments)
     {
         TERMINATE_BUFFER();
-        if(_longstr.size() > 0) _longstr.pop_back(); //remove the last '*'
-        _svalue = &_longstr[0];
+        if(data->longstr.size() > 0) data->longstr.pop_back(); //remove the last '*'
+        data->svalue = &data->longstr[0];
     }
-	return 0;
-}
-SQInteger SQLexer::LexLineComment()
+	return 0;
+}
+
+SQInteger SQLexer::LexLineComment()
 {
     if(_want_comments) INIT_TEMP_STRING();
-    NEXT(); //remove the comment token
+    NEXT(); //remove the comment token
 	while (CUR_CHAR != _SC('\n') && (!IS_EOB())) {if(_want_comments) APPEND_CHAR(CUR_CHAR); NEXT();}
     if(_want_comments)
     {
         TERMINATE_BUFFER();
-        _svalue = &_longstr[0];
+        data->svalue = &data->longstr[0];
+    }
+	return 0;
+}
+
+SQInteger SQLexer::LookaheadLex()
+{
+    if(_data_lookahead.currentline >= 0)
+    {
+        return Error(_SC("lex lookahead already done"));
     }
-	return 0;
-}
-
-SQInteger SQLexer::Lex()
-{
-	_lasttokenline = _currentline;
-	_lasttokencolumn = _currentcolumn;
-	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;
+    _data_lookahead.copy(&_data);
+    data = &_data_lookahead;
+    Lex();
+    data = &_data;
+    return _data_lookahead.curtoken;
+}
+
+SQInteger SQLexer::Lex()
+{
+    if(_data_lookahead.currentline >= 0 && data != &_data_lookahead)
+    {
+        //we did a lookahead before, reuse it now
+        _data.copy(&_data_lookahead);
+        _data_lookahead.currentline = -1;
+        return _data.curtoken;
+    }
+	data->lasttokenline = data->currentline;
+	data->lasttokencolumn = data->currentcolumn;
+	while(CUR_CHAR != SQUIRREL_EOB) {
+		switch(CUR_CHAR){
+		case _SC('\t'): case _SC('\r'): case _SC(' '): NEXT(); continue;
+		case _SC('\n'):
+			data->currentline++;
+			data->prevtoken=data->curtoken;
+			data->curtoken=_SC('\n');
+			NEXT();
+			data->currentcolumn=1;
+			continue;
 		case _SC('#'):
 		    NEXT();
 		    if(CUR_CHAR == '!') //shell shebang
@@ -268,184 +288,184 @@ SQInteger SQLexer::Lex()
             }
             RETURN_TOKEN(TK_PRAGMA);
             continue;
-		case _SC('/'):
-			NEXT();
-			switch(CUR_CHAR){
-			case _SC('*'):
-				if(LexBlockComment()) return -1;
+		case _SC('/'):
+			NEXT();
+			switch(CUR_CHAR){
+			case _SC('*'):
+				if(LexBlockComment()) return -1;
                 if(_want_comments) RETURN_TOKEN(TK_COMMENT_BLOCK)
-				continue;
-			case _SC('/'):
-				if(LexLineComment()) return -1;
+				continue;
+			case _SC('/'):
+				if(LexLineComment()) return -1;
                 if(_want_comments) RETURN_TOKEN(TK_COMMENT_LINE)
-				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('=') }
+				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();
                 if (CUR_CHAR == _SC('=')){ NEXT(); RETURN_TOKEN(TK_EQ_IDENTITY) }
                 else { RETURN_TOKEN(TK_EQ); }
-            }
-		case _SC('<'):
-			NEXT();
-			switch(CUR_CHAR) {
-			case _SC('='):
-				NEXT();
-				if(CUR_CHAR == _SC('>')) {
-					NEXT();
-					RETURN_TOKEN(TK_3WAYSCMP);
-				}
-				RETURN_TOKEN(TK_LE)
-				break;
-			case _SC('-'): NEXT(); RETURN_TOKEN(TK_NEWSLOT); break;
-			case _SC('<'): NEXT(); RETURN_TOKEN(TK_SHIFTL); break;
-			case _SC('/'): NEXT(); RETURN_TOKEN(TK_ATTR_OPEN); break;
-			}
-			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('!')}
+            }
+		case _SC('<'):
+			NEXT();
+			switch(CUR_CHAR) {
+			case _SC('='):
+				NEXT();
+				if(CUR_CHAR == _SC('>')) {
+					NEXT();
+					RETURN_TOKEN(TK_3WAYSCMP);
+				}
+				RETURN_TOKEN(TK_LE)
+				break;
+			case _SC('-'): NEXT(); RETURN_TOKEN(TK_NEWSLOT); break;
+			case _SC('<'): NEXT(); RETURN_TOKEN(TK_SHIFTL); break;
+			case _SC('/'): NEXT(); RETURN_TOKEN(TK_ATTR_OPEN); break;
+			}
+			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();
                 if (CUR_CHAR == _SC('=')){ NEXT(); RETURN_TOKEN(TK_NE_IDENTITY)}
                 else { RETURN_TOKEN(TK_NE); }
-            }
-		case _SC('@'): {
-			SQInteger stype;
-			NEXT();
-			if(CUR_CHAR != _SC('"')) {
-				RETURN_TOKEN('@');
-			}
-			if((stype=ReadString('"',true))!=-1) {
-				RETURN_TOKEN(stype);
-			}
-			return Error(_SC("error parsing the string"));
-					   }
-		case _SC('"'):
-		case _SC('\''): {
-			SQInteger stype;
-			if((stype=ReadString(CUR_CHAR,false))!=-1){
-				RETURN_TOKEN(stype);
-			}
-			return 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 stype;
+			NEXT();
+			if(CUR_CHAR != _SC('"')) {
+				RETURN_TOKEN('@');
+			}
+			if((stype=ReadString('"',true))!=-1) {
+				RETURN_TOKEN(stype);
+			}
+			return Error(_SC("error parsing the string"));
+					   }
+		case _SC('"'):
+		case _SC('\''): {
+			SQInteger stype;
+			if((stype=ReadString(CUR_CHAR,false))!=-1){
+				RETURN_TOKEN(stype);
+			}
+			return 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('~'):
 			{
-			    SQInteger ret = CUR_CHAR;
+			    SQInteger ret = CUR_CHAR;
                 NEXT();
                 if((ret == _SC('[') || ret == _SC('{') || ret == _SC('(')) && CUR_CHAR == _SC('=')){
                     //lets try lua literal delimiters
-                    SQInteger stype;
-                    if((stype=ReadString(ret,true))!=-1){
-                        RETURN_TOKEN(stype);
-                    }
-                    return Error(_SC("error parsing the string"));
+                    SQInteger stype;
+                    if((stype=ReadString(ret,true))!=-1){
+                        RETURN_TOKEN(stype);
+                    }
+                    return Error(_SC("error parsing the string"));
                 }
                 else RETURN_TOKEN(ret);
-            }
-		case _SC('.'):
-			NEXT();
-			if (CUR_CHAR != _SC('.')){ RETURN_TOKEN('.') }
-			NEXT();
-			if (CUR_CHAR != _SC('.')){ return Error(_SC("invalid token '..'")); }
-			NEXT();
-			RETURN_TOKEN(TK_VARPARAMS);
-		case _SC('^'):
-			NEXT();
-			//if (CUR_CHAR == _SC('=')){ NEXT(); RETURN_TOKEN(TK_BIT_XOR_EQ);}
-			RETURN_TOKEN('^');
-		case _SC('&'):
-			NEXT();
-			//if (CUR_CHAR == _SC('=')){ NEXT(); RETURN_TOKEN(TK_BIT_AND_EQ);}
-			if (CUR_CHAR != _SC('&')){ RETURN_TOKEN('&') }
-			else { NEXT(); RETURN_TOKEN(TK_AND); }
-		case _SC('|'):
+            }
+		case _SC('.'):
+			NEXT();
+			if (CUR_CHAR != _SC('.')){ RETURN_TOKEN('.') }
+			NEXT();
+			if (CUR_CHAR != _SC('.')){ return Error(_SC("invalid token '..'")); }
+			NEXT();
+			RETURN_TOKEN(TK_VARPARAMS);
+		case _SC('^'):
+			NEXT();
+			//if (CUR_CHAR == _SC('=')){ NEXT(); RETURN_TOKEN(TK_BIT_XOR_EQ);}
+			RETURN_TOKEN('^');
+		case _SC('&'):
+			NEXT();
+			//if (CUR_CHAR == _SC('=')){ NEXT(); RETURN_TOKEN(TK_BIT_AND_EQ);}
+			if (CUR_CHAR != _SC('&')){ RETURN_TOKEN('&') }
+			else { NEXT(); RETURN_TOKEN(TK_AND); }
+		case _SC('|'):
+			NEXT();
+			//if (CUR_CHAR == _SC('=')){ NEXT(); RETURN_TOKEN(TK_BIT_OR_EQ);}
+			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_BIT_OR_EQ);}
-			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 if  (CUR_CHAR == _SC('>')){ NEXT(); RETURN_TOKEN('.');} //accept C/C++ like pointers
-			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)) {
+			if (CUR_CHAR == _SC('=')){ NEXT(); RETURN_TOKEN(TK_MINUSEQ);}
+			else if  (CUR_CHAR == _SC('-')){ NEXT(); RETURN_TOKEN(TK_MINUSMINUS);}
+			else if  (CUR_CHAR == _SC('>')){ NEXT(); RETURN_TOKEN('.');} //accept C/C++ like pointers
+			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();
-					if(ret < 0) return -1;
-					RETURN_TOKEN(ret);
-				}
-				else if (scisalpha(CUR_CHAR) || CUR_CHAR == _SC('_')) {
+					if(ret < 0) return -1;
+					RETURN_TOKEN(ret);
+				}
+				else if (scisalpha(CUR_CHAR) || CUR_CHAR == _SC('_')) {
 					SQInteger t = ReadID();
-					if(t < 0) return -1;
-					RETURN_TOKEN(t);
-				}
-				else {
-					SQInteger c = CUR_CHAR;
-					if (sciscntrl((int)c)) return Error(_SC("unexpected character(control)"));
-					NEXT();
-					RETURN_TOKEN(c);
-				}
-				RETURN_TOKEN(0);
-			}
-		}
-	}
-	return 0;
-}
-
+					if(t < 0) return -1;
+					RETURN_TOKEN(t);
+				}
+				else {
+					SQInteger c = CUR_CHAR;
+					if (sciscntrl((int)c)) return Error(_SC("unexpected character(control)"));
+					NEXT();
+					RETURN_TOKEN(c);
+				}
+				RETURN_TOKEN(0);
+			}
+		}
+	}
+	return 0;
+}
+
 SQInteger SQLexer::GetIDType(const SQChar *s,SQInteger len)
 {
 	SQObjectPtr t;
 	if(_keywords->GetStr(s,len, t)) {
-		return SQInteger(_integer(t));
-	}
-	return TK_IDENTIFIER;
-}
+		return SQInteger(_integer(t));
+	}
+	return TK_IDENTIFIER;
+}
 
 #ifdef SQUNICODE
 #if WCHAR_SIZE == 2
@@ -506,10 +526,10 @@ SQInteger SQLexer::ProcessStringHexEscape(SQChar *dest, SQInteger maxdigits)
     dest[n] = 0;
     return n;
 }
-
-SQInteger SQLexer::ReadString(SQInteger ndelim,bool verbatim)
-{
-	INIT_TEMP_STRING();
+
+SQInteger SQLexer::ReadString(SQInteger ndelim,bool verbatim)
+{
+	INIT_TEMP_STRING();
 	SQInteger start_equals = 0;
 	SQChar cdelim1, cdelim2;
 	if(ndelim == _SC('{')){
@@ -535,40 +555,40 @@ SQInteger SQLexer::ReadString(SQInteger ndelim,bool verbatim)
 	        return Error(_SC("expect '%c' on literal delimiter"), cdelim1);
 	    }
 	    ndelim = cdelim2;
-	}
-	NEXT();
-	if(IS_EOB()) return -1;
+	}
+	NEXT();
+	if(IS_EOB()) return -1;
 	if(start_equals) {
 	    int cr_nl = CUR_CHAR == _SC('\r');
         if(cr_nl) NEXT();
         cr_nl = CUR_CHAR == _SC('\n');
         if(cr_nl) NEXT();
         if(cr_nl) {//if a new line follows the start of delimiter drop it
-            ++_currentline;
+            ++data->currentline;
             if(IS_EOB())
             {
                 return Error(_SC("unfinished string"));
             }
-        }
+        }
 	}
-	for(;;) {
+	for(;;) {
 		while(CUR_CHAR != ndelim) {
-            SQInteger x = CUR_CHAR;
-			switch(x) {
-			case SQUIRREL_EOB:
-				return Error(_SC("unfinished string"));
-			case _SC('\n'):
-				if(!verbatim) return 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) {
+            SQInteger x = CUR_CHAR;
+			switch(x) {
+			case SQUIRREL_EOB:
+				return Error(_SC("unfinished string"));
+			case _SC('\n'):
+				if(!verbatim) return Error(_SC("newline in a constant"));
+				APPEND_CHAR(CUR_CHAR); NEXT();
+				data->currentline++;
+				break;
+			case _SC('\\'):
+				if(verbatim) {
+					APPEND_CHAR('\\'); NEXT();
+				}
+				else {
+					NEXT();
+					switch(CUR_CHAR) {
                     case _SC('x'):  {
                         const SQInteger maxdigits = sizeof(SQChar) * 2;
                         SQChar temp[maxdigits + 1];
@@ -592,31 +612,31 @@ SQInteger SQLexer::ReadString(SQInteger ndelim,bool verbatim)
 #else
                         AddUTF8(scstrtoul(temp, &stemp, 16));
 #endif
-					}
-				    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:
-						return Error(_SC("unrecognised escaper char"));
-					break;
-					}
-				}
-				break;
-			default:
-				APPEND_CHAR(CUR_CHAR);
-				NEXT();
-			}
-		}
-		NEXT();
+					}
+				    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:
+						return Error(_SC("unrecognised escaper char"));
+					break;
+					}
+				}
+				break;
+			default:
+				APPEND_CHAR(CUR_CHAR);
+				NEXT();
+			}
+		}
+		NEXT();
 		if(start_equals){
 		    bool lastBraceAdded = false;
 		    if(CUR_CHAR == _SC('=')){
@@ -640,154 +660,154 @@ SQInteger SQLexer::ReadString(SQInteger ndelim,bool verbatim)
 		    if(!lastBraceAdded) APPEND_CHAR(cdelim2); //the first NEXT() after break the while loop
 		    APPEND_CHAR(CUR_CHAR);
 		    NEXT();
-		}
-		else 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) return Error(_SC("empty constant"));
-		if(len > 1) return 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');
+		}
+		else if(verbatim && CUR_CHAR == '"') { //double quotation
+			APPEND_CHAR(CUR_CHAR);
+			NEXT();
+		}
+		else {
+			break;
+		}
+	}
+	TERMINATE_BUFFER();
+	SQInteger len = data->longstr.size()-1;
+	if(ndelim == _SC('\'')) {
+		if(len == 0) return Error(_SC("empty constant"));
+		if(len > 1) return Error(_SC("constant too long"));
+		data->nvalue = data->longstr[0];
+		return TK_INTEGER;
+	}
+	data->svalue = &data->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 scisodigit(SQInteger c) { return c >= _SC('0') && c <= _SC('7'); }
+
+void LexOctal(const SQChar *s,SQUnsignedInteger *res)
+{
+	*res = 0;
+	while(*s != 0)
+	{
+		if(scisodigit(*s)) *res = (*res)*8+((*s++)-'0');
+		else { assert(0); }
 	}
-}
-
-SQInteger scisodigit(SQInteger c) { return c >= _SC('0') && c <= _SC('7'); }
-
-void LexOctal(const SQChar *s,SQUnsignedInteger *res)
-{
-	*res = 0;
-	while(*s != 0)
-	{
-		if(scisodigit(*s)) *res = (*res)*8+((*s++)-'0');
-		else { assert(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
-#define TOCTAL 5
+}
+
+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
+#define TOCTAL 5
 	SQInteger type = TINT, firstchar = CUR_CHAR;
-	SQUnsignedInteger itmp=0;
-	SQChar *sTemp;
-	INIT_TEMP_STRING();
-	NEXT();
-	if(firstchar == _SC('0') && (toupper(CUR_CHAR) == _SC('X') || scisodigit(CUR_CHAR)) ) {
-		if(scisodigit(CUR_CHAR)) {
-			type = TOCTAL;
-			while(scisodigit(CUR_CHAR)) {
-				APPEND_CHAR(CUR_CHAR);
-				NEXT();
-			}
-			if(scisdigit(CUR_CHAR)) return Error(_SC("invalid octal number"));
-		}
-		else {
-			NEXT();
-			type = THEX;
-			while(isxdigit(CUR_CHAR)) {
-				APPEND_CHAR(CUR_CHAR);
-				NEXT();
-			}
-			if(_longstr.size() > MAX_HEX_DIGITS) return 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('.') || isexponent(CUR_CHAR)) type = TFLOAT;
-			if(isexponent(CUR_CHAR)) {
-				if(type != TFLOAT) return 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)) return 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],&itmp);
-		break;
-	case THEX:
-		LexHexadecimal(&_longstr[0],&itmp);
-		break;
-	case TOCTAL:
-		LexOctal(&_longstr[0],&itmp);
-		break;
-	}
-	switch(type) {
-	case TINT:
-	case THEX:
+	SQUnsignedInteger itmp=0;
+	SQChar *sTemp;
+	INIT_TEMP_STRING();
+	NEXT();
+	if(firstchar == _SC('0') && (toupper(CUR_CHAR) == _SC('X') || scisodigit(CUR_CHAR)) ) {
+		if(scisodigit(CUR_CHAR)) {
+			type = TOCTAL;
+			while(scisodigit(CUR_CHAR)) {
+				APPEND_CHAR(CUR_CHAR);
+				NEXT();
+			}
+			if(scisdigit(CUR_CHAR)) return Error(_SC("invalid octal number"));
+		}
+		else {
+			NEXT();
+			type = THEX;
+			while(isxdigit(CUR_CHAR)) {
+				APPEND_CHAR(CUR_CHAR);
+				NEXT();
+			}
+			if(data->longstr.size() > MAX_HEX_DIGITS) return 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('.') || isexponent(CUR_CHAR)) type = TFLOAT;
+			if(isexponent(CUR_CHAR)) {
+				if(type != TFLOAT) return 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)) return Error(_SC("exponent expected"));
+			}
+
+			APPEND_CHAR(CUR_CHAR);
+			NEXT();
+		}
+	}
+	TERMINATE_BUFFER();
+	switch(type) {
+	case TSCIENTIFIC:
+	case TFLOAT:
+		data->fvalue = (SQFloat)scstrtod(&data->longstr[0],&sTemp);
+		return TK_FLOAT;
+	case TINT:
+		LexInteger(&data->longstr[0],&itmp);
+		break;
+	case THEX:
+		LexHexadecimal(&data->longstr[0],&itmp);
+		break;
+	case TOCTAL:
+		LexOctal(&data->longstr[0],&itmp);
+		break;
+	}
+	switch(type) {
+	case TINT:
+	case THEX:
 	case TOCTAL:
 	    //to allow 64 bits integers comment bellow
         //if(itmp > INT_MAX) return Error(_SC("integer overflow %ulld %d"));
-        _nvalue = (SQInteger) itmp;
-		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],_longstr.size() - 1);
-	if(res == TK_IDENTIFIER || res == TK_CONSTRUCTOR || res == TK_DESTRUCTOR) {
-		_svalue = &_longstr[0];
-	}
-	return res;
-}
+        data->nvalue = (SQInteger) itmp;
+		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(&data->longstr[0],data->longstr.size() - 1);
+	if(res == TK_IDENTIFIER || res == TK_CONSTRUCTOR || res == TK_DESTRUCTOR) {
+		data->svalue = &data->longstr[0];
+	}
+	return res;
+}

+ 96 - 48
SquiLu/squirrel/sqlexer.h

@@ -1,32 +1,91 @@
-/*	see copyright notice in squirrel.h */
-#ifndef _SQLEXER_H_
-#define _SQLEXER_H_
-
-#ifdef SQUNICODE
-typedef SQChar LexChar;
-#else
-typedef	unsigned char LexChar;
-#endif
-
-struct SQLexer
-{
-	SQLexer();
-	virtual ~SQLexer();
+/*	see copyright notice in squirrel.h */
+#ifndef _SQLEXER_H_
+#define _SQLEXER_H_
+
+#ifdef SQUNICODE
+typedef SQChar LexChar;
+#else
+typedef	unsigned char LexChar;
+#endif
+
+struct SQLexerData
+{
+    SQInteger curtoken;
+    SQBool reached_eof;
+    SQInteger prevtoken;
+    SQInteger currentline;
+    SQInteger currentcolumn;
+    SQInteger lasttokenline;
+    SQInteger lasttokencolumn;
+    const SQChar *svalue;
+    sqvector<SQChar> longstr;
+    SQInteger nvalue;
+    SQFloat fvalue;
+    LexChar currdata;
+    SQChar lasterror[256];
+    SQLexerData()
+    {
+        clear();
+    }
+    SQLexerData(SQLexerData *src)
+    {
+        copy(src);
+    }
+    void copy(SQLexerData *src)
+    {
+        curtoken = src->curtoken;
+        reached_eof = src->reached_eof;
+        prevtoken = src->prevtoken;
+        currentline = src->currentline;
+        currentcolumn = src->currentcolumn;
+        lasttokenline = src->lasttokenline;
+        lasttokencolumn = src->lasttokencolumn;
+        longstr.resize(src->longstr.size());
+        memcpy(longstr._vals, src->longstr._vals, src->longstr.size());
+        svalue = &longstr[0];
+        nvalue = src->nvalue;
+        fvalue = src->fvalue;
+        currdata = src->currdata;
+        scstrcpy(lasterror, src->lasterror);
+    }
+    void clear()
+    {
+        curtoken = 0;
+        reached_eof = SQFalse;
+        prevtoken = -1;
+        currentline = 0;
+        currentcolumn = 0;
+        lasttokenline = 0;
+        lasttokencolumn = 0;
+        longstr.resize(0);
+        svalue = NULL;
+        nvalue = 0;
+        fvalue = 0.0;
+        currdata = 0;
+        lasterror[0] = '\0';
+    }
+};
+
+struct SQLexer
+{
+	SQLexer();
+	virtual ~SQLexer();
 	SQInteger Init(SQSharedState *ss,SQLEXREADFUNC rg,SQUserPointer up,
                 CompilerErrorFunc efunc,void *ed, SQBool want_comments=SQFalse);
 	SQInteger ResetReader(SQLEXREADFUNC rg, SQUserPointer up, SQInteger line);
-	SQTable * GetKeywords();
-	SQInteger Error(const SQChar *err, ...);
-	SQInteger Lex();
+	SQTable * GetKeywords();
+	SQInteger Error(const SQChar *err, ...);
+	SQInteger Lex();
+	SQInteger LookaheadLex();
 	const SQChar *Tok2Str(SQInteger tok);
-	const SQChar *GetTokenName(int tk_code);
-private:
+	const SQChar *GetTokenName(int tk_code);
+private:
 	SQInteger GetIDType(const SQChar *s,SQInteger len);
-	SQInteger ReadString(SQInteger ndelim,bool verbatim);
-	SQInteger ReadNumber();
-	SQInteger LexBlockComment();
-	SQInteger LexLineComment();
-	SQInteger ReadID();
+	SQInteger ReadString(SQInteger ndelim,bool verbatim);
+	SQInteger ReadNumber();
+	SQInteger LexBlockComment();
+	SQInteger LexLineComment();
+	SQInteger ReadID();
 	SQInteger Next();
 #ifdef SQUNICODE
 #if WCHAR_SIZE == 2
@@ -35,28 +94,17 @@ private:
 #else
     SQInteger AddUTF8(SQUnsignedInteger ch);
 #endif
-    SQInteger ProcessStringHexEscape(SQChar *dest, SQInteger maxdigits);
-	SQInteger _curtoken;
-	SQTable *_keywords;
-	SQBool _reached_eof;
-public:
-	SQInteger _prevtoken;
-	SQInteger _currentline;
-	SQInteger _lasttokenline;
-	SQInteger _lasttokencolumn;
-	SQInteger _currentcolumn;
-	const SQChar *_svalue;
-	SQInteger _nvalue;
-	SQFloat _fvalue;
-	SQLEXREADFUNC _readf;
-	SQUserPointer _up;
-	LexChar _currdata;
-	SQSharedState *_sharedstate;
-	sqvector<SQChar> _longstr;
-	CompilerErrorFunc _errfunc;
+    SQInteger ProcessStringHexEscape(SQChar *dest, SQInteger maxdigits);
+    SQLexerData _data, _data_lookahead;
+	SQTable *_keywords;
+public:
+    SQLexerData *data;
+	SQLEXREADFUNC _readf;
+	SQUserPointer _up;
+	SQSharedState *_sharedstate;
+	CompilerErrorFunc _errfunc;
 	void *_errtarget;
-	SQChar _lasterror[256];
-	SQBool _want_comments;
-};
-
-#endif
+	SQBool _want_comments;
+};
+
+#endif