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