Browse Source

Add preproccessor directives #ifdef, #else, #endif, #define and #undef they are parsed at the same time as the script, I mean it's not a two pass scan/parse, the named proproccessor variables are not accessible to scripts.

mingodad 8 years ago
parent
commit
9f8b951d6d

+ 17 - 4
SquiLu/sq/sq.c

@@ -101,6 +101,7 @@ void PrintUsage()
 		_SC("   -v              displays version infos\n")
 		_SC("   -v              displays version infos\n")
 		_SC("   -p              preload given script file\n")
 		_SC("   -p              preload given script file\n")
 		_SC("   -i              set the include_path\n")
 		_SC("   -i              set the include_path\n")
+		_SC("   -D              define a preprocesor named constant\n")
 		_SC("   -h              prints help\n"));
 		_SC("   -h              prints help\n"));
 }
 }
 
 
@@ -174,6 +175,20 @@ int getargs(HSQUIRRELVM v,int argc, char* argv[],SQInteger *retval)
 						sq_set_include_path(v, argv[arg]);
 						sq_set_include_path(v, argv[arg]);
 					}
 					}
 					break;
 					break;
+				case 'D':
+					if(arg < argc) {
+						if(argv[arg][2])
+                        {
+                            //printf("-D=%s\n", argv[arg]+2);
+                            sq_set_define_name(v, argv[arg]+2);
+                        }
+                        else //argument separated by spaces
+                        {
+                            arg++;
+                            sq_set_define_name(v, argv[arg]);
+                        }
+					}
+					break;
 				case 'v':
 				case 'v':
 					PrintVersionInfos();
 					PrintVersionInfos();
 					return _DONE;
 					return _DONE;
