Preprocessor

The preprocessor is used to perform certain translation operations on the source program, such as replacing text, conditionally compiling areas of code, or including macros, definitions, or access to a pre-compiled library within a program.

Text Replacement Macro (#define/#undef)

The #define preprocessor directive is used to define a macro, which associates some value with an identifier. The syntax variations for a #define directive are as follows.

#define <Identifier>
#define <Identifier><Value>
#define <Identifier1>(<Identifer2>, ...)

#define <Identifier1>(<Identifer2>, ...) <Value>

The <Identifier*> arguments must be valid identifiers (see Valid Identifier Format). Macros have two general purposes:

  • They allow text to be substituted in a program before the program is compiled.

  • They allow an identifier to be defined, which can be used to perform conditional compilation based on the existence of that identifier.

// Define a macro without a token string
#define DEBUG_ENABLE
 

// Define a macro with some replacement text

#define MY_ADD(x, y) (x + y)
 

// Define some macros with replacement strings

#define MY_STRING "Hello"

#define MY_VALUE  2
 

// The following is replaced with var $myStr as string = "Hello"

var
$myStr as string = MY_STRING 
#ifdef DEBUG_ENABLE
   // This code compiles because DEBUG_ENABLE has been #defined
   Enable([X, Y])
#endif
 

// The following is replaced with $rglobal[0] = (1 + 2)

$rglobal
[0] = MY_ADD(1, MY_VALUE)

The #define preprocessor directive cannot be used to replace text within string literals.

// Define a macro with a token string
#define MY_VALUE 3

// Text replacement occurs and $myInt is assigned a value of 3
var
$myInt as integer = MY_VALUE
// No text replacement occurs, so $myStr is assigned "MY_VALUE"
var
$myStr as string = "MY_VALUE"

The #undef preprocessor directive can be used to undo a definition that was previously defined with the #define preprocessor directive. The syntax of an #undef preprocessor directive is as follows.

#undef <Identifier>

Similar to the #define preprocessor directive, the <Identifier> argument must be a valid identifier (see Valid Identifier Format).

#define DEBUG_MODE
#undef DEBUG_MODE 


#ifdef DEBUG_MODE
   // This code is not compiled because DEBUG_MODE is no longer #defined
   Enable(X)
#endif

The backslash character (\) can be used to allow a #define preprocessor directive macro to span multiple lines.

#define M300 \
Enable
(X) \
Home
(X) \
AnalogOutputSet
(X, 0, 0.0

// The following will be replaced with all 3 lines specified in the

// above #define macro

M300

Source File Inclusion (#include)

The #include preprocessor directive is used to directly include the text from another source file into the program in the line directly following the directive. This can be used, for example, to include another program that contains #defines. Only preprocessor directives and comments can be specified in a file that you include with the #include preprocessor directive.

// defines.ascript
#define VAL1 123.4

#define VAL2 0xFF
// main.ascript
#include"defines.ascript"

$rglobal[0] = VAL1
$rglobal
[2] = VAL2

Conditional Inclusion (#if/#ifdef/#ifndef)

Various preprocessor directives exist to perform conditional compilation of a source program:

  • #if
  • #ifdef
  • #ifndef

The #if directive is used to conditionally compile an area of code when a condition evaluates as true (non-zero). The syntax for the #if directive is as follows.

#if<Condition>
   <Code>
#endif

The <Condition> expression can contain any of the following:

  • Integer constants (e.g., 3 or 0xFF)

  • A subset of operators from the language

    • Arithmetic operators (e.g., +, -, *, /)

    • Bitwise operators (e.g., &, |, ~, <<, >>)

    • Comparison/relational operators (e.g., >, <, >=, <=)

    • Logical operators (e.g., ||, &&)

  • Macros created with the #define preprocessor directive

  • The defined preprocessor operator, which returns 1 if a macro has previously been defined with #define, or 0 if it has not been defined

#if (5 > 3)
   // This block will be included
#endif
#if 0
   // This block will not be included
#endif

The #elif and #else directives can be used within an #if block. These directives allow code to be conditionally included when the #if conditional is not true or non-zero. Refer to the following example.

#define DEBUG_LEVEL 2

#if !defined(DEBUG_LEVEL)
   // This block will not be included (DEBUG_LEVEL is defined)
#elif DEBUG_LEVEL == 1

   // This block will not be included (DEBUG_LEVEL is not 1)
#else
   // This block will be included (the other conditions were false)
#endif

The #ifdef preprocessor directive is used to conditionally compile an area of code when a macro has been previously defined with the #define directive. Similarly, the #ifndef directive is used to perform conditional compilation when a macro has not been previously defined. The syntax for these two directives is as follows.

#ifdef<Name>
   <Code>
#endif
#ifndef<Name>
   <Code>
#endif

Similar to the #if preprocessor directive, the #elif and #else preprocessor directives can be used within #ifdef and #ifndef blocks.

#define DEBUG_MODE
#define LOG_MODE   3


#ifndef DEBUG_MODE
   // This block will not be included (DEBUG_MODE is defined)
#elif (LOG_MODE > 0)

   // This block will be included (LOG_MODE is 3)
#else

   // This block will not be included (the previous block was included)
#endif

Next Topic: Data Types and Variables