fix cr/lfs and remove trailing whitespaces...
[supertux.git] / src / squirrel / squirrel / sqlexer.cpp
index c9cac24..2552f7d 100644 (file)
@@ -24,8 +24,10 @@ SQLexer::~SQLexer()
        _keywords->Release();
 }
 
-void SQLexer::Init(SQSharedState *ss, SQLEXREADFUNC rg, SQUserPointer up)
+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);
@@ -63,6 +65,7 @@ void SQLexer::Init(SQSharedState *ss, SQLEXREADFUNC rg, SQUserPointer up)
        ADD_KEYWORD(vargv,TK_VARGV);
        ADD_KEYWORD(true,TK_TRUE);
        ADD_KEYWORD(false,TK_FALSE);
+       ADD_KEYWORD(static,TK_STATIC);
 
        _readf = rg;
        _up = up;
@@ -72,27 +75,32 @@ void SQLexer::Init(SQSharedState *ss, SQLEXREADFUNC rg, SQUserPointer up)
        Next();
 }
 
+void SQLexer::Error(const SQChar *err)
+{
+       _errfunc(_errtarget,err);
+}
+
 void SQLexer::Next()
 {
        SQInteger t = _readf(_up);
-       if(t > MAX_CHAR) throw ParserException(_SC("Invalid character"));
+       if(t > MAX_CHAR) Error(_SC("Invalid character"));
        if(t != 0) {
-               _currdata = t;
+               _currdata = (LexChar)t;
                return;
        }
        _currdata = SQUIRREL_EOB;
 }
 
-SQObjectPtr SQLexer::Tok2Str(int tok)
+const SQChar *SQLexer::Tok2Str(SQInteger tok)
 {
        SQObjectPtr itr, key, val;
-       int nitr;
-       while((nitr = _keywords->Next(itr, key, val)) != -1) {
+       SQInteger nitr;
+       while((nitr = _keywords->Next(false,itr, key, val)) != -1) {
                itr = (SQInteger)nitr;
-               if(((int)_integer(val)) == tok)
-                       return key;
+               if(((SQInteger)_integer(val)) == tok)
+                       return _stringval(key);
        }
-       return SQObjectPtr();
+       return NULL;
 }
 
 void SQLexer::LexBlockComment()
@@ -101,15 +109,14 @@ void SQLexer::LexBlockComment()
        while(!done) {
                switch(CUR_CHAR) {
                        case _SC('*'): { NEXT(); if(CUR_CHAR == _SC('/')) { done = true; NEXT(); }}; continue;
-                       //case _SC('/'): { NEXT(); if(CUR_CHAR == _SC('*')) { nest++; NEXT(); }}; continue;
                        case _SC('\n'): _currentline++; NEXT(); continue;
-                       case SQUIRREL_EOB: throw ParserException(_SC("missing \"*/\" in comment"));
+                       case SQUIRREL_EOB: Error(_SC("missing \"*/\" in comment"));
                        default: NEXT();
                }
        }
 }
 
