millfork

Millfork: a middle-level programming language targeting 6502- and Z80-based microcomputers and home consoles

This project is maintained by KarolS

< back to index

Preprocessor

The Millfork preprocessor does 2 things:

Despite its similarity to the C preprocessor, it’s much more restricted in its power:

Preprocessor directives by default start with #. To avoid conflicts with C preprocessor (for users wishing to use it), it is also possible to replace # with $$.

Defining feature values

Feature values are defined in the [define] section of the platform definition file.
Each value is a signed 64-bit integer number.

Example:

[define]
WIDESCREEN=1

You can also define feature values using the -D command line option.

Built-in features

The following features are defined based on the chosen CPU and compilation options:

Commonly used features

These features are frequently defined in the platform definition file. Some libraries may require that some of these be defined.

Target-specific features

These features are used to identify the target machine in multiplatform programs and libraries:

Built-in preprocessor functions and operators

The same function returns 1 if given identical identifiers and 0 otherwise. It is the only function that does not support any other kind of parameters, and it’s only useful in module templates.

// prints 1:
#infoeval same(a,a)
// prints 0:
#infoeval same(a,b)
// fails to compile
#infoeval same(a,1)

The defined function returns 1 if the feature is defined, 0 otherwise.
All the other functions and operators treat undefined features as if they were defined as 0.

The if function returns its second parameter if the first parameter is defined and non-zero, and the third parameter otherwise:

// prints 400:
#infoeval if(1, 400, 500)
// prints 500:
#infoeval if(0, 400, 500)

The min and max functions return the smallest or largest parameter respectively. They support any number of arguments:

// prints 400:
#infoeval min(400, 500, 600)
// prints 500:
#infoeval max(400, 500)

The following Millfork operators and functions are also available in the preprocessor:
not, lo, hi, +, -, *, |, &, ^, ||, &&, <<, >>,==, !=, >, >=, <, <=

The following Millfork operators and functions are not available in the preprocessor:
$+, $-, $*, $<<, $>>, :, >>>>, nonet, all the assignment operators

Character literals

Preprocessor supports character literals. By default, they are interpreted in the default encoding, but you can suffix them with other encodings.

// usually prints 97:
#infoeval 'a'
// prints 97:
#infoeval 'a'ascii

Exceptionally, you can suffix the character literal with utf32. This gives the literal the value of the Unicode codepoint of the character:

// may print 94, 96, 112, 173, 176, 184, 185, 222, 227, 234, 240, something else, or even fail to compile:
#infoeval 'π'
// prints 960:
#infoeval 'π'utf32

Escape sequences are supported, as per encoding. utf32 pseudoencoding supports the same escape sequences as utf8.

#template

Defines the source to be a module template. See Modules for more information.

#if/#elseif/#else/#endif

#if <expr>
#elseif <expr>
#else
#endif

TODO

#fatal/#error/#warn/#info

#fatal fatal error message
#error error message
#warn warning message
#info informational message

Emits a diagnostic message.

#fatal interrupts the compilation immediately.
#error causes an error, but the compilation will continue.
#warn emits a warning. It may be treated as an error depending on compilation options.
#info emits a benign diagnostic message.

#infoeval

#infoeval <expr>

Evaluates an expression and emits the result as a diagnostic message.

#define

#define <ident> = <expr>

Defines a new feature value or redefines a previous feature value.

The feature value is visible only to the preprocessor, only when processing the current file, and only in lines preprocessed after this one.

#use

#use <ident> = <expr>

#use <feature>
// equivalent to #use <feature> = <feature>

Exports a value to the parser. The parser will substitute every use of the given identifier as a variable or constant with the numeric value of the feature.

#use CPU_MODEL = if(CPU_65816 | ARCH_X86, 16, 8)
putstrz("Your CPU is "z)
putword(CPU_MODEL)
putstrz("-bit."z)

The substitution will happen only within the current file. To use such value in other files, consider using a normal constant:

#use WIDESCREEN
const byte is_widescreen = WIDESCREEN

#pragma

Changes the behaviour of the parser for the current file. The change applies to the whole file, regardless of where the directive is located.