Preprocessor
A number of preprocessor directives can be used within redcode. These directives affect how the parser turns the source redcode into the load file.
Note these preprocessor directives are used a parse time and are not output directly into the parsed output itself.
EQU
The EQU
directive allows constants
to be defined, which can then be referred to through out your code. This works in a similar way to labels. The difference is that you explicitly specify the value of these constants
rather than being implicitly set based on where they are declared within the redcode.
The syntax for the EQU
directive is as follows
name EQU value
Constant names follow the same naming rules as labels (see labels for details).
The value can be either a number, a label, one of the special constants or even a mathematical expression combining a mixture of these values.
Literal Number Constant
Here is an example of using EQU
to set a constant within the classic dwarf
:
step EQU 3044
ORG top
bmb: dat #step #step
top: add.ab bmb, bmb
mov bmb, @bmb
jmp top
The parsed output will look like this:
ORG 1
DAT.F #3044, #3044
ADD.AB $-1, $-1
MOV.I $-2, @-2
JMP.B $-2, $0
Notice that all references to step
have been replaced with the value of step
i.e. 3044
.
Label Constant
You can also use a label
when declaring a constant
using the EQU
directive. When you do this, the parser first replaces all references to the constant within code with the label
that the constant
is equal to. After this substitution has been made, labels are replaced with their relative addresses in the normal way, see labels for details.
mybmb EQU bmb
ORG top
bmb: dat #step #step
top: add.ab mybmb, mybmb
mov mybmb, @mybmb
jmp top
Notice here that mybmb
and bmb
are equivalent.
Mathematical Expressions
Mathematical expressions can also be used within redcode. These are evaluated at parse time and replaced by the numeric result.
These expressions can be placed in any operand within your code or at the value of a EQU directive.
Mathematical expressions can use the following operators: * + addition * - subtraction * * multiplication * / division * % modulo
Multiplication and division operatiors have precendence (are evaluated first) over addition and subtraction.
5+2*3
For example, the above will be evaluated as 2*3=6, therefore 5+6 = 11.
Brackets (
and )
can be used to control the order that the expression is evaluated.
add (4/2-1)*5, 1
The A
operand in the above example will be evaluated to 5
so the parsed output will be:
ADD.AB $5, $1
The following example uses a mathematical expression to set the value of a constant
:
myconst EQU (1+2)/2
This will be evaluated as:
myconst EQU 1
Note that when using division, the result is always rounded towards zero.
It is also possible to use labels within mathematical expressions as follows:
bmb dat 5, 5
dat 0, 0
mov bmb, bmb+1
This example will be parsed to:
DAT.F #5, #5
DAT.F #0, #0
MOV.I $-2, $-1
The label bmb
is replaced with -2
since its address is two lower than the mov
instruction. The B
operand of the mov
instruction is bmb+1
which is therefore effectively -2+1
, hence the parsed output for the B
number of the mov
instruction is -1
.
Special constants
NOTE this feature is not yet implemented within corewar.io
A number of preprocessor constants are defined in redcode. These constants are resolved during parsing and replaced with their numeric equivalent.
Constant | Description |
---|---|
CORESIZE | The size of the core |
MAXCYCLES | The number of cycles which will be executed before a draw is declared |
MAXPROCESSES | The maxmimum number of processes each warrior can have (see Processes) |
WARRIORS | The number of warriors which have been loaded into the Core |
MAXLENGTH | The maximum length (number of instructions) a warrior can have |
CURLINE | The absolute position (beginning at zero) of this line within the warrior's source code |
MINDISTANCE | The closest that two warriors can be placed when loaded into core |
VERSION | The version of the simulator used |
PSPACESIZE | The size of P-space - see P-Space |
Assert
NOTE this feature is not yet implemented within corewar.io
When writing your warrior you may have a specific environment in mind. For example you may only want to deploy your warrior to a Core of size 8000. In order to make this clear and to prevent your warrior being loaded into a Core of the wrong size you can use the assert
directive as shown in the following example:
;assert CORESIZE==8000
The above snippet will prevent your warrior from being parsed and loaded into a core of any size other than 8000.
The following C like operators can be used within an assert
directive to build a logical condition:
Operator | Meaning |
---|---|
+ | Addition |
- | Subtraction |
* | Multiplication |
/ | Division |
% | Modulo |
== | Equal |
!= | Not equal |
< | Less than |
<= | Less than or equal |
> | Greater than |
>= | Greater than or equal |
&& | Boolean and |
|| | Boolean or |
! | Boolean not |
FOR
NOTE this feature is only partially implemented within corewar.io - FOR loops can be used but nested FOR loops and label references are not yet supported
FOR
blocks cause the redcode contained within to be output by the parser multiple times. This saves the author from manually duplicating a line of code and is useful for introducing padding within your warrior's source code.
The FOR
block is used as shown in the following example:
FOR 10
dat.f $1, $2
ROF
In this example, FOR
begins the FOR
block. The number 10
indicates that the contents of the FOR
block should be repeated ten times. Next the instruction to be duplicated is included. Finally, the FOR
block is terminated using the ROF
keyword.
The above redcode will be parsed to produce the following output:
dat.f $1, $2
dat.f $1, $2
dat.f $1, $2
dat.f $1, $2
dat.f $1, $2
dat.f $1, $2
dat.f $1, $2
dat.f $1, $2
dat.f $1, $2
dat.f $1, $2
A label can be declared in front of the FOR block. Referencing the label within the FOR block will result in a different number being emitted for each sucessive instruction as the parser outputs the contents of the FOR block and each instruction gets further away from the label declaration. This is demonstrated below:
label FOR 4
dat.f $1+label, $1-label
ROF
This will be parsed to produce:
dat.f $1, $1
dat.f $0, $2
dat.f $-1, $3
dat.f $-2, $4
It is also possible to nest FOR
blocks within each other as follows:
FOR 2
FOR 3
dat.f $1, $2
ROF
ROF
Becomes
dat.f $1, $2
dat.f $1, $2
dat.f $1, $2
dat.f $1, $2
dat.f $1, $2
dat.f $1, $2
Finally, the &
operator can be used within a FOR
loop to add the loop counter to a label declaration as demonstrated in the following example:
i FOR 3
loop&i dat.f $1, $1
ROF
Becomes
loop01 dat.f $1, $1
loop02 dat.f $1, $1
loop03 dat.f $1, $1