1
0
mirror of https://github.com/KarolS/millfork.git synced 2024-12-22 16:31:02 +00:00

Officially deprecate old decimal operators

This commit is contained in:
Karol Stasiak 2021-05-23 22:31:11 +02:00
parent ca35367974
commit 4f6eefab79
6 changed files with 74 additions and 52 deletions

View File

@ -18,9 +18,9 @@ Millfork has different operator precedence compared to most other languages. Fro
* `->` and `[]` * `->` and `[]`
* `*`, `*'`, `/`, `%%` * `*`, `$*`, `/`, `%%`
* `+`, `+'`, `-`, `-'`, `|`, `&`, `^`, `>>`, `>>'`, `<<`, `<<'`, `>>>>` * `+`, `$+`, `-`, `$-`, `|`, `&`, `^`, `>>`, `$>>`, `<<`, `$<<`, `>>>>`
* `:` * `:`
@ -34,16 +34,16 @@ Millfork has different operator precedence compared to most other languages. Fro
You cannot use two different operators at the same precedence levels without using parentheses to disambiguate. 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. 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 `-'`. The only exceptions are `+` and `-`, and `$+` and `$-`.
They are interpreted as expected: `5 - 3 + 2 == 4` and `5 -' 3 +' 2 == 4`. They are interpreted as expected: `5 - 3 + 2 == 4` and `5 $- 3 $+ 2 == 4`.
Note that you cannot mix `+'` and `-'` with `+` and `-`. Note that you cannot mix `$+` and `$-` with `+` and `-`.
Certain operators (`/`, `%%`, `<<`, `>>`, `<<'`, `>>'`, `>>>>`, `:`, `!=`) cannot have more than 2 parameters, Certain operators (`/`, `%%`, `<<`, `>>`, `$<<`, `$>>`, `>>>>`, `:`, `!=`) cannot have more than 2 parameters,
i.e. `x / y / z` will not compile. i.e. `x / y / z` will not compile.
The decimal operators have two different forms: 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 * apostrophe form (e.g. `+'`) the original one, deprecated, will be removed in Millfork 0.4
* dollar form (e.g. `$+`) available since Millfork 0.3.22 * dollar form (e.g. `$+`) available since Millfork 0.3.22
@ -135,20 +135,20 @@ These operators work using the decimal arithmetic (packed BCD).
On Ricoh-based targets (e.g. Famicom) they require the zeropage register to have size at least 4 On Ricoh-based targets (e.g. Famicom) they require the zeropage register to have size at least 4
* `+'`, `-'`: decimal addition/subtraction * `$+`, `$-`: decimal addition/subtraction
`$+`, `$-`: (since Millfork 0.3.22) `+'`, `-'`: (deprecated form)
`byte +' byte` `byte $+ byte`
`constant word +' constant word` `constant word $+ constant word`
`constant long +' constant long` `constant long $+ constant long`
`word +' word` (zpreg) `word $+ word` (zpreg)
* `*'`: decimal multiplication * `$*`: decimal multiplication
`$*`: (since Millfork 0.3.22) `*'`: (deprecated form)
`constant *' constant` `constant $* constant`
* `<<'`, `>>'`: decimal multiplication/division by power of two * `$<<`, `$>>`: decimal multiplication/division by power of two
`$<<`, `$>>`: (since Millfork 0.3.22) `<<'`, `>>'`: (deprecated form)
`byte <<' constant byte` `byte $<< constant byte`
## Comparison operators ## Comparison operators
@ -201,8 +201,8 @@ An expression of form `a[f()] += b` may call `f` an undefined number of times.
`mutable word = word` `mutable word = word`
`mutable long = long` `mutable long = long`
* `+=`, `+'=`, `|=`, `^=`, `&=`: modification in place * `+=`, `$+=`, `|=`, `^=`, `&=`: modification in place
`$+=` (since Millfork 0.3.22) `+'=` (deprecated form)
`mutable byte += byte` `mutable byte += byte`
`mutable word += word` `mutable word += word`
`mutable trivial long += long` `mutable trivial long += long`
@ -212,14 +212,14 @@ An expression of form `a[f()] += b` may call `f` an undefined number of times.
`mutable word <<= byte` `mutable word <<= byte`
`mutable trivial long <<= byte` `mutable trivial long <<= byte`
* `<<'=`, `>>'=`: decimal shift in place * `$<<=`, `$>>=`: decimal shift in place
`$<<=`, `$>>=` (since Millfork 0.3.22) `<<'=`, `>>'=` (deprecated form)
`mutable byte <<'= constant byte` `mutable byte $<<= constant byte`
`mutable word <<'= constant byte` `mutable word $<<= constant byte`
`mutable trivial long <<'= constant byte` `mutable trivial long $<<= constant byte`
* `-=`, `-'=`: subtraction in place * `-=`, `$-=`: subtraction in place
`$-=` (since Millfork 0.3.22) `-'=` (deprecated form)
`mutable byte -= byte` `mutable byte -= byte`
`mutable word -= simple word` `mutable word -= simple word`
`mutable trivial long -= simple long` `mutable trivial long -= simple long`
@ -230,9 +230,9 @@ An expression of form `a[f()] += b` may call `f` an undefined number of times.
`mutable word *= unsigned byte` (zpreg) `mutable word *= unsigned byte` (zpreg)
`mutable word *= word` (zpreg) `mutable word *= word` (zpreg)
* `*'=`: decimal multiplication in place * `$*=`: decimal multiplication in place
`$*=` (since Millfork 0.3.22) `*'=` (deprecated form)
`mutable byte *'= constant byte` `mutable byte $*= constant byte`
* `/=`, `%%=`: unsigned division and modulo in place * `/=`, `%%=`: unsigned division and modulo in place
`mutable unsigned byte /= unsigned byte` (zpreg) `mutable unsigned byte /= unsigned byte` (zpreg)
@ -291,9 +291,9 @@ but you can access its fields or take its pointer:
* `nonet`: expansion of an 8-bit operation to a 9-bit operation * `nonet`: expansion of an 8-bit operation to a 9-bit operation
`nonet(byte + byte)` `nonet(byte + byte)`
`nonet(byte +' byte)` `nonet(byte $+ byte)`
`nonet(byte << constant byte)` `nonet(byte << constant 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. Other kinds of expressions than the above (even `nonet(byte + byte + byte)`) will not work as expected.
* `hi`, `lo`: most/least significant byte of a word * `hi`, `lo`: most/least significant byte of a word

View File

@ -151,11 +151,18 @@ The `if` function returns its second parameter if the first parameter is defined
// prints 500: // prints 500:
#infoeval if(0, 400, 500) #infoeval if(0, 400, 500)
TODO The `min` and `max` functions return the smallest or largest parameter respectively. They support any number of arguments:
`not`, `lo`, `hi`, `min`, `max` `+`, `-`, `*`, `|`, `&`, `^`, `||`, `&&`, `<<`, `>>`,`==`, `!=`, `>`, `>=`, `<`, `<=`
// 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: The following Millfork operators and functions are not available in the preprocessor:
`+'`, `-'`, `*'`, `<<'`, `>>'`, `:`, `>>>>`, `nonet`, all the assignment operators `$+`, `$-`, `$*`, `$<<`, `$>>`, `:`, `>>>>`, `nonet`, all the assignment operators
### Character literals ### Character literals

