Preprocessor Directives
Preprocessor directives are special language constructs, which control the script interpreter behavior. All UnigineScript directives begin with the # sign, and each of them should be on its own line. Note that there are no semicolons at the end of strings that start with directives.
Preprocessor Macros
A macro is a fragment of code which has been given a name. Whenever the name is used, it is replaced by the contents of the macro.
There is a pre-defined set of macros:
- _VERSION_ - the UnigineScript interpreter version, for example, "1.82"
- NDEBUG - the binary does not contain debugging information (release build)
- _WIN32 - target operating system is Windows
- _LINUX - target operating system is Linux
- _MACOS - target operating system is Mac OS X
- HAS_BUFFER - Buffer Class is available in the Core Library
- HAS_DIRECT3D11 - the binary is built with Direct3D 11 rendering system
- HAS_DIRECT3D119 - the binary is built with Direct3D 11 feature level 9 rendering system
- HAS_JOYSTICK - the binary is built with support of a joystick
- HAS_IMAGE - Image Class is available in the Core Library
- HAS_MEMORY - the binary is built with Unigine memory management system
- HAS_OPENAL - the binary is built with OpenAL sound system
- HAS_OPENGL - the binary is built with OpenGL rendering system
- HAS_REGEXP - Regexp Class is available in the Core Library
- HAS_SOCKET - Socket Class is available in the Core Library
- HAS_XAUDIO21 - the binary is built with XAudio2 sound system
- HAS_XML - Xml Class is available in the Core Library
- HAS_XPAD360 - the binary is built with support of Xbox 360 gamepad
- USE_DOUBLE - the binary is built with support of double precision of coordinates
- USE_MICROPROFILE - the binary is built with support of microprofile.
- USE_OPENGL_DEBUG_OUTPUT - the binary is built with the OpenGL debug context.
These macros can be used as conditions and combined with logical operators: () for grouping, || for "or", && for "and".
#include
Loads the content of a given file.
Syntax: #include "someFile"
Here someFile is a target file name.
#include "foo.h"
foo(); // ok if foo.h contains declaration of foo()
To avoid conflicts it's recommended to include files this way:
#ifndef __MYLIB_H__
#define __MYLIB_H__
#include "myLib.h"
#endif /* __MYLIB_H__ */
#define
Sets an identifier and a character sequence, by which the identifier will be replaced in the text of the program.
Syntax: #define macro_name character_sequence
Here macro_name will be replaced with character_sequence everywhere in the code. Note that character_sequence shouldn't contain spaces (except for strings, which must be enclosed in double quotes) and can be omitted.
#define LEFT 1
#define RIGHT 0
log.message("%d %d\n",LEFT,RIGHT);
// Output: 1 0
#define FRUIT "an apple"
log.message("%s\n", "today we will eat "FRUIT);
// Output: today we will eat an apple
// arguments are also supported:
#define saturate(v) clamp(v,0.0,1.0)
// literal # operator:
#define assert(EXP) { if(EXP) { } else { throw("Assertion: '%s'",#EXP); } }
See also Templates.
#
Turns a macro argument into a string constant.
Syntax: #macro_arg
Here macro_arg is an argument to a macro.
#define assert(EXP) { if(EXP) { } else { throw("Assertion: '%s'",#EXP); } }
See also: #define .
#undef
Removes a previously defined identifier.
Syntax: #undef macro_name
#define LOCK
#undef LOCK
#ifndef LOCK
log.message("unlocked\n"); // this fragment will be executed
#endif
#ifdef
Allows executing some fragment of code conditionally, if a given identifier is defined with #define.
Syntax:
#ifdef macro_name
some_code #endif
If macro_name is defined, then some_code will be executed.
#define LOCK1
#define LOCK2
#ifdef (LOCK1 && LOCK2) || LOCK3
log.message("locked\n"); // this fragment will be executed
#endif
#ifndef
Allows executing some fragment of code conditionally, if a given identifier is not defined with #define or is undefined with #undef.
Syntax:
#ifndef macro_name
some_code #endif
If macro_name is not defined, then some_code will be executed.
#define LOCK
#ifndef LOCK
log.message("unlocked\n"); // this fragment will NOT be executed
#endif
#else
Creates an alternative to #ifdef and #ifndef pragmas.
Syntax:
#ifdef macro_name some_code
#else some_more_code
#endif
Here #ifndef can be used instead of #ifdef (however, the meaning of the condition will be reversed). If the first condition is false, then everything from the first #else up to the first #endif will be executed.
#define SOUND_ENABLE
#ifdef SOUND_ENABLE
log.message("sound enabled\n");
#else
log.message("sound disabled\n"); // this fragment will be executed
#endif
#elif
Create a conditional alternative to #ifdef and #ifndef pragmas.
Syntax:
#ifdef macro_name1 some_code1
#elif macro_name2 some_code2
#endif
Here #ifndef can be used instead of #ifdef (however, the meaning of the condition will be reversed). If macro_name1 is false, then macro_name2 is tested, and if it's true, everything from this #elif up to the first #elif, #else or #endif will be executed.
#define VAL2
#ifdef VAL1
log.message("it is 1\n");
#elif VAL2
log.message("it is 2\n"); // this fragment will be executed
#elif VAL3
log.message("it is 3\n");
#endif
#endif
Marks an end of conditional compilation.
#error
Terminates execution of the script and logs the message into the console and a system log file.
Syntax: #error message_text
#error I don't want to execute it any longer
#warning
Logs the message into the console and a system log file, the script continues execution.
Syntax: #warning message_text
#warning There is somethings wrong in here
#warn_long
Terminates compilation if a variable of a long type is used in the script, and logs the error message into the console and a system log file.
#warn_double
Terminates compilation if a variable of a double type is used in the script, and logs the error message into the console and a system log file.