V22 Macro Preprocessor

V22 introduces the full macro expansion engine. Macros are expanded before the lexer runs, so they can generate any PB code including declarations, statements, and expressions.

Object-Like Macros: #DEFINE

Syntax: #DEFINE name value

Simple text-replacement macros. Every occurrence of name in subsequent source is replaced with value.

#DEFINE MAX_COUNT 100
#DEFINE APP_NAME "MyApp"

LOCAL i AS LONG
FOR i = 1 TO MAX_COUNT
    PRINT APP_NAME
NEXT i
Duplicates: Redefining an existing #DEFINE symbol produces a diagnostic error.

Single-Line Function Macros

Syntax: MACRO name(args) = expression

Expression macros that expand inline with argument substitution.

MACRO Add1(x) = (x + 1)
MACRO Square(n) = (n * n)
MACRO Max(a, b) = IIF((a) > (b), (a), (b))

LOCAL v AS LONG
v = Add1(10)       ' Expands to: v = (10 + 1)
v = Square(v)      ' Expands to: v = (v * v)

Multi-Line Statement Macros

Syntax: MACRO name(args) ... END MACRO

Block macros that expand to multiple statements. Arguments are substituted by name.

MACRO SAY(text)
    PRINT text
END MACRO

MACRO SwapVars(a, b)
    LOCAL t AS LONG
    t = a
    a = b
    b = t
END MACRO

FUNCTION PBMAIN() AS LONG
    LOCAL x, y AS LONG
    x = 10 : y = 20
    SwapVars(x, y)
    SAY("Hello from macro!")
END FUNCTION

MACROFUNCTION with MACROTEMP

Syntax: MACROFUNCTION name(args) ... END MACRO = expr

Function-like macros that can declare temporary variables with MACROTEMP. MACROTEMP generates a unique name for each expansion, preventing collisions.

MACROFUNCTION Twice(x)
    MACROTEMP t
    LOCAL t AS LONG
    t = x * 2
END MACRO = t

FUNCTION PBMAIN() AS LONG
    LOCAL a, b AS LONG
    a = Twice(5)     ' a = 10, uses unique temporary
    b = Twice(a)     ' b = 20, uses different unique temporary
END FUNCTION
Known limit: MACROFUNCTION does not yet implement every PowerBASIC macro edge case. Basic expression macros with MACROTEMP work well for common patterns.

Recursive Macro Protection

The preprocessor detects and rejects recursive macro invocations and excessive expansion depth (default limit: 256 levels).

' This produces a diagnostic error, not infinite expansion
' #DEFINE X Y
' #DEFINE Y X
' PRINT X    ' Error: recursive macro expansion

#INCLUDE ONCE and #INCLUDEONCE

Syntax: #INCLUDE ONCE "file.inc" or #INCLUDEONCE "file.inc"

Prevents duplicate inclusion of the same file. Useful for header files included from multiple locations. Missing-file diagnostics are emitted when the included file cannot be found.

#INCLUDE ONCE "win32api.inc"
#INCLUDEONCE "mytypes.pbi"

#COMPILE DLL and GUI Mode Rejection

V22 explicitly rejects unsupported compile modes with a clear diagnostic instead of silently producing a wrong EXE type:

' #COMPILE DLL "mylib.dll"      ' Error: DLL output not yet implemented
' #COMPILE EXE "app.exe" GUI     ' Error: GUI subsystem not yet implemented

Predefined V22 Symbol

V22 defines PBXA64_V22 as a conditional symbol, allowing version-gated code:

#IF %DEF(PBXA64_V22)
    PRINT "Running under PBXA64 V22 or later"
    ' Use V22 macro features
#ELSE
    PRINT "Older version - macros not available"
#ENDIF

#UNDEF

Syntax: #UNDEF name

Removes a previously defined conditional symbol or #DEFINE macro.

#DEFINE DEBUG 1
' ... debug code here ...
#UNDEF DEBUG
' Debug code no longer active

Diagnostics

ErrorCause
Duplicate #DEFINESymbol already defined with a value
Recursive macro expansionMacro expansion led to itself
Expansion depth exceededToo many nested macro invocations
Missing END MACROMACRO block not closed
MACROFUNCTION arity mismatchWrong number of arguments provided
#INCLUDE ONCE file not foundIncluded file does not exist
DLL/GUI mode not supported#COMPILE target not yet implemented