-int SQLexer::Lex()
+SQInteger SQLexer::Lex()
 {
        _lasttokenline = _currentline;
        while(CUR_CHAR != SQUIRREL_EOB) {
@@ -128,7 +135,7 @@ int SQLexer::Lex()
                        case _SC('*'):
                                NEXT();
                                LexBlockComment();
-                               continue;       
+                               continue;
                        case _SC('/'):
                                do { NEXT(); } while (CUR_CHAR != _SC('\n') && (!IS_EOB()));
                                continue;
@@ -158,8 +165,8 @@ int SQLexer::Lex()
                case _SC('>'):
                        NEXT();
                        if (CUR_CHAR == _SC('=')){ NEXT(); RETURN_TOKEN(TK_GE);}
-                       else if(CUR_CHAR == _SC('>')){ 
-                               NEXT(); 
+                       else if(CUR_CHAR == _SC('>')){
+                               NEXT();
                                if(CUR_CHAR == _SC('>')){
                                        NEXT();
                                        RETURN_TOKEN(TK_USHIFTR);
@@ -172,32 +179,32 @@ int SQLexer::Lex()
                        if (CUR_CHAR != _SC('=')){ RETURN_TOKEN('!')}
                        else { NEXT(); RETURN_TOKEN(TK_NE); }
                case _SC('@'): {
-                       int stype;
-                       NEXT(); 
+                       SQInteger stype;
+                       NEXT();
                        if(CUR_CHAR != _SC('"'))
-                               throw ParserException(_SC("string expected"));
+                               Error(_SC("string expected"));
                        if((stype=ReadString('"',true))!=-1) {
                                RETURN_TOKEN(stype);
                        }
-                       throw ParserException(_SC("error parsing the string"));
+                       Error(_SC("error parsing the string"));
                                           }
                case _SC('"'):
                case _SC('\''): {
-                       int stype;
+                       SQInteger stype;
                        if((stype=ReadString(CUR_CHAR,false))!=-1){
                                RETURN_TOKEN(stype);
                        }
-                       throw ParserException(_SC("error parsing the string"));
+                       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('~'):
-                       {int ret = CUR_CHAR;
+                       {SQInteger ret = CUR_CHAR;
                        NEXT(); RETURN_TOKEN(ret); }
                case _SC('.'):
                        NEXT();
                        if (CUR_CHAR != _SC('.')){ RETURN_TOKEN('.') }
                        NEXT();
-                       if (CUR_CHAR != _SC('.')){ throw ParserException(_SC("invalid token '..'")); }
+                       if (CUR_CHAR != _SC('.')){ Error(_SC("invalid token '..'")); }
                        NEXT();
                        RETURN_TOKEN(TK_VARPARAMS);
                case _SC('&'):
@@ -234,37 +241,37 @@ int SQLexer::Lex()
                        return 0;
                default:{
                                if (scisdigit(CUR_CHAR)) {
-                                       int ret = ReadNumber();
+                                       SQInteger ret = ReadNumber();
                                        RETURN_TOKEN(ret);
                                }
                                else if (scisalpha(CUR_CHAR) || CUR_CHAR == _SC('_')) {
-                                       int t = ReadID();
+                                       SQInteger t = ReadID();
                                        RETURN_TOKEN(t);
                                }
                                else {
-                                       int c = CUR_CHAR;
-                                       if (sciscntrl(c)) throw ParserException(_SC("unexpected character(control)"));
+                                       SQInteger c = CUR_CHAR;
+                                       if (sciscntrl((int)c)) Error(_SC("unexpected character(control)"));
                                        NEXT();
-                                       RETURN_TOKEN(c);  
+                                       RETURN_TOKEN(c);
                                }
                                RETURN_TOKEN(0);
                        }
                }
        }
-       return 0;    
+       return 0;
 }
-       
-int SQLexer::GetIDType(SQChar *s)
+
+SQInteger SQLexer::GetIDType(SQChar *s)
 {
        SQObjectPtr t;
        if(_keywords->Get(SQString::Create(_sharedstate, s), t)) {
-               return int(_integer(t));
+               return SQInteger(_integer(t));
        }
        return TK_IDENTIFIER;
 }
 
 
-int SQLexer::ReadString(int ndelim,bool verbatim)
+SQInteger SQLexer::ReadString(SQInteger ndelim,bool verbatim)
 {
        INIT_TEMP_STRING();
        NEXT();
@@ -273,20 +280,35 @@ int SQLexer::ReadString(int ndelim,bool verbatim)
                while(CUR_CHAR != ndelim) {
                        switch(CUR_CHAR) {
                        case SQUIRREL_EOB:
-                               throw ParserException(_SC("unfinished string"));
+                               Error(_SC("unfinished string"));
                                return -1;
-                       case _SC('\n'): 
-                               if(!verbatim) throw ParserException(_SC("newline in a constant")); 
-                               APPEND_CHAR(CUR_CHAR); NEXT(); 
+                       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(); 
+                                       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;
@@ -299,7 +321,7 @@ int SQLexer::ReadString(int ndelim,bool verbatim)
                                        case _SC('"'): APPEND_CHAR(_SC('"')); NEXT(); break;
                                        case _SC('\''): APPEND_CHAR(_SC('\'')); NEXT(); break;
                                        default:
-                                               throw ParserException(_SC("unrecognised escaper char"));
+                                               Error(_SC("unrecognised escaper char"));
                                        break;
                                        }
                                }
@@ -319,10 +341,10 @@ int SQLexer::ReadString(int ndelim,bool verbatim)
                }
        }
        TERMINATE_BUFFER();
-       int len = _longstr.size()-1;
+       SQInteger len = _longstr.size()-1;
        if(ndelim == _SC('\'')) {
-               if(len == 0) throw ParserException(_SC("empty constant"));
-               if(len > 1) throw ParserException(_SC("constant too long"));
+               if(len == 0) Error(_SC("empty constant"));
+               if(len > 1) Error(_SC("constant too long"));
                _nvalue = _longstr[0];
                return TK_INTEGER;
        }
@@ -330,16 +352,35 @@ int SQLexer::ReadString(int ndelim,bool verbatim)
        return TK_STRING_LITERAL;
 }
 
-int isexponent(int c) { return c == 'e' || c=='E'; }
+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); }
+       }
+}
 