View File

@ -456,11 +456,26 @@ abstract class MfParser[T](fileId: String, input: String, currentDirectory: Stri
mfParenExpr(allowIntelHex) | derefExpression | a mfParenExpr(allowIntelHex) | derefExpression | a
} }
def normalizeOperator(op: String, pos: Position): String = {
if (mfOperatorNormalizations.contains(op)) return mfOperatorNormalizations(op)
if (op.contains('\'')) {
if (options.flag(CompilationFlag.DeprecationWarning)) {
mfOperatorNormalizations.find(_._2.==(op)).map(_._1) match {
case None =>
log.warn(s"Operator $op is deprecated and will be removed in 0.4", Some(pos))
case Some(newOp) =>
log.warn(s"Operator $op is deprecated and will be removed in 0.4, since 0.3.22 you should use $newOp as a replacement", Some(pos))
}
}
}
op
}
def mfExpression(level: Int, allowIntelHex: Boolean, allowTopLevelIndexing: Boolean = true): P[Expression] = { def mfExpression(level: Int, allowIntelHex: Boolean, allowTopLevelIndexing: Boolean = true): P[Expression] = {
val allowedOperators = mfOperatorsDropFlatten(level) val allowedOperators = mfOperatorsDropFlatten(level)
def innerNowOperatorOrNothing: P[List[(String, (Boolean, Expression))]] = { def innerNowOperatorOrNothing: P[List[(String, (Boolean, Expression))]] = {
((StringIn(allowedOperators: _*).! ~ !CharIn(Seq('/', '=', '-', '+', ':', '>', '<', '\''))).map(op => if (mfOperatorNormalizations.contains(op)) mfOperatorNormalizations(op) else op) ~/ ((position() ~ StringIn(allowedOperators: _*).! ~ !CharIn(Seq('/', '=', '-', '+', ':', '>', '<', '\''))).map{ case (pos, op) => normalizeOperator(op, pos) } ~/
(AWS ~/ P(innerNowTerm) ~/ HWS)).?.map{ (AWS ~/ P(innerNowTerm) ~/ HWS)).?.map{
case None => Nil case None => Nil
case Some((op, rhs)) => rhs.toPairList(op) case Some((op, rhs)) => rhs.toPairList(op)

View File

@ -54,7 +54,7 @@ class ByteDecimalMathSuite extends FunSuite with Matchers with AppendedClues {
| run() | run()
| } | }
| void init() { output = $#i } | void init() { output = $#i }
| void run () { output +'= $#j } | void run () { output $+= $#j }
""".stripMargin.replace("#i", i.toString).replace("#j", j.toString)) { m => """.stripMargin.replace("#i", i.toString).replace("#j", j.toString)) { m =>
toDecimal(m.readByte(0xc000)) should equal((i + j) % 100) toDecimal(m.readByte(0xc000)) should equal((i + j) % 100)
} }
@ -68,7 +68,7 @@ class ByteDecimalMathSuite extends FunSuite with Matchers with AppendedClues {
| byte a | byte a
| void main () { | void main () {
| a = $50 | a = $50
| output = a -' $35 | output = a $- $35
| } | }
""".stripMargin)(_.readByte(0xc000) should equal(0x15)) """.stripMargin)(_.readByte(0xc000) should equal(0x15))
} }
@ -81,8 +81,8 @@ class ByteDecimalMathSuite extends FunSuite with Matchers with AppendedClues {
| void main () { | void main () {
| a = 1 | a = 1
| output[1] = 5 | output[1] = 5
| output[a] +'= 1 | output[a] $+= 1
| output[a] +'= $36 | output[a] $+= $36
| } | }
""".stripMargin)(_.readByte(0xc001) should equal(0x42)) """.stripMargin)(_.readByte(0xc001) should equal(0x42))
} }
@ -101,7 +101,7 @@ class ByteDecimalMathSuite extends FunSuite with Matchers with AppendedClues {
| x = tmpx | x = tmpx
| y = tmpy | y = tmpy
| output[y] = $39 | output[y] = $39
| output[x] +'= 1 | output[x] $+= 1
| } | }
| byte one() { return 1 } | byte one() { return 1 }
""".stripMargin)(_.readByte(0xc001) should equal(0x40)) """.stripMargin)(_.readByte(0xc001) should equal(0x40))
@ -124,7 +124,7 @@ class ByteDecimalMathSuite extends FunSuite with Matchers with AppendedClues {
""" """
| word output @$c000 | word output @$c000
| void main () { | void main () {
| output = f() +' g() | output = f() $+ g()
| } | }
| word f() { | word f() {
| return $253 | return $253
@ -187,7 +187,7 @@ class ByteDecimalMathSuite extends FunSuite with Matchers with AppendedClues {
| void main () { | void main () {
| output = addDecimal(9, 9) + addDecimal(9, 9) | output = addDecimal(9, 9) + addDecimal(9, 9)
| } | }
| byte addDecimal(byte a, byte b) { return a +' b } | byte addDecimal(byte a, byte b) { return a $+ b }
""".stripMargin)(_.readByte(0xc000) should equal(0x30)) """.stripMargin)(_.readByte(0xc000) should equal(0x30))
} }
@ -198,7 +198,7 @@ class ByteDecimalMathSuite extends FunSuite with Matchers with AppendedClues {
| void main () { | void main () {
| output = addDecimalTwice(9, 9) | output = addDecimalTwice(9, 9)
| } | }
| byte addDecimalTwice(byte a, byte b) { return (a +' b) + (a +' b) } | byte addDecimalTwice(byte a, byte b) { return (a $+ b) + (a $+ b) }
""".stripMargin)(_.readByte(0xc000) should equal(0x30)) """.stripMargin)(_.readByte(0xc000) should equal(0x30))
} }
@ -209,7 +209,7 @@ class ByteDecimalMathSuite extends FunSuite with Matchers with AppendedClues {
| void main () { | void main () {
| output = addDecimalTwice($c, $c) | output = addDecimalTwice($c, $c)
| } | }
| byte addDecimalTwice(byte a, byte b) { return (a + b) +' (a + b) } | byte addDecimalTwice(byte a, byte b) { return (a + b) $+ (a + b) }
""".stripMargin)(_.readByte(0xc000) should equal(0x36)) """.stripMargin)(_.readByte(0xc000) should equal(0x36))
} }
@ -398,10 +398,10 @@ class ByteDecimalMathSuite extends FunSuite with Matchers with AppendedClues {
| byte output @$c000 | byte output @$c000
| void main () { | void main () {
| init() | init()
| if output +' 1 == 0 { | if output $+ 1 == 0 {
| output = $22 | output = $22
| } | }
| output +'= 1 | output $+= 1
| } | }
| void init() { output = $99 } | void init() { output = $99 }
""".stripMargin """.stripMargin

