Using the Preprocessor
Here are the preprocessor directives supported by Tibbo BASIC and Tibbo C.
#define
Creates a macro, which is the association of the preprocessor identifier with a token string.
#define RED 0
#define GREEN 1
#define BLUE 2
#define COLOR BLUE
TIDE also features "global" preprocessor identifiers. You can inspect them in the Customize Project dialog (File > Project Settings —> Customize (button)).
The dialog shows global identifiers that come directly from platform files. Some identifiers allow you to alter their values. You can also define your own global identifiers.
Like identifiers defined with the #define directive, all these global identifiers can be used in conditional preprocessor constructs described below.
The difference between preprocessor identifiers defined using the #define directive and the global ones is that global identifiers can additionally be used in setting file compilation conditions.
#undef
Un-defines (removes) the current definition of the preprocessor identifier.
#define GREEN 1
...
#undef GREEN
#ifdef—#else—#endif
Conditional compilation construct that checks if the specified preprocessor identifier exists.
#define GREEN 1 ... dim s as string #ifdef GREEN 'code here will be included s="GREEN is defined" #else 'code here will not be included s="GREEN is not defined" #endif
#define GREEN 1 ... string s; #ifdef GREEN //code here will be included s="GREEN is defined"; #else //code here will not be included s="GREEN is not defined"; #endif
#if defined (C Only)
This is a more sophisticated version of #ifdef, it allows you to set compound conditions.
Note how the #if defined construct requires parentheses around macro identifiers.
#define PRINTER 1 #if defined(PRINTER) && !defined(ABC) 'code here will be included #endif
#ifndef—#else—#endif
Conditional compilation construct that checks if the specified preprocessor identifier does not exists.
#define GREEN 1 ... dim s as string #ifndef GREEN 'code here will not be included s="GREEN is not defined" #else 'code here will be included s="GREEN is defined" #endif
#define GREEN 1 ... string s; #ifndef GREEN //code here will not be included s="GREEN is not defined"; #else //code here will be included s="GREEN is defined"; #endif
#if—#elif—#else—#endif
Conditional compilation construct that evaluates an expression involving preprocessor identifiers.
Reminder: Some relational and logic operators differ between BASIC and C. What's #if COLOR=RED in BASIC is #if COLOR==RED in C!
#define RED 0 #define GREEN 1 #define BLUE 2 #define COLOR GREEN #if COLOR=RED 'code here will not be included #elif COLOR=GREEN 'code here will be included #else 'code here will not be included #endif
#define RED 0 #define GREEN 1 #define BLUE 2 #define COLOR GREEN #if COLOR==RED //code here will not be included #elif COLOR==GREEN //code here will be included #else //code here will not be included #endif
#include (C); include (BASIC)
In BASIC, files are included with the include statement, which is technically not a part of the preprocessor.
I am combining this with the C preprocessor directive #include, because the two do exactly the same job.
'remember, headers files must be included, 'it's not enough to just have them in the project tree include "global.tbh"
//remember, headers files must be included, //it's not enough to just have them in the project tree #include "global.tbh"
#includeb (C Only)
Allows you to include a BASIC header file (.TBH) from a C file. This is a powerful tool that you can use to avoid having two identical header files with definitions — one for BASIC and a mirror one for C.
The reverse directive for including C headers from BASIC files does not exist.
dim ctr as byte
include "global.tbh" sub on_sys_init ctr=0 end sub
#includeb "global.tbh" void on_sys_timer(){ ctr++; //a separate declaration of ctr in the C style is not required }
#includepp
One special feature of our preprocessor is that preprocessor directives may be included in text resource files.
This is widely used in libraries. For example, the STG library relies on settings.xtxt, which is a definition file carrying the list of settings with their names, types, etc.
You typically work with this file through a convenient configurator. If you were to look at the contents of the underlying text file you would see that there are several #define directives in that file.
To make TIDE recognize these directives you need to include that text resource file into your compilation process using the includepp directive.
includepp "settings.xtxt" 'define an arrays with the number of elements equal to the #define made in a 'text resource file dim arr(STG_MAX_NUM_SETTINGS) as byte
#includepp "settings.xtxt" //define an arrays with the number of elements equal to the #define made in a //text resource file unsigned char arr[STG_MAX_NUM_SETTINGS];
...
#define STG_MAX_NUM_SETTINGS 40
#message
Prints a message into the Output pane (don't forget to put "" around the message string).
... #if COLOR=RED #message "The color is RED" #elif COLOR=GREEN #message "The color is GREEN" #else #message "The color is BLUE" #endif
... #if COLOR==RED #message "The color is RED" #elif COLOR==GREEN #message "The color is GREEN" #else #message "The color is BLUE" #endif
The example compiler output (abridged) for the above would be:
Compiling main.tbs...
(prj)\main.tbs(4): message: The color is BLUE
Linking...
Build complete.
#error
Prints a message into the Output pane and aborts the compilation (don't forget to put "" around the message string).
... #if COLOR=RED #message "The color is RED" #elif COLOR=GREEN #message "The color is GREEN" #elif COLOR=BLUE #message "The color is BLUE" #else #error "Unsupported color. Compilation aborted." #endif
... #if COLOR==RED #message "The color is RED" #elif COLOR==GREEN #message "The color is GREEN" #elif COLOR==BLUE #message "The color is BLUE" #else #error "Unsupported color. Compilation aborted." #endif
The example compiler output (abridged) for the above would be:
Compiling c.tc...
(prj)\c.tc(142): #error: Unsupported color. Compilation aborted.
#pragma pack (C Only)
Possible values are #pragma pack (1), (2), or (4).
Specifying #pragma pack (2) leads to 16-bit alignment in structures and unions (zero-byte padding is used to achieve proper alignment).
Using #pragma pack (4) will lead to 32-bit alignment.
The same construct doesn't exist in Tibbo BASIC, because it uses "safe" structures featuring special headers. "Packing" wouldn't make any sense for such "safe" structures.
The Tibbo C default is (1); i.e., no padding of any kind.
struct test_unpacked{ unsigned char x; //occupies one byte unsigned long l; //occupies four bytes }; #pragma pack (4) //this will affect all definitions below struct test_packed{ //this structure will be with padding unsigned char x; //occupies one byte unsigned long l; //occupies four bytes }; test_unpacked tu; test_packed tp; void on_sys_timer(){ sys.debugprint(str(sizeof(tu))+", "); //Will print "5" (unsigned char + unsigned long need 5 bytes) sys.debugprint(str(sizeof(tp))); //Will print "8" because 3 padding bytes will be added after the unsigned char }
With #pragma pack (4), and assuming that tp.x=0x12 and tp.l=0x3456789A, the memory structure holding the tp variable will look like this (notice three padding zero bytes):
0x12 |
0x00 |
0x00 |
0x00 |
0x9A |
0x78 |
0x56 |
0x34 |
#pragma message (C Only)
Exists for compatibility with other C implementations; the same is achieved with the #message directive.