-int SQLexer::ReadNumber()
+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
-       int type = TINT, firstchar = CUR_CHAR;
-       //bool isfloat = false;
+       SQInteger type = TINT, firstchar = CUR_CHAR;
        SQChar *sTemp;
        INIT_TEMP_STRING();
        NEXT();
@@ -350,14 +391,14 @@ int SQLexer::ReadNumber()
                        APPEND_CHAR(CUR_CHAR);
                        NEXT();
                }
-               if(_longstr.size() > 8) throw ParserException(_SC("Hex number over 8 digits"));
+               if(_longstr.size() > MAX_HEX_DIGITS) Error(_SC("too many digits for an Hex number"));
        }
        else {
-               APPEND_CHAR(firstchar);
+               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) throw ParserException(_SC("invalid numeric format"));
+                               if(type != TFLOAT) Error(_SC("invalid numeric format"));
                                type = TSCIENTIFIC;
                                APPEND_CHAR(CUR_CHAR);
                                NEXT();
@@ -365,9 +406,9 @@ int SQLexer::ReadNumber()
                                        APPEND_CHAR(CUR_CHAR);
                                        NEXT();
                                }
-                               if(!scisdigit(CUR_CHAR)) throw ParserException(_SC("exponent expected"));
+                               if(!scisdigit(CUR_CHAR)) Error(_SC("exponent expected"));
                        }
-                       
+
                        APPEND_CHAR(CUR_CHAR);
                        NEXT();
                }
@@ -379,19 +420,18 @@ int SQLexer::ReadNumber()
                _fvalue = (SQFloat)scstrtod(&_longstr[0],&sTemp);
                return TK_FLOAT;
        case TINT:
-               _nvalue = (SQInteger)scatoi(&_longstr[0]);
+               LexInteger(&_longstr[0],(SQUnsignedInteger *)&_nvalue);
                return TK_INTEGER;
        case THEX:
-               *((unsigned long *)&_nvalue) = scstrtoul(&_longstr[0],&sTemp,16);
+               LexHexadecimal(&_longstr[0],(SQUnsignedInteger *)&_nvalue);
                return TK_INTEGER;
        }
        return 0;
 }
 
-int SQLexer::ReadID()
+SQInteger SQLexer::ReadID()
 {
-       int res;
-       // int size = 0;
+       SQInteger res;
        INIT_TEMP_STRING();
        do {
                APPEND_CHAR(CUR_CHAR);
@@ -399,7 +439,7 @@ int SQLexer::ReadID()
        } while(scisalnum(CUR_CHAR) || CUR_CHAR == _SC('_'));
        TERMINATE_BUFFER();
        res = GetIDType(&_longstr[0]);
-       if(res == TK_IDENTIFIER) {
+       if(res == TK_IDENTIFIER || res == TK_CONSTRUCTOR) {
                _svalue = &_longstr[0];
        }
        return res;