View File

@ -448,7 +448,7 @@ class ForLoopSuite extends FunSuite with Matchers {
| p = a.addr | p = a.addr
| sum = 0 | sum = 0
| for i,0,paralleluntil,100 { sum += a[i] } | for i,0,paralleluntil,100 { sum += a[i] }
| for i,0,paralleluntil,100 { sum +'= a[i] } | for i,0,paralleluntil,100 { sum $+= a[i] }
| for i,0,paralleluntil,100 { sum &= a[i] } | for i,0,paralleluntil,100 { sum &= a[i] }
| for i,0,until,100 { sum &= a[i] } | for i,0,until,100 { sum &= a[i] }
| for i,0,until,50 { sum &= a[i+1] } | for i,0,until,50 { sum &= a[i+1] }

View File

@ -376,11 +376,11 @@ class PointerSuite extends FunSuite with Matchers with AppendedClues {
| output2 = 0 | output2 = 0
| pointer.word value_pointer | pointer.word value_pointer
| value_pointer = output2.pointer | value_pointer = output2.pointer
| value_pointer[0] +'= constant | value_pointer[0] $+= constant
| tmp[0] = output2 | tmp[0] = output2
| value_pointer[0] +'= constant | value_pointer[0] $+= constant
| tmp[1] = output2 | tmp[1] = output2
| value_pointer[0] -'= constant | value_pointer[0] $-= constant
| tmp[2] = output2 | tmp[2] = output2
| value_pointer[0] <<= f(1) | value_pointer[0] <<= f(1)
| tmp[3] = output2 | tmp[3] = output2