The $DEFINE preprocessor directive is translated to the
C keyword #define.
👉 In the C code translation of $DEFINE, the #define is
placed before the #include references. If
the #define is needed to be placed after the
#include references, then the BCX MACRO directive must be used instead of $DEFINE.
Syntax:$DEFINE ConstantName Value |
Except for its placement in the C translation, $DEFINE is functionally equivalent to the MACRO directive.
$DEFINE NTDDI_VERSION 0x0A000007 PRINT "NTDDI_VERSION : " , HEX$(NTDDI_VERSION ) PRINT "WINVER : " , HEX$(WINVER) PRINT "_WIN32_WINNT : " , HEX$(_WIN32_WINNT) PRINT "_WIN32_IE : " , HEX$(_WIN32_IE)
On a Windows 11 x64 machine, the above code, compiled with MSVC, Pelles C, Nuwen, LLVM, and LLVM-MinGW, when run, prints
NTDDI_VERSION : A000007 WINVER : A00 _WIN32_WINNT : A00 _WIN32_IE : A00
MACRO is a preprocessor directive which defines an identifier with a string argument. The BCX MACRO keyword is translated to the C keyword #define. In the C code translation, a #define is placed after the #include references. If it is needed for the #define to be placed before the #include references, then the BCX $DEFINE directive must be used instead of MACRO.
MACRO replaces CONST.
👉 The CONST
directive keyword has been deprecated and replaced with the BCX
keyword MACRO.
Syntax 1:MACRO ConstantName = Value |
👉 Do not append any sigil, (% ! # $), to the ConstantName or to any variable on the right hand side of the MACRO directive.
MACRO ConstantName% = Value%
is invalid and will not compile.
👉 If a MACRO value
is used in an $IF, $ELSEIF, or $ELSE directive,
it must evaluate as an integer. If a MACRO is
defined, but is not given a value, attempting to compile the code
will cause a compilation error, as is the case, in the following
example.
$BCXVERSION "7.4.0" MACRO NOVALUE $IF NOVALUE PRINT "This will end your dreams" $ENDIF
Pelles C compiler throws this error
error #1019: Syntax error in #if/#elif expression.
Microsoft (R) C/C++ Optimizing Compiler Version 19.26.28806 for x86 throws this error
fatal error C1017: invalid integer constant expression
Syntax 2:MACRO MacroName = (MacroExpression) |
👉 The macro and the variable names in macro definitions must be parenthesized.
This example shows the correct parenthesization of a MACRO.
DIM A, B MACRO CubeAnInteger(C) = ((C) * (C) * (C)) A = 3 B = 1984 / CubeAnInteger(A + 1) PRINT " Correct parenthesization ! = ", B
Correct parenthesization ! = 31
This example shows an incorrect parenthesization of a MACRO.
If the parentheses surrounding the right hand expression are omitted, the result will be different from Example 1:, for example,
DIM A, B MACRO CubeAnInteger(C) = (C) * (C) * (C) A = 3 B = 1984 / CubeAnInteger(A + 1) PRINT "Incorrect parenthesization ! = ", B
Incorrect parenthesization ! = 7936
This example shows an incorrect parenthesization of a MACRO.
And if the parentheses surrounding variable names are omitted, the result again will be different from Example 1:, for example,
DIM A, B MACRO CubeAnInteger(C) = (C * C * C) A = 3 B = 1984 / CubeAnInteger(A + 1) PRINT "Incorrect parenthesization ! = ", B
Incorrect parenthesization ! = 198
This example shows an incorrect parenthesization of a MACRO.
And again if the parentheses surrounding both the macro and variable names are omitted, the result yet again will be different from Example 1:, for example,
DIM A, B MACRO CubeAnInteger(C) = C * C * C A = 3 B = 1984 / CubeAnInteger(A + 1) PRINT "Incorrect parenthesization ! = ", B
Incorrect parenthesization ! = 668
Here is an example of using MACRO to create a function-like macro.
MACRO ShowWin(Window) = RedrawWindow(Window,0,0,0),ShowWindow(Window,SW_SHOW) MACRO HideWin(Window) = RedrawWindow(Window,0,0,0),ShowWindow(Window,0) PRINT "About to HIDE the console Window for 2 seconds" DELAY 2 HideWin(CONWIN) DELAY 2 ShowWin(CONWIN) PAUSE
Here is another example of MACRO used to create a function-like macro.
MACRO RunEx(lpFile, _ lpParameters, _ nShowCmd) = _ ShellExecute(0, _ "open", _ lpFile, _ lpParameters, _ 0, _ nShowCmd)
To use the above macro you must link with SHELL32.LIB. The following shows how RunEx would be called in the application.
RunEx("notepad.exe", "xxx.txt", 1)
Syntax 3:MACRO ConstName = Expression |
Here is a way to use MACRO to embed NULL in a string.
$IPRINT_OFF MACRO Filter = "Icons(*.ico)\0*.ICO\0All files(*.*)\0*.*" $IPRINT_ON
If you have a C code snippet that should look like:
void* F_CALLBACKAPI WaveformCB(void *originalbuffer, void *newbuffer, int length, int param)
it can be translated to BCX like this:
MACRO pF_Callback = (Void*)F_CALLBACKAPI FUNCTION WaveformCB (originalbuffer AS void PTR, _ newbuffer AS void PTR, _ length AS INTEGER, _ param AS INTEGER) AS pF_Callback
To provide conditional compilation, these five preprocessor directives check whether a controlling conditional expression evaluates to zero or nonzero, and excludes or includes a block of code respectively.
$BCXVERSION "7.4.0" MACRO FOO = 1 MACRO BAR = 0 $IFDEF FOO PRINT "FOO is defined." $ENDIF $IF FOO PRINT "FOO has a value of ", FOO $ENDIF $IFDEF BAR PRINT "BAR is defined." $ENDIF $IF BAR PRINT "BAR has 0 value so this will not print" $ENDIF ' Note that the "==" equality operator must be used ' when performing a comparison. $IF BAR == 0 PRINT "BAR has a value of ", BAR $ENDIF $IF FOO == 1 PRINT "FOO has a value of ", FOO $ENDIF $IF FOO == 5 PRINT "FOO does not have a value of 5 so this will not print", FOO $ENDIF $IF FOO OR BAR PRINT "FOO has a value of ", FOO PRINT "BAR has a value of ", BAR $ENDIF
FOO is defined. FOO has a value of 1 BAR is defined. BAR has a value of 0 FOO has a value of 1 FOO has a value of 1 BAR has a value of 0
This BCX code
MACRO FooBar DIM A $IFNDEF FooBar A = 1 $ELSE A = 2 $ENDIF PRINT A
translates to the following C code, showing that the conditional directives are local in scope located in the main function.
// ************************************************* // User Defined Constants // ************************************************* #define FooBar // ************************************************* // User Global Variables // ************************************************* static int A; // ************************************************* // Main Program // ************************************************* int main(int argc, char *argv[]) { #ifndef FooBar A= 1; #else A= 2; #endif // Main printf("% d\n",(int)A); return 0; /* End of main program */ }👉 Conditional directives cannot encase any of the following:
👉 Any conditional directives will be local in scope to any FUNCTION or SUB procedure including the main function.
👉 If you want global preprocessor conditionals, placed at the top of the file scope level code, executing before anything else, then C style preprocessor code in $HEADER directives must be used as shown below.
$HEADER #define FooBar #ifndef FooBar #define A 1 #else #define A 2 #endif $HEADER PRINT A
A rudimentary ability to conditionally compile BCX code using
$IFDEF ... $ENDIF has been
enabled.
👉 $IF, $IFNDEF, $ELSE, $ELSEIF, are not supported for this purpose.
The following are example directives and declarators allowed inside SUB and FUNCTION procedures within $IFDEF ... $ENDIF blocks.
$INCLUDE "a.bas" DIM APPLES AS INT LOCAL oranges AS LONG DIM RAW bananas AS INT DIM STATIC spooky AS STRING CONST FOO = 1 MACRO BAR = 2
A GLOBAL variable cannot be created but a GLOBAL variable can be referenced.
Here is a working example:
MACRO USE_NewFoo1 MACRO USE_NewFoo2 CALL TestingX1("TestingX1") CALL TestingX5("TestingX5") PAUSE $IFDEF USE_NewFoo1 SUB TestingX1 (x$) PRINT x$ END SUB FUNCTION TestingX2 (x$) PRINT x$ FUNCTION = 1 END FUNCTION SUB TestingX3 (x$) PRINT x$ END SUB FUNCTION TestingX4 (x$) PRINT x$ FUNCTION = 1 END FUNCTION $ENDIF $IFDEF USE_NewFoo2 SUB TestingX5 (x$) PRINT x$ END SUB FUNCTION TestingX6 (x$) PRINT x$ FUNCTION = 1 END FUNCTION SUB TestingX7 (x$) PRINT x$ END SUB FUNCTION TestingX8 (x$) PRINT x$ FUNCTION = 1 END FUNCTION $ENDIF
TestingX1 TestingX5 Press any key to continue . . .
As an example, suppose you wanted all the messages in your program to be in a particular language, you could use something like the following sample. There would be only one set of language statements in the final .exe
'*********************************************************************** ' Conditional compilation using: $IFDEF/$ELSE/$ELSEIF/$ENDIF directives '*********************************************************************** ' By uncommenting one of the following CONST statements, the resulting ' executable code changes as well. Only the code that is associated ' with the true condition is compiled, the rest is disregarded. '******************************************************************* 'CONST ENGLISH 'CONST SPANISH 'CONST GERMAN $IFDEF ENGLISH PRINT "Good Day" PRINT "What's happening?" $ELSEIF SPANISH PRINT "Buenas Dias" PRINT "Como va?" $ELSEIF GERMAN PRINT "Guten Tag" PRINT "Was ist los?" $ELSE PRINT "Greetings Earthling" PRINT "Where is the cafeteria?" $ENDIF
Greetings Earthling Where is the cafeteria?
$BCXVERSION "7.5.7" MACRO APPLES = 1 MACRO ORANGES = 2 $IF APPLES OR ORANGES '<<-- OR is always Boolean in any IF/ $IF statement PRINT "$IF should translate to (||) and yield 3:", %APPLES OR ORANGES '<<-- otherwise, OR is bitwise $ENDIF $IF APPLES ORELSE ORANGES '<<-- ORELSE is ALWAYS Boolean PRINT "$IF should translate to (||) and yield 1:", %APPLES ORELSE ORANGES ' <<-- ORELSE is ALWAYS Boolean $ENDIF $IF APPLES BOR ORANGES '<<-- This is explicitly bitwise PRINT "$IF should translate to (|) and yield 3:", %APPLES BOR ORANGES '<<-- This is explicitly bitwise $ENDIF
$IF should translate to (||) and yield 3: 3 $IF should translate to (||) and yield 1: 1 $IF should translate to (|) and yield 3: 3