2019-07-15 14:21:50 +02:00
[< back to index ](../doc_index.md )
2018-04-03 00:21:26 +02:00
2018-01-10 13:08:24 +01:00
# Operators
Unlike in high-level languages, operators in Millfork have limited applicability.
Not every well-formed expression is actually compilable.
2018-01-10 13:17:09 +01:00
Most expressions involving single bytes compile,
but for larger types usually you need to use in-place modification operators.
2018-01-10 13:08:24 +01:00
Further improvements to the compiler may increase the number of acceptable combinations.
2019-06-05 18:34:32 +02:00
On 6502-like targets, certain expressions require the commandline flag `-fzp-register` (`.ini` equivalent: `zeropage_register` ) to be enabled.
2018-03-05 12:05:37 +01:00
They will be marked with (zpreg) next to them.
2018-06-09 00:05:17 +02:00
The flag is enabled by default, but you can disable it if you need to.
2018-03-05 12:05:37 +01:00
2018-01-10 13:08:24 +01:00
## Precedence
Millfork has different operator precedence compared to most other languages. From highest to lowest it goes:
2019-04-18 17:20:35 +02:00
* `->` and `[]`
2020-07-24 17:28:04 +02:00
* `*` , `*'` , `/` , `%%`
2018-01-10 13:08:24 +01:00
2018-03-10 22:05:10 +01:00
* `+` , `+'` , `-` , `-'` , `|` , `&` , `^` , `>>` , `>>'` , `<<` , `<<'` , `>>>>`
2018-01-10 13:08:24 +01:00
* `:`
* `==` , `!=` , `<` , `>` , `<=` , `>=`
* `&&`
* `||`
* assignment and in-place modification operators
You cannot use two different operators at the same precedence levels without using parentheses to disambiguate.
It is to prevent confusion about whether `a + b & c << d` means `(a + b) & (c << d)` `((a + b) & c) << d` or something else.
The only exceptions are `+` and `-` , and `+'` and `-'` .
2018-01-31 22:26:20 +01:00
They are interpreted as expected: `5 - 3 + 2 == 4` and `5 -' 3 +' 2 == 4` .
2018-01-10 13:08:24 +01:00
Note that you cannot mix `+'` and `-'` with `+` and `-` .
2020-07-24 17:28:04 +02:00
Certain operators (`/` , `%%` , `<<` , `>>` , `<<'` , `>>'` , `>>>>` , `:` , `!=` ) cannot have more than 2 parameters,
i.e. `x / y / z` will not compile.
2020-08-14 02:22:13 +02:00
The decimal operators have two different forms:
* apostrophe form (e.g. `+'` ) – the original one, to be deprecated in the future, may be removed in Millfork 0.4
* dollar form (e.g. `$+` ) – available since Millfork 0.3.22
2018-01-10 13:08:24 +01:00
## Argument types
In the descriptions below, arguments to the operators are explained as follows:
2018-07-20 22:46:53 +02:00
* `enum` means any enumeration type
2018-01-10 13:08:24 +01:00
2018-07-20 22:46:53 +02:00
* `byte` means any numeric one-byte type
2018-01-10 13:08:24 +01:00
2019-06-06 13:06:30 +02:00
* `unsigned byte` means any numeric one-byte type that is not signed
2018-07-20 22:46:53 +02:00
* `word` means any numeric two-byte type, or a byte expanded to a word; `pointer` is considered to be numeric
* `long` means any numeric type longer than two bytes, or a shorter type expanded to such length to match the other argument
2018-01-10 13:08:24 +01:00
* `constant` means a compile-time constant
2020-01-12 20:53:11 +01:00
* `trivial` means either a constant or a non-stack variable
2018-01-10 13:08:24 +01:00
* `simple` means either: a constant, a non-stack variable,
a pointer indexed with a constant, a pointer indexed with a non-stack variable,
an array indexed with a constant, an array indexed with a non-stack variable,
an array indexed with a sum of a constant and a non-stack variable,
or a split-word expression made of two simple expressions.
Examples: `1` , `a` , `p[2]` , `p[i]` , `arr[2]` , `arr[i]` , `arr[i+2]` , `h:l` , `h[i]:l[i]`
Such expressions have the property that the only register they may clobber is Y.
2018-03-09 00:07:21 +01:00
* `mutable` means an expression that can be assigned to
2018-01-10 13:08:24 +01:00
2018-01-18 22:35:25 +01:00
## Split-word operator
Expressions of the shape `h:l` where `h` and `l` are of type byte, are considered expressions of type word.
If and only if both `h` and `l` are assignable expressions, then `h:l` is also an assignable expression.
2019-04-15 19:45:26 +02:00
## Indirect field access operator
`->`
TODO
2018-01-10 13:08:24 +01:00
## Binary arithmetic operators
2020-12-01 14:26:47 +01:00
* `+` , `-` : addition and subtraction
2018-01-10 13:08:24 +01:00
`byte + byte`
2018-01-10 13:17:09 +01:00
`constant word + constant word`
2018-03-10 21:33:13 +01:00
`constant long + constant long`
2018-03-18 23:54:02 +01:00
`constant word + byte`
2018-03-10 21:33:13 +01:00
`word + word` (zpreg)
2018-01-10 13:08:24 +01:00
2021-02-18 00:51:07 +01:00
* `*` : multiplication (signed or unsigned); the size of the result is the same as the size of the largest of the arguments
2018-01-10 13:08:24 +01:00
`byte * constant byte`
2018-01-10 13:17:09 +01:00
`constant byte * byte`
`constant word * constant word`
2018-03-05 12:05:37 +01:00
`constant long * constant long`
2018-12-19 01:09:27 +01:00
`byte * byte` (zpreg)
`word * byte` (zpreg)
`byte * word` (zpreg)
2019-09-04 21:17:06 +02:00
`word * word` (zpreg)
2018-01-10 13:08:24 +01:00
2019-06-06 13:06:30 +02:00
* `/` , `%%` : unsigned division and unsigned modulo
`unsigned byte / unsigned byte` (zpreg)
`word / unsigned byte` (zpreg)
2019-09-15 19:47:19 +02:00
`word / word` (zpreg)
2019-06-05 18:36:39 +02:00
`constant word / constant word`
2019-06-06 13:06:30 +02:00
`constant long / constant long`
2018-01-10 13:08:24 +01:00
## Bitwise operators
* `|` , `^` , `&` : OR, EXOR and AND
2018-01-10 13:17:09 +01:00
`byte | byte`
`constant word | constant word`
2018-03-10 21:33:13 +01:00
`constant long | constant long`
`word | word` (zpreg)
2018-01-10 13:08:24 +01:00
2018-01-10 13:17:09 +01:00
* `<<` , `>>` : bit shifting; shifting pads the result with zeroes
2018-03-11 23:02:34 +01:00
`byte << byte`
`word << byte` (zpreg)
2018-01-10 13:17:09 +01:00
`constant word << constant byte`
`constant long << constant byte`
2018-01-10 13:08:24 +01:00
2018-03-10 22:05:10 +01:00
* `>>>>` : shifting a 9-bit value and returning a byte; `a >>>> b` is equivalent to `(a & $1FF) >> b`
`word >>>> constant byte`
2018-02-01 22:39:38 +01:00
2018-01-10 13:08:24 +01:00
## Decimal arithmetic operators
2018-08-01 18:49:37 +02:00
These operators work using the decimal arithmetic (packed BCD).
2018-08-03 13:06:23 +02:00
On Ricoh-based targets (e.g. Famicom) they require the zeropage register to have size at least 4
2018-01-10 13:08:24 +01:00
* `+'` , `-'` : decimal addition/subtraction
2020-12-01 14:26:47 +01:00
`$+` , `$-` : (since Millfork 0.3.22)
2018-01-10 13:08:24 +01:00
`byte +' byte`
2018-01-10 13:17:09 +01:00
`constant word +' constant word`
2018-03-10 21:33:13 +01:00
`constant long +' constant long`
`word +' word` (zpreg)
2018-01-10 13:08:24 +01:00
* `*'` : decimal multiplication
2020-12-01 14:26:47 +01:00
`$*` : (since Millfork 0.3.22)
2018-01-10 13:08:24 +01:00
`constant *' constant`
* `<<'` , `>>'` : decimal multiplication/division by power of two
2020-12-01 14:26:47 +01:00
`$<<` , `$>>` : (since Millfork 0.3.22)
2018-01-10 13:09:38 +01:00
`byte <<' constant byte`
2018-01-10 13:08:24 +01:00
## Comparison operators
These operators (except for `!=` ) can accept more than 2 arguments.
In such case, the result is true if each comparison in the group is true.
Note you cannot mix those operators, so `a <= b < c` is not valid.
2018-06-09 00:05:17 +02:00
**WARNING:** Currently in cases like `a < f() < b` , `f()` may be evaluated an undefined number of times
(the current implementation calls it twice, but do not rely on this behaviour).
2018-01-18 22:35:25 +01:00
2019-10-24 15:09:11 +02:00
The `==` and `!=` operators also work for non-arithmetic types.
2018-01-10 13:08:24 +01:00
* `==` : equality
2018-07-20 22:46:53 +02:00
`enum == enum`
2018-01-10 13:08:24 +01:00
`byte == byte`
2018-03-16 13:19:54 +01:00
`simple word == simple word`
2019-04-15 19:45:26 +02:00
`word == constant`
2019-10-24 15:09:11 +02:00
`simple word == word` (zpreg)
`word == simple word` (zpreg)
2018-03-16 13:19:54 +01:00
`simple long == simple long`
2018-01-10 13:08:24 +01:00
* `!=` : inequality
2018-07-20 22:46:53 +02:00
`enum != enum`
2018-01-10 13:09:38 +01:00
`byte != byte`
2018-03-16 13:19:54 +01:00
`simple word != simple word`
2019-04-15 19:45:26 +02:00
`word != constant`
2019-10-24 15:09:11 +02:00
`simple word != word` (zpreg)
`word != simple word` (zpreg)
2018-03-16 13:19:54 +01:00
`simple long != simple long`
2018-01-10 13:08:24 +01:00
* `>` , `<` , `<=` , `>=` : inequality
`byte > byte`
2019-10-24 15:09:11 +02:00
`simple word > simple word`
`simple word > word` (zpreg)
`word > simple word` (zpreg)
2018-03-16 13:19:54 +01:00
`simple long > simple long`
2018-01-10 13:08:24 +01:00
2018-08-03 16:21:02 +02:00
Currently, `>` , `<` , `<=` , `>=` operators perform signed comparison
if any of the types of their arguments is signed,
and unsigned comparison otherwise.
2018-01-10 13:17:09 +01:00
## Assignment and in-place modification operators
2018-01-10 13:08:24 +01:00
2018-06-09 00:05:17 +02:00
**WARNING:** Unlike other languages, Millfork does not provide any guarantees about how many times the left hand side will be evaluated.
An expression of form `a[f()] += b` may call `f` an undefined number of times.
2018-01-10 13:08:24 +01:00
* `=` : normal assignment
2018-07-20 22:46:53 +02:00
`mutable enum = enum`
2018-01-10 13:08:24 +01:00
`mutable byte = byte`
2019-04-18 17:20:35 +02:00
`mutable word = word`
2018-01-10 13:08:24 +01:00
`mutable long = long`
* `+=` , `+'=` , `|=` , `^=` , `&=` : modification in place
2020-08-14 02:22:13 +02:00
`$+=` (since Millfork 0.3.22)
2018-01-10 13:08:24 +01:00
`mutable byte += byte`
`mutable word += word`
2020-01-12 20:53:11 +01:00
`mutable trivial long += long`
2018-01-10 13:08:24 +01:00
2018-03-11 23:02:34 +01:00
* `<<=` , `>>=` : shift in place
`mutable byte <<= byte`
`mutable word <<= byte`
2020-01-12 20:53:11 +01:00
`mutable trivial long <<= byte`
2018-03-11 23:02:34 +01:00
* `<<'=` , `>>'=` : decimal shift in place
2020-08-14 02:22:13 +02:00
`$<<=` , `$>>=` (since Millfork 0.3.22)
2018-07-23 15:47:03 +02:00
`mutable byte <<'= constant byte`
`mutable word <<'= constant byte`
2020-01-12 20:53:11 +01:00
`mutable trivial long <<'= constant byte`
2018-01-10 13:08:24 +01:00
* `-=` , `-'=` : subtraction in place
2020-08-14 02:22:13 +02:00
`$-=` (since Millfork 0.3.22)
2018-01-10 13:08:24 +01:00
`mutable byte -= byte`
`mutable word -= simple word`
2020-01-12 20:53:11 +01:00
`mutable trivial long -= simple long`
2018-01-10 13:08:24 +01:00
* `*=` : multiplication in place
2018-03-06 16:59:18 +01:00
`mutable byte *= constant byte`
2019-06-06 13:06:30 +02:00
`mutable byte *= byte` (zpreg)
2018-12-14 22:50:20 +01:00
`mutable word *= unsigned byte` (zpreg)
2019-09-04 21:17:06 +02:00
`mutable word *= word` (zpreg)
2018-01-10 13:08:24 +01:00
2018-01-31 22:26:20 +01:00
* `*'=` : decimal multiplication in place
2020-08-14 02:22:13 +02:00
`$*=` (since Millfork 0.3.22)
2018-01-31 22:26:20 +01:00
`mutable byte *'= constant byte`
2018-01-10 13:17:09 +01:00
2019-06-06 13:06:30 +02:00
* `/=` , `%%=` : unsigned division and modulo in place
`mutable unsigned byte /= unsigned byte` (zpreg)
`mutable word /= unsigned byte` (zpreg)
2019-09-15 19:47:19 +02:00
`mutable word /= word` (zpreg)
2019-06-06 13:06:30 +02:00
2019-07-26 18:56:24 +02:00
There are no `||=` , `&&=` or `>>>>=` operators.
2018-01-18 22:35:25 +01:00
## Indexing
While Millfork does not consider indexing an operator, this is a place as good as any to discuss it.
An expression of form `a[i]` , where `i` is an expression of type `byte` , is:
2019-04-18 17:20:35 +02:00
* when `a` is an array that has numeric index type and `T` value type:
an access to the `i` -th element of the array `a`
* when `a` is a raw pointer variable:
an access to the byte in memory at address `a + i`
* when `a` is a typed pointer variable to a 1-byte type `T` :
an access to the value pointed to by `a`
2018-01-18 22:35:25 +01:00
2019-04-18 17:20:35 +02:00
* when `a` is a typed pointer variable to a 2-byte type `T` and `i` is zero:
an access to the value pointed to by `a`
2018-01-18 22:35:25 +01:00
2019-04-18 17:20:35 +02:00
* otherwise: a compile error
2018-01-18 22:35:25 +01:00
2019-04-18 17:20:35 +02:00
On 8080-like targets, and on 6502 if the zeropage register is enabled, `i` can also be of type `word` .
2018-07-20 22:46:53 +02:00
An expression of form `a[i]` , where `i` is an expression of a enumeration type, is:
* when `a` is an array that has index type equal to the type of `i` :
an access to the element of the array `a` at the location assigned to the key `i`
* otherwise: a compile error
2018-06-09 00:05:17 +02:00
2019-08-05 14:07:33 +02:00
Note that you cannot access a whole array element if it's bigger than 2 bytes (except in a simple assignment),
but you can access its fields or take its pointer:
2019-07-10 16:51:12 +02:00
array(int32) a[6]
a[2] // not ok
2019-08-05 14:07:33 +02:00
a[2] = 4 // ok, assignments are an exception
x = a[2] // ok, assignments are an exception
2019-07-10 16:51:12 +02:00
a[2].b0 // ok
a[2].loword // ok
a[2].pointer // ok
2019-07-24 00:14:27 +02:00
a[2].addr // ok
a[2].b0.addr // ok, equal to the above on little-endian targets
2019-07-10 16:51:12 +02:00
2018-03-10 22:05:10 +01:00
## Built-in functions
* `not` : negation of a boolean expression
`not(bool)`
* `nonet` : expansion of an 8-bit operation to a 9-bit operation
`nonet(byte + byte)`
`nonet(byte +' byte)`
`nonet(byte << constant byte)`
`nonet(byte <<' constant byte)`
Other kinds of expressions than the above (even `nonet(byte + byte + byte)` ) will not work as expected.
2018-04-03 00:21:26 +02:00
* `hi` , `lo` : most/least significant byte of a word
2019-07-27 00:58:10 +02:00
`hi(word)`
2018-08-08 23:14:09 +02:00
Furthermore, any type that can be assigned to a variable can be used to convert
either from one type either to another type of the same size,
2019-07-27 00:58:10 +02:00
or from a 1-byte integer type to a compatible 2-byte integer type.
2018-08-08 23:14:09 +02:00
`byte` → `word`
`word` → `pointer`
some enum → `byte`
`byte` → some enum
but not
`word` → `byte`
some enum → `word`
2018-04-03 00:21:26 +02:00
2018-12-16 15:43:17 +01:00
* `sizeof` : size of the argument in bytes; the argument can be an expression or a type,
2020-10-05 22:20:08 +02:00
and the result is a constant of either `byte` or `word` type, depending on the actual value.
In case of aligned types, this returns the aligned size.
2018-04-03 00:21:26 +02:00
2021-02-18 00:51:07 +01:00
* `typeof` : a word constant that identifies the type of the argument; the argument can be an expression or a type.
The argument is never evaluated.
**Warnings:**
* **This is a highly experimental feature.**
* The exact values may change in any future version of the compiler. Only compare one `typeof` to another `typeof` .
* There is no guarantee that different types will have different values of `typeof` . Indeed, it's even easy to see that a Millfork program can have more than 65536 types – and values of `typeof` can clash even before that.
* In certain circumstances, pointer types and function pointer types may have different `typeof` values even if they're essentially the same.
2019-07-27 00:58:10 +02:00
* `call` : calls a function via a pointer;
the first argument is the pointer to the function;
the second argument, if present, is the argument to the called function.
2019-07-30 22:49:32 +02:00
The function can have max one parameter, of size max 2 bytes, and may return a value of size max 2 bytes.
2019-07-27 00:58:10 +02:00
You can't create typed pointers to other kinds of functions anyway.
If the pointed-to function returns a value, then the result of `call(...)` is the result of the function.
Using `call` on 6502 targets requires at least 4 bytes of zeropage pseudoregister.
2018-01-18 22:35:25 +01:00