7.5 KiB
Operators
Unlike in high-level languages, operators in Millfork have limited applicability.
Not every well-formed expression is actually compilable.
Most expressions involving single bytes compile,
but for larger types usually you need to use in-place modification operators.
Further improvements to the compiler may increase the number of acceptable combinations.
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 to.
Work in progress: Certain expressions may not work on non-6502 targets yet. This should improve in the future.
Precedence
Millfork has different operator precedence compared to most other languages. From highest to lowest it goes:
-
*,*' -
+,+',-,-',|,&,^,>>,>>',<<,<<',>>>> -
: -
==,!=,<,>,<=,>= -
&& -
|| -
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 -'.
They are interpreted as expected: 5 - 3 + 2 == 4 and 5 -' 3 +' 2 == 4.
Note that you cannot mix +' and -' with + and -.
Argument types
In the descriptions below, arguments to the operators are explained as follows:
-
enummeans any enumeration type -
bytemeans any numeric one-byte type -
wordmeans any numeric two-byte type, or a byte expanded to a word;pointeris considered to be numeric -
longmeans any numeric type longer than two bytes, or a shorter type expanded to such length to match the other argument -
constantmeans a compile-time constant -
simplemeans 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. -
mutablemeans an expression that can be assigned to
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.
Binary arithmetic operators
-
+,-:
byte + byte
constant word + constant word
constant long + constant long
constant word + byte
word + word(zpreg) -
*: multiplication; the size of the result is the same as the size of the arguments
byte * constant byte
constant byte * byte
constant word * constant word
constant long * constant long
byte * byte(zpreg)
There are no division, remainder or modulo operators.
Bitwise operators
-
|,^,&: OR, EXOR and AND
byte | byte
constant word | constant word
constant long | constant long
word | word(zpreg) -
<<,>>: bit shifting; shifting pads the result with zeroes
byte << byte
word << byte(zpreg)
constant word << constant byte
constant long << constant byte -
>>>>: shifting a 9-bit value and returning a byte;a >>>> bis equivalent to(a & $1FF) >> b
word >>>> constant byte
Decimal arithmetic operators
These operators work using the decimal arithmetic and will not work on Ricoh CPU's. The compiler issues a warning if these operators appear in the code.
-
+',-': decimal addition/subtraction
byte +' byte
constant word +' constant word
constant long +' constant long
word +' word(zpreg) -
*': decimal multiplication
constant *' constant -
<<',>>': decimal multiplication/division by power of two
byte <<' constant byte
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.
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).
-
==: equality
enum == enum
byte == byte
simple word == simple word
simple long == simple long -
!=: inequality
enum != enum
byte != byte
simple word != simple word
simple long != simple long -
>,<,<=,>=: inequality
byte > byte
simple word > simple word
simple long > simple 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.
Assignment and in-place modification operators
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.
-
=: normal assignment
mutable enum = enum
mutable byte = byte
mutable word = wordmutable long = long -
+=,+'=,|=,^=,&=: modification in place
mutable byte += byte
mutable word += word
mutable long += long -
<<=,>>=: shift in place
mutable byte <<= byte
mutable word <<= byte
mutable long <<= byte -
<<'=,>>'=: decimal 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
mutable byte *= constant byte
mutable byte *= byte(zpreg) -
*'=: decimal multiplication in place
mutable byte *'= constant byte
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
ais an array that has numeric index type: an access to thei-th element of the arraya -
when
ais a pointer variable: an access to the byte in memory at addressa + i
Those expressions are of type byte. If a is any other kind of expression, a[i] is invalid.
If the zeropage register is enabled, i can also be of type word.
An expression of form a[i], where i is an expression of a enumeration type, is:
-
when
ais an array that has index type equal to the type ofi: an access to the element of the arrayaat the location assigned to the keyi -
otherwise: a compile error
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 (evennonet(byte + byte + byte)) will not work as expected. -
hi,lo: most/least significant byte of a word
hi(word)
Furthermore, any type that can be assigned to a variable can be used to convert from one type to another of the same size.