2018-01-10 12:08:24 +00:00
|
|
|
# Operators
|
|
|
|
|
|
|
|
Unlike in high-level languages, operators in Millfork have limited applicability.
|
|
|
|
Not every well-formed expression is actually compilable.
|
2018-01-10 12:17:09 +00:00
|
|
|
Most expressions involving single bytes compile,
|
|
|
|
but for larger types usually you need to use in-place modification operators.
|
2018-01-10 12:08:24 +00:00
|
|
|
Further improvements to the compiler may increase the number of acceptable combinations.
|
|
|
|
|
2018-03-05 11:05:37 +00:00
|
|
|
Certain expressions require the commandline flag `-fzp-register` (`.ini` equivalent: `zeropage_register`) to be enabled.
|
|
|
|
They will be marked with (zpreg) next to them.
|
|
|
|
The flag is enabled by default, but you can disable it if you need it.
|
|
|
|
|
2018-01-10 12:08:24 +00:00
|
|
|
## Precedence
|
|
|
|
|
|
|
|
Millfork has different operator precedence compared to most other languages. From highest to lowest it goes:
|
|
|
|
|
|
|
|
* `*`, `*'`
|
|
|
|
|
2018-03-10 21:05:10 +00:00
|
|
|
* `+`, `+'`, `-`, `-'`, `|`, `&`, `^`, `>>`, `>>'`, `<<`, `<<'`, `>>>>`
|
2018-01-10 12:08:24 +00: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 21:26:20 +00:00
|
|
|
They are interpreted as expected: `5 - 3 + 2 == 4` and `5 -' 3 +' 2 == 4`.
|
2018-01-10 12:08:24 +00:00
|
|
|
Note that you cannot mix `+'` and `-'` with `+` and `-`.
|
|
|
|
|
|
|
|
## Argument types
|
|
|
|
|
|
|
|
In the descriptions below, arguments to the operators are explained as follows:
|
|
|
|
|
|
|
|
* `byte` means any one-byte type
|
|
|
|
|
|
|
|
* `word` means any two-byte type, or a byte expanded to a word
|
|
|
|
|
2018-03-10 21:05:10 +00:00
|
|
|
* `long` means any type longer than two bytes, or a shorter type expanded to such length to match the other argument
|
2018-01-10 12:08:24 +00:00
|
|
|
|
|
|
|
* `constant` means a compile-time constant
|
|
|
|
|
|
|
|
* `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-08 23:07:21 +00:00
|
|
|
* `mutable` means an expression that can be assigned to
|
2018-01-10 12:08:24 +00:00
|
|
|
|
2018-01-18 21:35:25 +00: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.
|
|
|
|
|
2018-01-10 12:08:24 +00:00
|
|
|
## Binary arithmetic operators
|
|
|
|
|
|
|
|
* `+`, `-`:
|
|
|
|
`byte + byte`
|
2018-01-10 12:17:09 +00:00
|
|
|
`constant word + constant word`
|
2018-03-10 20:33:13 +00:00
|
|
|
`constant long + constant long`
|
|
|
|
`word + word` (zpreg)
|
2018-01-10 12:08:24 +00:00
|
|
|
|
2018-01-10 12:17:09 +00:00
|
|
|
* `*`: multiplication; the size of the result is the same as the size of the arguments
|
2018-01-10 12:08:24 +00:00
|
|
|
`byte * constant byte`
|
2018-01-10 12:17:09 +00:00
|
|
|
`constant byte * byte`
|
|
|
|
`constant word * constant word`
|
2018-03-05 11:05:37 +00:00
|
|
|
`constant long * constant long`
|
|
|
|
`byte * byte` (zpreg)
|
2018-01-10 12:08:24 +00:00
|
|
|
|
|
|
|
There are no division, remainder or modulo operators.
|
|
|
|
|
|
|
|
## Bitwise operators
|
|
|
|
|
|
|
|
* `|`, `^`, `&`: OR, EXOR and AND
|
2018-01-10 12:17:09 +00:00
|
|
|
`byte | byte`
|
|
|
|
`constant word | constant word`
|
2018-03-10 20:33:13 +00:00
|
|
|
`constant long | constant long`
|
|
|
|
`word | word` (zpreg)
|
2018-01-10 12:08:24 +00:00
|
|
|
|
2018-01-10 12:17:09 +00:00
|
|
|
* `<<`, `>>`: bit shifting; shifting pads the result with zeroes
|
|
|
|
`byte << constant byte`
|
2018-03-05 11:05:37 +00:00
|
|
|
`word << constant byte` (zpreg)
|
2018-01-10 12:17:09 +00:00
|
|
|
`constant word << constant byte`
|
|
|
|
`constant long << constant byte`
|
2018-01-10 12:08:24 +00:00
|
|
|
|
2018-03-10 21:05:10 +00:00
|
|
|
* `>>>>`: shifting a 9-bit value and returning a byte; `a >>>> b` is equivalent to `(a & $1FF) >> b`
|
|
|
|
`word >>>> constant byte`
|
2018-02-01 21:39:38 +00:00
|
|
|
|
2018-01-10 12:08:24 +00:00
|
|
|
## Decimal arithmetic operators
|
|
|
|
|
|
|
|
These operators work using the decimal arithmetic and will not work on Ricoh CPU's.
|
|
|
|
|
|
|
|
* `+'`, `-'`: decimal addition/subtraction
|
|
|
|
`byte +' byte`
|
2018-01-10 12:17:09 +00:00
|
|
|
`constant word +' constant word`
|
2018-03-10 20:33:13 +00:00
|
|
|
`constant long +' constant long`
|
|
|
|
`word +' word` (zpreg)
|
2018-01-10 12:08:24 +00:00
|
|
|
|
|
|
|
* `*'`: decimal multiplication
|
|
|
|
`constant *' constant`
|
|
|
|
|
|
|
|
* `<<'`, `>>'`: decimal multiplication/division by power of two
|
2018-01-10 12:09:38 +00:00
|
|
|
`byte <<' constant byte`
|
2018-01-10 12:08:24 +00: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-01-18 21:35:25 +00:00
|
|
|
Note that currently in cases like `a < f() < b`, `f()` will be evaluated twice!
|
|
|
|
|
2018-01-10 12:08:24 +00:00
|
|
|
* `==`: equality
|
|
|
|
`byte == byte`
|
|
|
|
`word == word`
|
|
|
|
`long == long`
|
|
|
|
|
|
|
|
* `!=`: inequality
|
2018-01-10 12:09:38 +00:00
|
|
|
`byte != byte`
|
|
|
|
`word != word`
|
|
|
|
`long != long`
|
2018-01-10 12:08:24 +00:00
|
|
|
|
|
|
|
* `>`, `<`, `<=`, `>=`: inequality
|
|
|
|
`byte > byte`
|
|
|
|
`word > word`
|
|
|
|
`long > long`
|
|
|
|
|
|
|
|
Currently, `>`, `<`, `<=`, `>=` operators perform unsigned comparison
|
|
|
|
if none of the types of their arguments is signed,
|
|
|
|
and fail to compile otherwise. This will be changed in the future.
|
|
|
|
|
2018-01-10 12:17:09 +00:00
|
|
|
## Assignment and in-place modification operators
|
2018-01-10 12:08:24 +00:00
|
|
|
|
|
|
|
* `=`: normal assignment
|
|
|
|
`mutable byte = byte`
|
|
|
|
`mutable word = word`
|
|
|
|
`mutable long = long`
|
|
|
|
|
|
|
|
* `+=`, `+'=`, `|=`, `^=`, `&=`: modification in place
|
|
|
|
`mutable byte += byte`
|
|
|
|
`mutable word += word`
|
|
|
|
`mutable long += long`
|
|
|
|
|
|
|
|
* `<<=`, `>>=`, `<<'=`, `>>'=`: shift in place
|
|
|
|
`mutable byte <<= constant byte`
|
|
|
|
`mutable word <<= constant byte`
|
|
|
|
`mutable long <<= constant byte`
|
|
|
|
|
|
|
|
* `-=`, `-'=`: subtraction in place
|
|
|
|
`mutable byte -= byte`
|
|
|
|
`mutable word -= simple word`
|
|
|
|
`mutable long -= simple long`
|
|
|
|
|
|
|
|
* `*=`: multiplication in place
|
2018-03-06 15:59:18 +00:00
|
|
|
`mutable byte *= constant byte`
|
|
|
|
`mutable byte *= byte` (zpreg)
|
2018-01-10 12:08:24 +00:00
|
|
|
|
2018-01-31 21:26:20 +00:00
|
|
|
* `*'=`: decimal multiplication in place
|
|
|
|
`mutable byte *'= constant byte`
|
2018-01-10 12:17:09 +00:00
|
|
|
|
2018-01-18 21:35:25 +00: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:
|
|
|
|
|
|
|
|
* when `a` is an array: an access to the `i`-th element of the array `a`
|
|
|
|
|
|
|
|
* when `a` is a pointer variable: an access to the byte in memory at address `a + i`
|
|
|
|
|
2018-01-31 21:26:20 +00:00
|
|
|
Those expressions are of type `byte`. If `a` is any other kind of expression, `a[i]` is invalid.
|
2018-01-18 21:35:25 +00:00
|
|
|
|
2018-03-10 21:05:10 +00: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-01-18 21:35:25 +00:00
|
|
|
|