@@ -255,7 +270,6 @@ int getargs(HSQUIRRELVM v,int argc, char* argv[],SQInteger *retval)
 					if(SQ_SUCCEEDED(sq_call(v,callargs,SQTrue,SQTrue))) {
 					if(SQ_SUCCEEDED(sq_call(v,callargs,SQTrue,SQTrue))) {
 						SQObjectType type = sq_gettype(v,-1);
 						SQObjectType type = sq_gettype(v,-1);
 						if(type == OT_INTEGER) {
 						if(type == OT_INTEGER) {
-							*retval = type;
 							sq_getinteger(v,-1,retval);
 							sq_getinteger(v,-1,retval);
 						}
 						}
 						//if there is a function called "main" we call it like in C/C++
 						//if there is a function called "main" we call it like in C/C++
@@ -272,7 +286,6 @@ int getargs(HSQUIRRELVM v,int argc, char* argv[],SQInteger *retval)
                                 if(SQ_SUCCEEDED(sq_call(v,3,SQTrue,SQTrue))) {
                                 if(SQ_SUCCEEDED(sq_call(v,3,SQTrue,SQTrue))) {
                                     SQObjectType type = sq_gettype(v,-1);
                                     SQObjectType type = sq_gettype(v,-1);
                                     if(type == OT_INTEGER) {
                                     if(type == OT_INTEGER) {
-                                        *retval = type;
                                         sq_getinteger(v,-1,retval);
                                         sq_getinteger(v,-1,retval);
                                     }
                                     }
                                 }
                                 }
@@ -666,7 +679,7 @@ static sq_modules_preload_st modules_preload[] = {
 #endif
 #endif
     {"slave_vm", sqext_register_sq_slave_vm},
     {"slave_vm", sqext_register_sq_slave_vm},
     //{"thread", sqext_register_ThreadObjects},
     //{"thread", sqext_register_ThreadObjects},
-#if !defined(ANDROID_BUILD)
+#ifndef ANDROID_BUILD
     {"dad_utils", sqext_register_dad_utils},
     {"dad_utils", sqext_register_dad_utils},
 #endif
 #endif
     //{"sys_extra", sqext_register_sys},
     //{"sys_extra", sqext_register_sys},
@@ -688,7 +701,7 @@ static sq_modules_preload_st modules_preload[] = {
 #ifdef WITH_MYSQL
 #ifdef WITH_MYSQL
     {"mysql", sqext_register_MySQL},
     {"mysql", sqext_register_MySQL},
 #endif
 #endif
-#if !defined(ANDROID_BUILD)
+#ifndef ANDROID_BUILD
     {"rs232", sqext_register_rs232},
     {"rs232", sqext_register_rs232},
 #endif
 #endif
 #ifdef WITH_FLTK
 #ifdef WITH_FLTK

+ 14 - 0
SquiLu/squirrel/sqapi.cpp

@@ -161,6 +161,20 @@ const SQChar * sq_get_include_path(HSQUIRRELVM v)
 	return v->GetIncludePath();
 	return v->GetIncludePath();
 }
 }
 
 
+SQBool sq_set_define_name(HSQUIRRELVM v, const SQChar *define_name)
+{
+	return v->AddDefined(define_name);
+}
+
+void sq_remove_define_name(HSQUIRRELVM v, const SQChar *define_name)
+{
+	v->RemoveDefined(define_name);
+}
+
+SQBool sq_exists_define_name(HSQUIRRELVM v, const SQChar *define_name)
+{
+	return v->IsDefined(define_name);
+}
 SQRESULT sq_compile(HSQUIRRELVM v,SQLEXREADFUNC read,SQUserPointer p,const SQChar *sourcename
 SQRESULT sq_compile(HSQUIRRELVM v,SQLEXREADFUNC read,SQUserPointer p,const SQChar *sourcename
                     ,SQBool raiseerror, SQBool show_warnings, SQInteger max_nested_includes)
                     ,SQBool raiseerror, SQBool show_warnings, SQInteger max_nested_includes)
 {
 {

+ 58 - 1
SquiLu/squirrel/sqcompiler.cpp

@@ -168,6 +168,9 @@ public:
         _max_nested_includes = max_nested_includes;
         _max_nested_includes = max_nested_includes;
         _nested_includes_count = 0;
         _nested_includes_count = 0;
         _is_parsing_extern = false;
         _is_parsing_extern = false;
+        _ifdef_exclude = 0;
+        _ifdef_line = 0;
+        _inside_ifdef = 0;
         squilu_lib_path = NULL;
         squilu_lib_path = NULL;
     }
     }
     ~SQCompiler()
     ~SQCompiler()
@@ -519,8 +522,17 @@ public:
     void Pragma()
     void Pragma()
     {
     {
         int line = _lex.data->currentline;
         int line = _lex.data->currentline;
-        //int column = _lex.data->currentcolumn;
+        int column = _lex.data->currentcolumn;
         Lex();
         Lex();
+        if(_token == TK_ELSE)
+        {
+            if(!_inside_ifdef) Error(_SC("'#else' without '#ifdef'"));
+            Lex();
+            //if we were not been excluding we start excluding
+            if(_ifdef_exclude == 0) ++_ifdef_exclude;
+            else if(_ifdef_exclude == 1) --_ifdef_exclude;
+            return;
+        }
         SQObject id = Expect(TK_IDENTIFIER);
         SQObject id = Expect(TK_IDENTIFIER);
         if(scstrcmp(_stringval(id), _SC("include")) == 0)
         if(scstrcmp(_stringval(id), _SC("include")) == 0)
         {
         {
@@ -594,6 +606,7 @@ public:
 
 
                 //close file
                 //close file
                 fclose(fp);
                 fclose(fp);
+                if(_inside_ifdef) Error(_SC("unterminated #ifdef starting on line %d"), _ifdef_line);
                 //restore saved source file and lex state
                 //restore saved source file and lex state
                 _fs->_sourcename = saved_source_name;
                 _fs->_sourcename = saved_source_name;
                 _sourcename = saved_source_name;
                 _sourcename = saved_source_name;
@@ -620,6 +633,43 @@ public:
             Error(_SC("Error: includes are not enabled\n"));
             Error(_SC("Error: includes are not enabled\n"));
 #endif
 #endif
         }
         }
+        else if(scstrcmp(_stringval(id), _SC("endif")) == 0)
+        {
+            if(!_inside_ifdef) Error(_SC("'#endif' without '#ifdef'"));
+            if(_ifdef_exclude) --_ifdef_exclude;
+            --_inside_ifdef;
+        }
+        else if((scstrcmp(_stringval(id), _SC("ifdef")) == 0)
+                || (scstrcmp(_stringval(id), _SC("ifndef")) == 0))
+        {
+            ++_inside_ifdef;
+            bool isIfndef = _stringval(id)[2] == _SC('n');
+            id = Expect(TK_IDENTIFIER);
+            if(_ifdef_exclude) ++_ifdef_exclude;
+            else
+            {
+                _ifdef_line = line;
+                bool isDefined = _vm->IsDefined(_stringval(id));
+                if(isIfndef) isDefined = !isDefined;
+                _ifdef_exclude = (isDefined ? 0 : 1);
+            }
+        }
+        else if(scstrcmp(_stringval(id), _SC("define")) == 0)
+        {
+            id = Expect(TK_IDENTIFIER);
+            if(_ifdef_exclude == 0)
+            {
+                if(_vm->IsDefined(_stringval(id)))
+                    Warning(_SC("%s:%d:%d warning '%s' redefined\n"),
+                        _stringval(_sourcename), line, column, _stringval(id));
+                _vm->AddDefined(_stringval(id));
+            }
+        }
+        else if(scstrcmp(_stringval(id), _SC("undef")) == 0)
+        {
+            id = Expect(TK_IDENTIFIER);
+            if(_ifdef_exclude == 0) _vm->RemoveDefined(_stringval(id));
+        }
         else
         else
         {
         {
             _lex.data->currentline = line;
             _lex.data->currentline = line;
@@ -649,6 +699,7 @@ public:
                 Statement();
                 Statement();
                 if(_lex.data->prevtoken != _SC('}') && _lex.data->prevtoken != _SC(';')) OptionalSemicolon();
                 if(_lex.data->prevtoken != _SC('}') && _lex.data->prevtoken != _SC(';')) OptionalSemicolon();
             }
             }
+            if(_inside_ifdef) Error(_SC("unterminated #ifdef starting on line %d"), _ifdef_line);
             _fs->SetStackSize(stacksize);
             _fs->SetStackSize(stacksize);
             _fs->AddLineInfos(_lex.data->currentline, _lineinfo, true);
             _fs->AddLineInfos(_lex.data->currentline, _lineinfo, true);
             _fs->AddInstruction(_OP_RETURN, 0xFF);
             _fs->AddInstruction(_OP_RETURN, 0xFF);
@@ -685,6 +736,11 @@ public:
         _es.etype = EXPR_STATEMENT;
         _es.etype = EXPR_STATEMENT;
         SQObject id;
         SQObject id;
         _fs->AddLineInfos(_lex.data->currentline, _lineinfo);
         _fs->AddLineInfos(_lex.data->currentline, _lineinfo);
+        while(_ifdef_exclude && (_token != TK_PRAGMA))
+        {
+            Lex();
+            if(_token <= 0) Error(_SC("'#endif' expected to close '#ifdef' started at %d"), _ifdef_line);
+        }
 start_again:
 start_again:
         switch(_token)
         switch(_token)
         {
         {
@@ -3301,6 +3357,7 @@ private:
     SQObjectPtr _extern_names; //to allow C/C++ style extern declarations
     SQObjectPtr _extern_names; //to allow C/C++ style extern declarations
     SQChar error_buf[MAX_COMPILER_ERROR_LEN];
     SQChar error_buf[MAX_COMPILER_ERROR_LEN];
     SQInteger _max_nested_includes, _nested_includes_count;
     SQInteger _max_nested_includes, _nested_includes_count;
+    SQInteger _ifdef_exclude, _ifdef_line, _inside_ifdef;
     const SQChar *squilu_lib_path;
     const SQChar *squilu_lib_path;
 };
 };
 
 

+ 3 - 0
SquiLu/squirrel/sqstate.cpp

@@ -115,6 +115,7 @@ void SQSharedState::Init()
 	sq_new(_metamethods,SQObjectPtrVec);
 	sq_new(_metamethods,SQObjectPtrVec);
 	sq_new(_systemstrings,SQObjectPtrVec);
 	sq_new(_systemstrings,SQObjectPtrVec);
 	sq_new(_types,SQObjectPtrVec);
 	sq_new(_types,SQObjectPtrVec);
+	_defined_names = SQTable::Create(this,0);
 	_metamethodsmap = SQTable::Create(this,MT_LAST-1);
 	_metamethodsmap = SQTable::Create(this,MT_LAST-1);
 	//adding type strings to avoid memory trashing
 	//adding type strings to avoid memory trashing
 	//types names
 	//types names
@@ -178,9 +179,11 @@ SQSharedState::~SQSharedState()
 	_table(_registry)->Finalize();
 	_table(_registry)->Finalize();
 	_table(_consts)->Finalize();
 	_table(_consts)->Finalize();
 	_table(_metamethodsmap)->Finalize();
 	_table(_metamethodsmap)->Finalize();
+	_table(_defined_names)->Finalize();
 	_registry.Null();
 	_registry.Null();
 	_consts.Null();
 	_consts.Null();
 	_metamethodsmap.Null();
 	_metamethodsmap.Null();
+	_defined_names.Null();
 	while(!_systemstrings->empty()) {
 	while(!_systemstrings->empty()) {
 		_systemstrings->back().Null();
 		_systemstrings->back().Null();
 		_systemstrings->pop_back();
 		_systemstrings->pop_back();

+ 1 - 0
SquiLu/squirrel/sqstate.h

@@ -86,6 +86,7 @@ public:
 	SQObjectPtr _metamethodsmap;
 	SQObjectPtr _metamethodsmap;
 	SQObjectPtrVec *_systemstrings;
 	SQObjectPtrVec *_systemstrings;
 	SQObjectPtrVec *_types;
 	SQObjectPtrVec *_types;
+	SQObjectPtr _defined_names;
 	SQStringTable *_stringtable;
 	SQStringTable *_stringtable;
 	RefTable _refs_table;
 	RefTable _refs_table;
 	SQObjectPtr _registry;
 	SQObjectPtr _registry;

+ 13 - 0
SquiLu/squirrel/sqvm.cpp

@@ -2055,6 +2055,19 @@ SQObjectPtr &SQVM::GetUp(SQInteger n) { return _stack[_top+n]; }
 SQObjectPtr &SQVM::GetAt(SQInteger n) { return _stack[n]; }
 SQObjectPtr &SQVM::GetAt(SQInteger n) { return _stack[n]; }
 void SQVM::SetIncludePath(const SQChar *s){_include_path = SQString::Create(_ss(this), s);}
 void SQVM::SetIncludePath(const SQChar *s){_include_path = SQString::Create(_ss(this), s);}
 const SQChar *SQVM::GetIncludePath(){return (sq_type(_include_path) == OT_STRING) ? _stringval(_include_path) : NULL;}
 const SQChar *SQVM::GetIncludePath(){return (sq_type(_include_path) == OT_STRING) ? _stringval(_include_path) : NULL;}
+bool SQVM::AddDefined(const SQChar *s){
+	SQObjectPtr key = SQString::Create(_ss(this), s);
+	SQObjectPtr value;
+    return _table(_ss(this)->_defined_names)->NewSlot(key, value);
+};
+void SQVM::RemoveDefined(const SQChar *s){
+	SQObjectPtr key = SQString::Create(_ss(this), s);
+	_table(_ss(this)->_defined_names)->Remove(key);
+};
+bool SQVM::IsDefined(const SQChar *s){
+	SQObjectPtr key = SQString::Create(_ss(this), s);
+	return _table(_ss(this)->_defined_names)->Exists(key);
+};
 
 
 #ifdef _DEBUG_DUMP
 #ifdef _DEBUG_DUMP
 void SQVM::dumpstack(SQInteger stackbase,bool dumpall)
 void SQVM::dumpstack(SQInteger stackbase,bool dumpall)

+ 3 - 0
SquiLu/squirrel/sqvm.h

@@ -160,6 +160,9 @@ public:
 
 
 	void SetIncludePath(const SQChar *s);
 	void SetIncludePath(const SQChar *s);
 	const SQChar *GetIncludePath();
 	const SQChar *GetIncludePath();
+	bool AddDefined(const SQChar *s);
+	void RemoveDefined(const SQChar *s);
+	bool IsDefined(const SQChar *s);
 	SQObjectPtrVec _stack;
 	SQObjectPtrVec _stack;
 
 
 	SQInteger _top;
 	SQInteger _top;