2009-02-25 02:21:50 +01:00
|
|
|
/*
|
|
|
|
see copyright notice in squirrel.h
|
|
|
|
*/
|
2014-09-06 21:54:35 +02:00
|
|
|
|
|
|
|
#include "../../../stdafx.h"
|
|
|
|
|
2009-02-25 02:21:50 +01:00
|
|
|
#include "sqpcheader.h"
|
|
|
|
#include <ctype.h>
|
|
|
|
#include "sqtable.h"
|
|
|
|
#include "sqstring.h"
|
|
|
|
#include "sqcompiler.h"
|
|
|
|
#include "sqlexer.h"
|
|
|
|
|
2014-09-06 19:22:06 +02:00
|
|
|
#include "../../../string_func.h"
|
|
|
|
|
2014-09-06 21:54:35 +02:00
|
|
|
#include "../../../safeguards.h"
|
|
|
|
|
2009-02-25 02:21:50 +01:00
|
|
|
#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++;}
|
2014-09-06 19:46:56 +02:00
|
|
|
#define ADD_KEYWORD(key,id) _keywords->NewSlot( SQString::Create(ss, #key) ,SQInteger(id))
|
2009-02-25 02:21:50 +01:00
|
|
|
|
|
|
|
SQLexer::~SQLexer()
|
|
|
|
{
|
|
|
|
_keywords->Release();
|
|
|
|
}
|
|
|
|
|
2014-09-07 08:46:03 +02:00
|
|
|
void SQLexer::APPEND_CHAR(WChar c)
|
2014-09-06 19:22:06 +02:00
|
|
|
{
|
|
|
|
char buf[4];
|
2014-09-07 08:46:03 +02:00
|
|
|
size_t chars = Utf8Encode(buf, c);
|
|
|
|
for (size_t i = 0; i < chars; i++) {
|
2014-09-06 19:22:06 +02:00
|
|
|
_longstr.push_back(buf[i]);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-09-16 22:08:44 +02:00
|
|
|
SQLexer::SQLexer(SQSharedState *ss, SQLEXREADFUNC rg, SQUserPointer up,CompilerErrorFunc efunc,void *ed)
|
2009-02-25 02:21:50 +01:00
|
|
|
{
|
|
|
|
_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);
|
|
|
|
ADD_KEYWORD(enum,TK_ENUM);
|
|
|
|
ADD_KEYWORD(const,TK_CONST);
|
|
|
|
|
|
|
|
_readf = rg;
|
|
|
|
_up = up;
|
|
|
|
_lasttokenline = _currentline = 1;
|
|
|
|
_currentcolumn = 0;
|
|
|
|
_prevtoken = -1;
|
|
|
|
Next();
|
|
|
|
}
|
|
|
|
|
2014-09-16 22:05:21 +02:00
|
|
|
NORETURN void SQLexer::Error(const SQChar *err)
|
2009-02-25 02:21:50 +01:00
|
|
|
{
|
|
|
|
_errfunc(_errtarget,err);
|
|
|
|
}
|
|
|
|
|
|
|
|
void SQLexer::Next()
|
|
|
|
{
|
2014-09-07 08:46:03 +02:00
|
|
|
WChar t = _readf(_up);
|
2014-09-06 19:46:56 +02:00
|
|
|
if(t > MAX_CHAR) Error("Invalid character");
|
2009-02-25 02:21:50 +01:00
|
|
|
if(t != 0) {
|
2014-09-07 08:46:03 +02:00
|
|
|
_currdata = t;
|
2009-02-25 02:21:50 +01:00
|
|
|
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) {
|
2014-09-06 19:46:56 +02:00
|
|
|
case '*': { NEXT(); if(CUR_CHAR == '/') { done = true; NEXT(); }}; continue;
|
|
|
|
case '\n': _currentline++; NEXT(); continue;
|
|
|
|
case SQUIRREL_EOB: Error("missing \"*/\" in comment");
|
2009-02-25 02:21:50 +01:00
|
|
|
default: NEXT();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
SQInteger SQLexer::Lex()
|
|
|
|
{
|
|
|
|
_lasttokenline = _currentline;
|
|
|
|
while(CUR_CHAR != SQUIRREL_EOB) {
|
|
|
|
switch(CUR_CHAR){
|
2014-09-06 19:46:56 +02:00
|
|
|
case '\t': case '\r': case ' ': NEXT(); continue;
|
|
|
|
case '\n':
|
2009-02-25 02:21:50 +01:00
|
|
|
_currentline++;
|
|
|
|
_prevtoken=_curtoken;
|
2014-09-06 19:46:56 +02:00
|
|
|
_curtoken='\n';
|
2009-02-25 02:21:50 +01:00
|
|
|
NEXT();
|
|
|
|
_currentcolumn=1;
|
|
|
|
continue;
|
2014-09-06 19:46:56 +02:00
|
|
|
case '/':
|
2009-02-25 02:21:50 +01:00
|
|
|
NEXT();
|
|
|
|
switch(CUR_CHAR){
|
2014-09-06 19:46:56 +02:00
|
|
|
case '*':
|
2009-02-25 02:21:50 +01:00
|
|
|
NEXT();
|
|
|
|
LexBlockComment();
|
|
|
|
continue;
|
2014-09-06 19:46:56 +02:00
|
|
|
case '/':
|
|
|
|
do { NEXT(); } while (CUR_CHAR != '\n' && (!IS_EOB()));
|
2009-02-25 02:21:50 +01:00
|
|
|
continue;
|
2014-09-06 19:46:56 +02:00
|
|
|
case '=':
|
2009-02-25 02:21:50 +01:00
|
|
|
NEXT();
|
|
|
|
RETURN_TOKEN(TK_DIVEQ);
|
2014-09-06 19:46:56 +02:00
|
|
|
case '>':
|
2009-02-25 02:21:50 +01:00
|
|
|
NEXT();
|
|
|
|
RETURN_TOKEN(TK_ATTR_CLOSE);
|
|
|
|
default:
|
|
|
|
RETURN_TOKEN('/');
|
|
|
|
}
|
2014-09-06 19:46:56 +02:00
|
|
|
case '=':
|
2009-02-25 02:21:50 +01:00
|
|
|
NEXT();
|
2014-09-06 19:46:56 +02:00
|
|
|
if (CUR_CHAR != '='){ RETURN_TOKEN('=') }
|
2009-02-25 02:21:50 +01:00
|
|
|
else { NEXT(); RETURN_TOKEN(TK_EQ); }
|
2014-09-06 19:46:56 +02:00
|
|
|
case '<':
|
2009-02-25 02:21:50 +01:00
|
|
|
NEXT();
|
2014-09-06 19:46:56 +02:00
|
|
|
if ( CUR_CHAR == '=' ) { NEXT(); RETURN_TOKEN(TK_LE) }
|
|
|
|
else if ( CUR_CHAR == '-' ) { NEXT(); RETURN_TOKEN(TK_NEWSLOT); }
|
|
|
|
else if ( CUR_CHAR == '<' ) { NEXT(); RETURN_TOKEN(TK_SHIFTL); }
|
|
|
|
else if ( CUR_CHAR == '/' ) { NEXT(); RETURN_TOKEN(TK_ATTR_OPEN); }
|
|
|
|
//else if ( CUR_CHAR == '[' ) { NEXT(); ReadMultilineString(); RETURN_TOKEN(TK_STRING_LITERAL); }
|
2009-02-25 02:21:50 +01:00
|
|
|
else { RETURN_TOKEN('<') }
|
2014-09-06 19:46:56 +02:00
|
|
|
case '>':
|
2009-02-25 02:21:50 +01:00
|
|
|
NEXT();
|
2014-09-06 19:46:56 +02:00
|
|
|
if (CUR_CHAR == '='){ NEXT(); RETURN_TOKEN(TK_GE);}
|
|
|
|
else if(CUR_CHAR == '>'){
|
2009-02-25 02:21:50 +01:00
|
|
|
NEXT();
|
2014-09-06 19:46:56 +02:00
|
|
|
if(CUR_CHAR == '>'){
|
2009-02-25 02:21:50 +01:00
|
|
|
NEXT();
|
|
|
|
RETURN_TOKEN(TK_USHIFTR);
|
|
|
|
}
|
|
|
|
RETURN_TOKEN(TK_SHIFTR);
|
|
|
|
}
|
|
|
|
else { RETURN_TOKEN('>') }
|
2014-09-06 19:46:56 +02:00
|
|
|
case '!':
|
2009-02-25 02:21:50 +01:00
|
|
|
NEXT();
|
2014-09-06 19:46:56 +02:00
|
|
|
if (CUR_CHAR != '='){ RETURN_TOKEN('!')}
|
2009-02-25 02:21:50 +01:00
|
|
|
else { NEXT(); RETURN_TOKEN(TK_NE); }
|
2014-09-06 19:46:56 +02:00
|
|
|
case '@': {
|
2009-02-25 02:21:50 +01:00
|
|
|
SQInteger stype;
|
|
|
|
NEXT();
|
2014-09-06 19:46:56 +02:00
|
|
|
if(CUR_CHAR != '"')
|
|
|
|
Error("string expected");
|
|
|
|
if((stype=ReadString('"',true))!=-1) {
|
2009-02-25 02:21:50 +01:00
|
|
|
RETURN_TOKEN(stype);
|
|
|
|
}
|
2014-09-06 19:46:56 +02:00
|
|
|
Error("error parsing the string");
|
2009-02-25 02:21:50 +01:00
|
|
|
}
|
2014-09-06 19:46:56 +02:00
|
|
|
case '"':
|
|
|
|
case '\'': {
|
2009-02-25 02:21:50 +01:00
|
|
|
SQInteger stype;
|
|
|
|
if((stype=ReadString(CUR_CHAR,false))!=-1){
|
|
|
|
RETURN_TOKEN(stype);
|
|
|
|
}
|
2014-09-06 19:46:56 +02:00
|
|
|
Error("error parsing the string");
|
2009-02-25 02:21:50 +01:00
|
|
|
}
|
2014-09-06 19:46:56 +02:00
|
|
|
case '{': case '}': case '(': case ')': case '[': case ']':
|
|
|
|
case ';': case ',': case '?': case '^': case '~':
|
2009-02-25 02:21:50 +01:00
|
|
|
{SQInteger ret = CUR_CHAR;
|
|
|
|
NEXT(); RETURN_TOKEN(ret); }
|
2014-09-06 19:46:56 +02:00
|
|
|
case '.':
|
2009-02-25 02:21:50 +01:00
|
|
|
NEXT();
|
2014-09-06 19:46:56 +02:00
|
|
|
if (CUR_CHAR != '.'){ RETURN_TOKEN('.') }
|
2009-02-25 02:21:50 +01:00
|
|
|
NEXT();
|
2014-09-06 19:46:56 +02:00
|
|
|
if (CUR_CHAR != '.'){ Error("invalid token '..'"); }
|
2009-02-25 02:21:50 +01:00
|
|
|
NEXT();
|
|
|
|
RETURN_TOKEN(TK_VARPARAMS);
|
2014-09-06 19:46:56 +02:00
|
|
|
case '&':
|
2009-02-25 02:21:50 +01:00
|
|
|
NEXT();
|
2014-09-06 19:46:56 +02:00
|
|
|
if (CUR_CHAR != '&'){ RETURN_TOKEN('&') }
|
2009-02-25 02:21:50 +01:00
|
|
|
else { NEXT(); RETURN_TOKEN(TK_AND); }
|
2014-09-06 19:46:56 +02:00
|
|
|
case '|':
|
2009-02-25 02:21:50 +01:00
|
|
|
NEXT();
|
2014-09-06 19:46:56 +02:00
|
|
|
if (CUR_CHAR != '|'){ RETURN_TOKEN('|') }
|
2009-02-25 02:21:50 +01:00
|
|
|
else { NEXT(); RETURN_TOKEN(TK_OR); }
|
2014-09-06 19:46:56 +02:00
|
|
|
case ':':
|
2009-02-25 02:21:50 +01:00
|
|
|
NEXT();
|
2014-09-06 19:46:56 +02:00
|
|
|
if (CUR_CHAR != ':'){ RETURN_TOKEN(':') }
|
2009-02-25 02:21:50 +01:00
|
|
|
else { NEXT(); RETURN_TOKEN(TK_DOUBLE_COLON); }
|
2014-09-06 19:46:56 +02:00
|
|
|
case '*':
|
2009-02-25 02:21:50 +01:00
|
|
|
NEXT();
|
2014-09-06 19:46:56 +02:00
|
|
|
if (CUR_CHAR == '='){ NEXT(); RETURN_TOKEN(TK_MULEQ);}
|
2009-02-25 02:21:50 +01:00
|
|
|
else RETURN_TOKEN('*');
|
2014-09-06 19:46:56 +02:00
|
|
|
case '%':
|
2009-02-25 02:21:50 +01:00
|
|
|
NEXT();
|
2014-09-06 19:46:56 +02:00
|
|
|
if (CUR_CHAR == '='){ NEXT(); RETURN_TOKEN(TK_MODEQ);}
|
2009-02-25 02:21:50 +01:00
|
|
|
else RETURN_TOKEN('%');
|
2014-09-06 19:46:56 +02:00
|
|
|
case '-':
|
2009-02-25 02:21:50 +01:00
|
|
|
NEXT();
|
2014-09-06 19:46:56 +02:00
|
|
|
if (CUR_CHAR == '='){ NEXT(); RETURN_TOKEN(TK_MINUSEQ);}
|
|
|
|
else if (CUR_CHAR == '-'){ NEXT(); RETURN_TOKEN(TK_MINUSMINUS);}
|
2009-02-25 02:21:50 +01:00
|
|
|
else RETURN_TOKEN('-');
|
2014-09-06 19:46:56 +02:00
|
|
|
case '+':
|
2009-02-25 02:21:50 +01:00
|
|
|
NEXT();
|
2014-09-06 19:46:56 +02:00
|
|
|
if (CUR_CHAR == '='){ NEXT(); RETURN_TOKEN(TK_PLUSEQ);}
|
|
|
|
else if (CUR_CHAR == '+'){ NEXT(); RETURN_TOKEN(TK_PLUSPLUS);}
|
2009-02-25 02:21:50 +01:00
|
|
|
else RETURN_TOKEN('+');
|
|
|
|
case SQUIRREL_EOB:
|
|
|
|
return 0;
|
|
|
|
default:{
|
2014-09-06 20:10:36 +02:00
|
|
|
if (isdigit(CUR_CHAR)) {
|
2009-02-25 02:21:50 +01:00
|
|
|
SQInteger ret = ReadNumber();
|
|
|
|
RETURN_TOKEN(ret);
|
|
|
|
}
|
2014-09-06 20:10:36 +02:00
|
|
|
else if (isalpha(CUR_CHAR) || CUR_CHAR == '_') {
|
2009-02-25 02:21:50 +01:00
|
|
|
SQInteger t = ReadID();
|
|
|
|
RETURN_TOKEN(t);
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
SQInteger c = CUR_CHAR;
|
2014-09-06 20:10:36 +02:00
|
|
|
if (iscntrl((int)c)) Error("unexpected character(control)");
|
2009-02-25 02:21:50 +01:00
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2014-09-07 08:46:03 +02:00
|
|
|
SQInteger SQLexer::ReadString(WChar ndelim,bool verbatim)
|
2009-02-25 02:21:50 +01:00
|
|
|
{
|
|
|
|
INIT_TEMP_STRING();
|
|
|
|
NEXT();
|
|
|
|
if(IS_EOB()) return -1;
|
|
|
|
for(;;) {
|
|
|
|
while(CUR_CHAR != ndelim) {
|
|
|
|
switch(CUR_CHAR) {
|
|
|
|
case SQUIRREL_EOB:
|
2014-09-06 19:46:56 +02:00
|
|
|
Error("unfinished string");
|
2009-02-25 02:21:50 +01:00
|
|
|
return -1;
|
2014-09-06 19:46:56 +02:00
|
|
|
case '\n':
|
|
|
|
if(!verbatim) Error("newline in a constant");
|
2009-02-25 02:21:50 +01:00
|
|
|
APPEND_CHAR(CUR_CHAR); NEXT();
|
|
|
|
_currentline++;
|
|
|
|
break;
|
2014-09-06 19:46:56 +02:00
|
|
|
case '\\':
|
2009-02-25 02:21:50 +01:00
|
|
|
if(verbatim) {
|
|
|
|
APPEND_CHAR('\\'); NEXT();
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
NEXT();
|
|
|
|
switch(CUR_CHAR) {
|
2014-09-06 19:46:56 +02:00
|
|
|
case 'x': NEXT(); {
|
|
|
|
if(!isxdigit(CUR_CHAR)) Error("hexadecimal number expected");
|
2009-02-25 02:21:50 +01:00
|
|
|
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;
|
2014-09-06 20:10:36 +02:00
|
|
|
APPEND_CHAR((SQChar)strtoul(temp,&sTemp,16));
|
2009-02-25 02:21:50 +01:00
|
|
|
}
|
|
|
|
break;
|
2014-09-06 19:46:56 +02:00
|
|
|
case 't': APPEND_CHAR('\t'); NEXT(); break;
|
|
|
|
case 'a': APPEND_CHAR('\a'); NEXT(); break;
|
|
|
|
case 'b': APPEND_CHAR('\b'); NEXT(); break;
|
|
|
|
case 'n': APPEND_CHAR('\n'); NEXT(); break;
|
|
|
|
case 'r': APPEND_CHAR('\r'); NEXT(); break;
|
|
|
|
case 'v': APPEND_CHAR('\v'); NEXT(); break;
|
|
|
|
case 'f': APPEND_CHAR('\f'); NEXT(); break;
|
|
|
|
case '0': APPEND_CHAR('\0'); NEXT(); break;
|
|
|
|
case '\\': APPEND_CHAR('\\'); NEXT(); break;
|
|
|
|
case '"': APPEND_CHAR('"'); NEXT(); break;
|
|
|
|
case '\'': APPEND_CHAR('\''); NEXT(); break;
|
2009-02-25 02:21:50 +01:00
|
|
|
default:
|
2014-09-06 19:46:56 +02:00
|
|
|
Error("unrecognised escaper char");
|
2009-02-25 02:21:50 +01:00
|
|
|
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;
|
2014-09-06 19:46:56 +02:00
|
|
|
if(ndelim == '\'') {
|
|
|
|
if(len == 0) Error("empty constant");
|
|
|
|
if(len > 1) Error("constant too long");
|
2009-02-25 02:21:50 +01:00
|
|
|
_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)
|
|
|
|
{
|
2014-09-06 20:10:36 +02:00
|
|
|
if(isdigit(*s)) *res = (*res)*16+((*s++)-'0');
|
|
|
|
else if(isxdigit(*s)) *res = (*res)*16+(toupper(*s++)-'A'+10);
|
2009-02-25 02:21:50 +01:00
|
|
|
else { assert(0); }
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void LexInteger(const SQChar *s,SQUnsignedInteger *res)
|
|
|
|
{
|
|
|
|
*res = 0;
|
|
|
|
while(*s != 0)
|
|
|
|
{
|
|
|
|
*res = (*res)*10+((*s++)-'0');
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-09-06 19:46:56 +02:00
|
|
|
SQInteger scisodigit(SQChar c) { return c >= '0' && c <= '7'; }
|
2009-02-25 02:21:50 +01:00
|
|
|
|
|
|
|
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 type = TINT, firstchar = CUR_CHAR;
|
|
|
|
SQChar *sTemp;
|
|
|
|
INIT_TEMP_STRING();
|
|
|
|
NEXT();
|
2014-09-06 19:46:56 +02:00
|
|
|
if(firstchar == '0' && (toupper(CUR_CHAR) == 'X' || scisodigit(CUR_CHAR)) ) {
|
2009-02-25 02:21:50 +01:00
|
|
|
if(scisodigit(CUR_CHAR)) {
|
|
|
|
type = TOCTAL;
|
|
|
|
while(scisodigit(CUR_CHAR)) {
|
|
|
|
APPEND_CHAR(CUR_CHAR);
|
|
|
|
NEXT();
|
|
|
|
}
|
2014-09-06 20:10:36 +02:00
|
|
|
if(isdigit(CUR_CHAR)) Error("invalid octal number");
|
2009-02-25 02:21:50 +01:00
|
|
|
}
|
|
|
|
else {
|
|
|
|
NEXT();
|
|
|
|
type = THEX;
|
|
|
|
while(isxdigit(CUR_CHAR)) {
|
|
|
|
APPEND_CHAR(CUR_CHAR);
|
|
|
|
NEXT();
|
|
|
|
}
|
2014-09-06 19:46:56 +02:00
|
|
|
if(_longstr.size() > MAX_HEX_DIGITS) Error("too many digits for an Hex number");
|
2009-02-25 02:21:50 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
APPEND_CHAR((int)firstchar);
|
2014-09-06 20:10:36 +02:00
|
|
|
while (CUR_CHAR == '.' || isdigit(CUR_CHAR) || isexponent(CUR_CHAR)) {
|
2014-09-06 19:46:56 +02:00
|
|
|
if(CUR_CHAR == '.' || isexponent(CUR_CHAR)) type = TFLOAT;
|
2009-02-25 02:21:50 +01:00
|
|
|
if(isexponent(CUR_CHAR)) {
|
2014-09-06 19:46:56 +02:00
|
|
|
if(type != TFLOAT) Error("invalid numeric format");
|
2009-02-25 02:21:50 +01:00
|
|
|
type = TSCIENTIFIC;
|
|
|
|
APPEND_CHAR(CUR_CHAR);
|
|
|
|
NEXT();
|
|
|
|
if(CUR_CHAR == '+' || CUR_CHAR == '-'){
|
|
|
|
APPEND_CHAR(CUR_CHAR);
|
|
|
|
NEXT();
|
|
|
|
}
|
2014-09-06 20:10:36 +02:00
|
|
|
if(!isdigit(CUR_CHAR)) Error("exponent expected");
|
2009-02-25 02:21:50 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
APPEND_CHAR(CUR_CHAR);
|
|
|
|
NEXT();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
TERMINATE_BUFFER();
|
|
|
|
switch(type) {
|
|
|
|
case TSCIENTIFIC:
|
|
|
|
case TFLOAT:
|
2014-09-06 20:10:36 +02:00
|
|
|
_fvalue = (SQFloat)strtod(&_longstr[0],&sTemp);
|
2009-02-25 02:21:50 +01:00
|
|
|
return TK_FLOAT;
|
|
|
|
case TINT:
|
|
|
|
LexInteger(&_longstr[0],(SQUnsignedInteger *)&_nvalue);
|
|
|
|
return TK_INTEGER;
|
|
|
|
case THEX:
|
|
|
|
LexHexadecimal(&_longstr[0],(SQUnsignedInteger *)&_nvalue);
|
|
|
|
return TK_INTEGER;
|
|
|
|
case TOCTAL:
|
|
|
|
LexOctal(&_longstr[0],(SQUnsignedInteger *)&_nvalue);
|
|
|
|
return TK_INTEGER;
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
SQInteger SQLexer::ReadID()
|
|
|
|
{
|
|
|
|
SQInteger res;
|
|
|
|
INIT_TEMP_STRING();
|
|
|
|
do {
|
|
|
|
APPEND_CHAR(CUR_CHAR);
|
|
|
|
NEXT();
|
2014-09-06 20:10:36 +02:00
|
|
|
} while(isalnum(CUR_CHAR) || CUR_CHAR == '_');
|
2009-02-25 02:21:50 +01:00
|
|
|
TERMINATE_BUFFER();
|
|
|
|
res = GetIDType(&_longstr[0]);
|
|
|
|
if(res == TK_IDENTIFIER || res == TK_CONSTRUCTOR) {
|
|
|
|
_svalue = &_longstr[0];
|
|
|
|
}
|
|
|
|
return res;
|
|
|
|
}
|