Positron Compiler Documentation

Preprocessor Directives

Source: Positron16 Compiler User Manual, PDF page 463

To define preprocessor macros the directive $define is used. Its format is:-

$define identifier replacement

When the preprocessor encounters this directive, it replaces any occurrence of identifier in the rest of the code by replacement. This replacement can be an expression, a statement, a block, or simply anything. The preprocessor does not understand BASIC, it simply replaces any occurrence of identifier by replacement.

$define TableSize 100
Dim Table1[TableSize] as Byte
Dim Table2[TableSize] as Byte

After the preprocessor has replaced TableSize, the code becomes equivalent to:-

Dim Table1[100] as Byte
Dim Table2[100] as Byte

The use of $define as a constant definer is only one aspect of the preprocessor, and $define can also work with parameters to define pseudo function macros. The syntax then is:-

$define identifier (parameter list) replacement

A simple example of a function-like macro is:-

$define RadToDeg(x) ((x) * 57.29578)

This defines a radians to degrees conversion which can be used as:-

Var1 = RadToDeg(34)

This is expanded in-place, so the caller does not need to clutter copies of the multiplication constant throughout the code.

Precedence

Note that the example macro RadToDeg(x) given above uses normally unnecessary parentheses both around the argument and around the entire expression. Omitting either of these can lead to unexpected results. For example:-

Macro defined as:

$define RadToDeg(x) (x * 57.29578)

will expand

RadToDeg(a + b)

to

(a + b * 57.29578)

Macro defined as

$define RadToDeg(x) (x) * 57.29578

will expand

1 / RadToDeg(a)

to

1 / (a) * 57.29578

neither of which give the intended result.

Not all replacement tokens can be passed back to an assignment using the equals operator. If this is the case, the code needs to be similar to BASIC Stamp syntax, where the assignment variable is the last parameter:-

$define GetMax(x,y,z) If x > y Then z = x : Else : z = y

This would replace any occurrence of GetMax followed by three parameter (argument) by the replacement expression, but also replacing each parameter by its identifier, exactly as would be expected of a function.

Dim Var1 as Byte
Dim Var2 as Byte
Dim Var3 as Byte
Var1 = 100
Var2 = 99
GetMax(Var1, Var2, Var3)

The previous would be placed within the BASIC program as:-

Dim Var1 as Byte
Dim Var2 as Byte
Dim Var3 as Byte
Var1 = 100
Var2 = 99
If Var1 > Var2 Then Var3 = Var1 : Else : Var3 = Var2

Notice that the third parameter “Var3” is loaded with the result.

A macro lasts until it is undefined with the $undef preprocessor directive:-

$define TableSize 100
Dim Table1[TableSize] as Byte
$undef TableSize
$define TableSize 200
Dim Table2[TableSize] as Byte

This would generate the same code as:-

Dim Table1[100] as Byte
Dim Table2[200] as Byte

Because preprocessor replacements happen before any BASIC syntax check, macro definitions can be a tricky feature, so be careful. Code that relies heavily on complicated macros may be difficult to understand, since the syntax they expect is, on many occasions, different from the regular expressions programmers expect in Positron16 BASIC.

Preprocessor directives only extend across a single line of code. As soon as a newline character is found (end of line), the preprocessor directive is considered to end. The only way a preprocessor directive can extend through more than one line is by preceding the newline character at the end of the line by a comment character (‘) followed by a new line. No comment text can follow the comment character. For example:-

$define GetMax(x,y,z) '
   If x > y Then
                      '
     z = x
                      '
   Else
                      '
     z = y
                      '
   EndIf
GetMax(Var1, Var2, Var3)

The compiler will see:-

If Var1 > Var2 Then
  Var3 = Var1
Else
  Var3 = Var2
EndIf

Note that parenthesis is always required around the $define declaration and its use within the program. If the replacement argument is not included within the $define directive, the identifier argument will output nothing. However, it can be used as an identifier for conditional code:-

$define DoThis
$ifdef DoThis
  {Rest of Code here}
$endif

$undef identifier This removes any existing definition of the user macro identifier.

$eval expression In normal operation, the $define directive simply replaces text, however, using the $eval directive allows constant value expressions to be evaluated before replacement within the BASIC code. For example:-

$define Expression(Prm1) $eval (Prm1 << 1)

The above will evaluate the constant parameter Prm1, shifting it left one position.

Var1 = Expression(1)

Will be added to the BASIC code as:-

Var1 = 2

Because 1 shifted left one position is 2.

Several operands are available for use with an expression. These are +, -, *, -, ~, <<, >>, =, >, <, >=, <=, <>, And, Or, Xor.