|
@@ -84,11 +84,18 @@ public:
|
|
|
_scope.stacksize = 0;
|
|
_scope.stacksize = 0;
|
|
|
_scope.nested = 0;
|
|
_scope.nested = 0;
|
|
|
compilererror = NULL;
|
|
compilererror = NULL;
|
|
|
|
|
+ _globals = SQTable::Create(_ss(_vm),0);
|
|
|
}
|
|
}
|
|
|
|
|
+ ~SQCompiler(){
|
|
|
|
|
+ _table(_globals)->Finalize();
|
|
|
|
|
+ _globals.Null();
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
static void ThrowError(void *ud, const SQChar *s) {
|
|
static void ThrowError(void *ud, const SQChar *s) {
|
|
|
SQCompiler *c = (SQCompiler *)ud;
|
|
SQCompiler *c = (SQCompiler *)ud;
|
|
|
c->Error(s);
|
|
c->Error(s);
|
|
|
- }
|
|
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
void Error(const SQChar *s, ...)
|
|
void Error(const SQChar *s, ...)
|
|
|
{
|
|
{
|
|
|
static SQChar temp[256];
|
|
static SQChar temp[256];
|
|
@@ -98,7 +105,8 @@ public:
|
|
|
va_end(vl);
|
|
va_end(vl);
|
|
|
compilererror = temp;
|
|
compilererror = temp;
|
|
|
longjmp(_errorjmp,1);
|
|
longjmp(_errorjmp,1);
|
|
|
- }
|
|
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
void Warning(const SQChar *s, ...)
|
|
void Warning(const SQChar *s, ...)
|
|
|
{
|
|
{
|
|
|
va_list vl;
|
|
va_list vl;
|
|
@@ -106,6 +114,39 @@ public:
|
|
|
scvfprintf(stderr, s, vl);
|
|
scvfprintf(stderr, s, vl);
|
|
|
va_end(vl);
|
|
va_end(vl);
|
|
|
}
|
|
}
|
|
|
|
|
+
|
|
|
|
|
+ void CheckGlobalName(const SQObject &name, bool addIfNotExists=false, bool checkLocals=true){
|
|
|
|
|
+ if(_table(_globals)->Exists(name)){
|
|
|
|
|
+ if(checkLocals) Error(_SC("global '%s' already declared"), _stringval(name));
|
|
|
|
|
+ else Warning(_SC("WARNING: %s:%d:%d global '%s' already declared will be shadowed\n"),
|
|
|
|
|
+ _stringval(_sourcename), _lex._currentline, _lex._currentcolumn, _stringval(name));
|
|
|
|
|
+ }
|
|
|
|
|
+ else if(checkLocals) CheckLocalNameScope(name, -1, false);
|
|
|
|
|
+ if(addIfNotExists) {
|
|
|
|
|
+ SQObjectPtr oname = name, otrue = true;
|
|
|
|
|
+ _table(_globals)->NewSlot(oname, otrue);
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ void CheckLocalNameScope(const SQObject &name, SQInteger scope, bool checkGlobals=true){
|
|
|
|
|
+ SQInteger found = _fs->GetLocalVariable(name);
|
|
|
|
|
+ if(found >= 0){
|
|
|
|
|
+ SQLocalVarInfo &lvi = _fs->_vlocals[found];
|
|
|
|
|
+ if(lvi._scope == scope)
|
|
|
|
|
+ Error(_SC("local '%s' already declared"), _stringval(name));
|
|
|
|
|
+ else
|
|
|
|
|
+ Warning(_SC("WARNING: %s:%d:%d local '%s' already declared will be shadowed\n"),
|
|
|
|
|
+ _stringval(_sourcename), _lex._currentline, _lex._currentcolumn, _stringval(name));
|
|
|
|
|
+ }
|
|
|
|
|
+ else
|
|
|
|
|
+ {
|
|
|
|
|
+ found = _fs->FindOuterVariable(name);
|
|
|
|
|
+ if(found >= 0) Warning(_SC("WARNING: %s:%d:%d outer variable '%s' already declared will be shadowed\n"),
|
|
|
|
|
+ _stringval(_sourcename), _lex._currentline, _lex._currentcolumn, _stringval(name));
|
|
|
|
|
+ }
|
|
|
|
|
+ if(checkGlobals) CheckGlobalName(name, false, false);
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
bool IsConstant(const SQObject &name,SQObject &e){
|
|
bool IsConstant(const SQObject &name,SQObject &e){
|
|
|
SQObjectPtr val;
|
|
SQObjectPtr val;
|
|
|
for(int i=_scope.nested-1; i >= 0; --i){
|
|
for(int i=_scope.nested-1; i >= 0; --i){
|
|
@@ -119,21 +160,36 @@ public:
|
|
|
return true;
|
|
return true;
|
|
|
}
|
|
}
|
|
|
return false;
|
|
return false;
|
|
|
- }
|
|
|
|
|
- bool ConstsExists(const SQObjectPtr &key){
|
|
|
|
|
- if(_scope.nested && _table(_scope_consts[_scope.nested-1])->Exists(key)) return true;
|
|
|
|
|
- return _table(_ss(_vm)->_consts)->Exists(key);
|
|
|
|
|
}
|
|
}
|
|
|
|
|
+
|
|
|
|
|
+ void CheckConstsExists(const SQObjectPtr &key){
|
|
|
|
|
+ int found = -1;
|
|
|
|
|
+ for(int i=_scope.nested-1; i >= 0; --i){
|
|
|
|
|
+ if(_table(_scope_consts[i])->Exists(key)) {
|
|
|
|
|
+ found = i+1;
|
|
|
|
|
+ break;
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ if(found < 0 && _table(_ss(_vm)->_consts)->Exists(key)) found = 0;
|
|
|
|
|
+ if(found == _scope.nested) {
|
|
|
|
|
+ Error(_SC("constant '%s' already exists\n"), _stringval(key));
|
|
|
|
|
+ }
|
|
|
|
|
+ if(found >= 0) Warning(_SC("WARNING: %s:%d:%d an already defined constant '%s' will be shadowed\n"),
|
|
|
|
|
+ _stringval(_sourcename), _lex._currentline, _lex._currentcolumn, _stringval(key));
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
bool ConstsGet(const SQObjectPtr &key,SQObjectPtr &val){
|
|
bool ConstsGet(const SQObjectPtr &key,SQObjectPtr &val){
|
|
|
for(int i=_scope.nested-1; i >= 0; --i){
|
|
for(int i=_scope.nested-1; i >= 0; --i){
|
|
|
if(_table(_scope_consts[i])->Get(key,val)) return true;
|
|
if(_table(_scope_consts[i])->Get(key,val)) return true;
|
|
|
}
|
|
}
|
|
|
return _table(_ss(_vm)->_consts)->Get(key,val);
|
|
return _table(_ss(_vm)->_consts)->Get(key,val);
|
|
|
}
|
|
}
|
|
|
|
|
+
|
|
|
bool ConstsNewSlot(const SQObjectPtr &key, const SQObjectPtr &val){
|
|
bool ConstsNewSlot(const SQObjectPtr &key, const SQObjectPtr &val){
|
|
|
if(_scope.nested) return _table(_scope_consts[_scope.nested-1])->NewSlot(key,val);
|
|
if(_scope.nested) return _table(_scope_consts[_scope.nested-1])->NewSlot(key,val);
|
|
|
return _table(_ss(_vm)->_consts)->NewSlot(key,val);
|
|
return _table(_ss(_vm)->_consts)->NewSlot(key,val);
|
|
|
- }
|
|
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
void Lex(){ _token = _lex.Lex();}
|
|
void Lex(){ _token = _lex.Lex();}
|
|
|
SQObjectPtr GetTokenObject(SQInteger tok)
|
|
SQObjectPtr GetTokenObject(SQInteger tok)
|
|
|
{
|
|
{
|
|
@@ -366,10 +422,8 @@ public:
|
|
|
SQObject id = Expect(TK_IDENTIFIER);
|
|
SQObject id = Expect(TK_IDENTIFIER);
|
|
|
Expect('=');
|
|
Expect('=');
|
|
|
SQObjectPtr strongid = id;
|
|
SQObjectPtr strongid = id;
|
|
|
- if(ConstsExists(strongid)) {
|
|
|
|
|
- strongid.Null();
|
|
|
|
|
- Error(_SC("constant '%s' already exists"), _stringval(id));
|
|
|
|
|
- }
|
|
|
|
|
|
|
+ CheckLocalNameScope(id, _scope.nested);
|
|
|
|
|
+ CheckConstsExists(strongid);
|
|
|
SQObject val = ExpectScalar();
|
|
SQObject val = ExpectScalar();
|
|
|
OptionalSemicolon();
|
|
OptionalSemicolon();
|
|
|
ConstsNewSlot(strongid,SQObjectPtr(val));
|
|
ConstsNewSlot(strongid,SQObjectPtr(val));
|
|
@@ -1080,23 +1134,6 @@ public:
|
|
|
_fs->SetIntructionParam(tpos, 1, nkeys);
|
|
_fs->SetIntructionParam(tpos, 1, nkeys);
|
|
|
Lex();
|
|
Lex();
|
|
|
}
|
|
}
|
|
|
- void checkLocalNameScope(const SQObject &name, SQInteger scope){
|
|
|
|
|
- SQInteger found = _fs->GetLocalVariable(name);
|
|
|
|
|
- if(found >= 0){
|
|
|
|
|
- SQLocalVarInfo &lvi = _fs->_vlocals[found];
|
|
|
|
|
- if(lvi._scope == scope)
|
|
|
|
|
- Error(_SC("local '%s' already declared"), _stringval(name));
|
|
|
|
|
- else
|
|
|
|
|
- Warning(_SC("WARNING: at line %d:%d local '%s' already declared will be shadowed\n"),
|
|
|
|
|
- _lex._currentline, _lex._currentcolumn, _stringval(name));
|
|
|
|
|
- }
|
|
|
|
|
- else
|
|
|
|
|
- {
|
|
|
|
|
- found = _fs->FindOuterVariable(name);
|
|
|
|
|
- if(found >= 0) Warning(_SC("WARNING: at line %d:%d outer variable '%s' already declared will be shadowed\n"),
|
|
|
|
|
- _lex._currentline, _lex._currentcolumn, _stringval(name));
|
|
|
|
|
- }
|
|
|
|
|
- }
|
|
|
|
|
void LocalDeclStatement()
|
|
void LocalDeclStatement()
|
|
|
{
|
|
{
|
|
|
SQObject varname;
|
|
SQObject varname;
|
|
@@ -1107,7 +1144,7 @@ public:
|
|
|
if( _token == TK_FUNCTION) {
|
|
if( _token == TK_FUNCTION) {
|
|
|
Lex();
|
|
Lex();
|
|
|
varname = Expect(TK_IDENTIFIER);
|
|
varname = Expect(TK_IDENTIFIER);
|
|
|
- checkLocalNameScope(varname, _scope.nested);
|
|
|
|
|
|
|
+ CheckLocalNameScope(varname, _scope.nested);
|
|
|
Expect(_SC('('));
|
|
Expect(_SC('('));
|
|
|
//the following is an attempt to allow local declared functions be called recursivelly
|
|
//the following is an attempt to allow local declared functions be called recursivelly
|
|
|
SQInteger old_pos = _fs->GetCurrentPos(); //save current instructions position
|
|
SQInteger old_pos = _fs->GetCurrentPos(); //save current instructions position
|
|
@@ -1129,7 +1166,7 @@ public:
|
|
|
Lex();
|
|
Lex();
|
|
|
}
|
|
}
|
|
|
varname = Expect(TK_IDENTIFIER);
|
|
varname = Expect(TK_IDENTIFIER);
|
|
|
- checkLocalNameScope(varname, _scope.nested);
|
|
|
|
|
|
|
+ CheckLocalNameScope(varname, _scope.nested);
|
|
|
if(_token == _SC('=')) {
|
|
if(_token == _SC('=')) {
|
|
|
Lex(); Expression();
|
|
Lex(); Expression();
|
|
|
SQInteger src = _fs->PopTarget();
|
|
SQInteger src = _fs->PopTarget();
|
|
@@ -1430,7 +1467,8 @@ if(color == "yellow"){
|
|
|
void FunctionStatement()
|
|
void FunctionStatement()
|
|
|
{
|
|
{
|
|
|
SQObject id;
|
|
SQObject id;
|
|
|
- Lex(); id = Expect(TK_IDENTIFIER);
|
|
|
|
|
|
|
+ Lex(); id = Expect(TK_IDENTIFIER);
|
|
|
|
|
+ CheckGlobalName(id, true);
|
|
|
_fs->PushTarget(0);
|
|
_fs->PushTarget(0);
|
|
|
_fs->AddInstruction(_OP_LOAD, _fs->PushTarget(), _fs->GetConstant(id));
|
|
_fs->AddInstruction(_OP_LOAD, _fs->PushTarget(), _fs->GetConstant(id));
|
|
|
if(_token == TK_DOUBLE_COLON) Emit2ArgsOP(_OP_GET);
|
|
if(_token == TK_DOUBLE_COLON) Emit2ArgsOP(_OP_GET);
|
|
@@ -1450,14 +1488,18 @@ if(color == "yellow"){
|
|
|
void ClassStatement()
|
|
void ClassStatement()
|
|
|
{
|
|
{
|
|
|
SQExpState es;
|
|
SQExpState es;
|
|
|
- Lex();
|
|
|
|
|
|
|
+ Lex();
|
|
|
|
|
+ if(_token == TK_IDENTIFIER) {
|
|
|
|
|
+ SQObjectPtr str = SQString::Create(_ss(_vm), _lex._svalue);
|
|
|
|
|
+ CheckGlobalName(str, true);
|
|
|
|
|
+ }
|
|
|
es = _es;
|
|
es = _es;
|
|
|
_es.donot_get = true;
|
|
_es.donot_get = true;
|
|
|
PrefixedExpr();
|
|
PrefixedExpr();
|
|
|
if(_es.etype == EXPR) {
|
|
if(_es.etype == EXPR) {
|
|
|
Error(_SC("invalid class name"));
|
|
Error(_SC("invalid class name"));
|
|
|
}
|
|
}
|
|
|
- else if(_es.etype == OBJECT || _es.etype == BASE) {
|
|
|
|
|
|
|
+ else if(_es.etype == OBJECT || _es.etype == BASE) {
|
|
|
ClassExp();
|
|
ClassExp();
|
|
|
EmitDerefOp(_OP_NEWSLOT);
|
|
EmitDerefOp(_OP_NEWSLOT);
|
|
|
_fs->PopTarget();
|
|
_fs->PopTarget();
|
|
@@ -1511,13 +1553,10 @@ if(color == "yellow"){
|
|
|
SQObject id = Expect(TK_IDENTIFIER);
|
|
SQObject id = Expect(TK_IDENTIFIER);
|
|
|
Expect(_SC('{'));
|
|
Expect(_SC('{'));
|
|
|
|
|
|
|
|
- //checkLocalNameScope(id, _scope.nested);
|
|
|
|
|
|
|
+ //CheckLocalNameScope(id, _scope.nested);
|
|
|
SQObjectPtr strongid = id;
|
|
SQObjectPtr strongid = id;
|
|
|
- if(ConstsExists(strongid)) {
|
|
|
|
|
- strongid.Null();
|
|
|
|
|
- Error(_SC("constant '%s' already exists"), _stringval(id));
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
|
|
+ CheckLocalNameScope(id, _scope.nested);
|
|
|
|
|
+ CheckConstsExists(strongid);
|
|
|
SQObject table = _fs->CreateTable();
|
|
SQObject table = _fs->CreateTable();
|
|
|
//_fs->AddInstruction(_OP_NEWOBJ, _fs->PushTarget(),0,NOT_TABLE);
|
|
//_fs->AddInstruction(_OP_NEWOBJ, _fs->PushTarget(),0,NOT_TABLE);
|
|
|
SQInteger nval = 0;
|
|
SQInteger nval = 0;
|
|
@@ -1744,7 +1783,8 @@ private:
|
|
|
SQChar *compilererror;
|
|
SQChar *compilererror;
|
|
|
jmp_buf _errorjmp;
|
|
jmp_buf _errorjmp;
|
|
|
SQVM *_vm;
|
|
SQVM *_vm;
|
|
|
- SQObjectPtrVec _scope_consts;
|
|
|
|
|
|
|
+ SQObjectPtrVec _scope_consts;
|
|
|
|
|
+ SQObjectPtr _globals;
|
|
|
};
|
|
};
|
|
|
|
|
|
|
|
bool Compile(SQVM *vm,SQLEXREADFUNC rg, SQUserPointer up, const SQChar *sourcename, SQObjectPtr &out, bool raiseerror, bool lineinfo)
|
|
bool Compile(SQVM *vm,SQLEXREADFUNC rg, SQUserPointer up, const SQChar *sourcename, SQObjectPtr &out, bool raiseerror, bool lineinfo)
|