Conditional compilation

Language reference ›› Directives ››
Parent Previous Next

PMP allows conditional compilation by means of conditional directives.

Conditional directives are special directives that change the compiler code generation. The PMP's syntax is a standard TP / Delphi syntax, with some improvements:


Note: in the following syntax declaration the encapsulating directives braces {} or (* *) are omitted.


conditional-directive = conditional-define | conditional-simple-block | conditional-expression-block.
conditional-define = define-item | undefine-item .
define-item =( $DEF | $DEFINE ) conditional-identifier [ [ "=" ] conditional-value ] .
conditional-value = string-literal | integer-expression .
undefine-item = ( $UNDEF | $UNDEFINE ) conditional-identifier.
conditional-simple-block = ( ifdef-item | ifndef-item | ifopt-item ) block [ $ELSE block ] conditional-block-end .
ifdef-item = $IFDEF ( conditional-identifier | conditional-string ) .
ifndef-item = $IFNDEF ( conditional-identifier | conditional-string )  .
conditional-string = constant-literal-string .
ifopt-item = ( $IFOPT | $IFNOPT ) directive-item .
directive-item = directive-name [ [ "=" ] directive-value ] .
conditional-block-end = ( $ENDIF | $IFEND ) .
conditional-expression-block = $IF constant-expression { conditional-alternative block } conditional-block-end ) .
conditional-alternative = $ELSE | (( $ELSEIF | $ELSIF ) constant-expression ) .


$DEFINE <conditional-identifier>:

A conditional identifier is not a Pascal identifier and cannot be referenced in real program code except by the DEFINED() pseudo-function. Likewise, Pascal identifiers cannot be referenced as a <conditional-identifier>.

A conditional identifier may have a conditional value. These values may be either a string literal or an integer constant value.

A conditional identifier is assumed to be defined until an $UNDEF directive.

A global conditional identifier (that has been passed from the project or from the main program) cannot be redefined or undefined locally.

NEW! (V2.1): If present the value may follow an optional "=" sign.


<constant-expression>:

Standard constant expression which may use some special built-in functions capabilities: DEFINED(<conditional-identifier>) and DECLARED(<identifier>).

It is evaluated as a boolean expression.


<conditional-value>:

This value is evaluated at the time where the $DEFINE is encountered and MUST be evaluable at this point, giving a constant result, numeric or alphanumeric; then the value is asserted to the symbol.

The value may be retrieved further by the DEFINED_VALUE(<conditional-identifier>) pseudo-function. As defined symbols are passed from the project to the program and from the program to the units, they may be used to pass environment values that may parametrize the used units.




{$DEFINE SERIAL_DEBUG}
{$DEFINE SERIAL_PORT 'PORTA'} // Note that using unquoted values would imply evaluation of an expression as a numeric value!
{$DEFINE SERIAL_PIN 3}
{$DEFINE ITERATIONS (FREQUENCY DIV 1000)}
...
VAR
 The_Bit: boolean @ DEFINED_VALUE(SERIAL_PORT).DEFINED_VALUE(SERIAL_PIN);


<conditional-string>:

This form accepts a quoted string which may contain ‘?’ and ‘*’ wild-cards to match more than one symbol.



{$IFDEF 'PIC16*14??'} // Compile if the processor is an ENHANCED mid-range with a 4-digits P/N index starting with "14".
 
{$ENDIF}


Conditional blocks:

If a $IFxxx conditional block expression is true, the next code compiles until a $ELSE, $ENDIF or $IFEND
conditional directive.

With a $ELSE directive, if all the previous $IF, $ELSEIF, $IFDEF or $IFNDEF conditional directives had been evaluated to FALSE, the next code compiles until a $ENDIF or $IFEND conditional directive.

A $ENDIF or $IFEND terminates $IFDEF, $IFNDEF or $IF conditional directive blocks ($IFEND and $ENDIF are true synonyms).

Also $ELSIF and $ELSEIF are true synonyms in PMP, as well as $IFEND and $ENDIF. $IFEND is now obsolete in Delphi and is no more related to $IF blocks only; $ENDIF may terminate any $IFxxx block.


$IFOPT | $IFNOPT <directive-item>:

Any directive that sets a compiler option may be checked to be true with the $IFOPT directive or checked to be false with the $IFNOPT directive, by including its name followed or not by an optional value (ON is assumed for simple toggle directives). See an example below.

NEW! (V2.1): If present the value may follow an optional "=" sign.



{$IFOPT POINTERS=LARGE} // Compile if pointers are defined to be large.
 
{$ENDIF}
{$IFOPT WARNING 2-} // Compile if warning 2 is OFF.
 
{$ENDIF}
{$IFNOPT BOOLEVAL} // Compile if complete boolean evaluation is OFF.
 
{$ENDIF}


defined-function = DEFINED "(" conditional-identifier | conditional-string ")" .


The special built-in function DEFINED can be used in conditional expressions ($IF and $ELSEIF directives) as well as in any expression in normal code.

It returns TRUE if <conditional-identifier> is known as a defined conditional symbol at this point (formally equivalent to the IFDEF directive). The second form accepts a string literal with ‘?’ and ‘*’ wild-card characters to match more than one symbol.



{$IF DEFINED(BOOT) and DEFINED('PIC16*')}
 
{$ENDIF}


defined-value-function = DEFINED_VALUE "(" conditional-identifier ")" .


The special built-in function DEFINED_VALUE can be used to retrieve the value assigned in the last $DEFINE of <conditional-identifier>. If there's no value a compilation error occurs.



{$DEFINE BAUD_RATE 9600}
 …
CONST
 Bit_Delay_us = 1_000_000 DIV Defined_Value(BAUD_RATE); // Value is 1000000 div 9600


declared-function = DECLARED "(" identifier ")" .


The special built-in function DECLARED can be used in conditional expressions as well as in any expression in normal code. It returns TRUE if <identifier> is a Pascal identifier (constant, type, variable, function or procedure name) that has been declared at this point.



{$IF DECLARED(MyVar) or DECLARED(TMR0H)}
 
{$ENDIF}