diff --git a/docs/lang/syntax.md b/docs/lang/syntax.md index ce1d02df..69a67130 100644 --- a/docs/lang/syntax.md +++ b/docs/lang/syntax.md @@ -40,6 +40,12 @@ If not specified, it will be located according to the usual allocation rules. Only global variables can be initialized that way. The behaviour is undefined when targeting a ROM-based platform. +You can declare multiple variables in one declaration, for example: + + byte x, y @$c000, z=6, w + +will declare 4 variables: uninitialized variables `x` and `w`, fixed-address variable `y` and initialized variable `z`. + For every variable `x` larger than a byte, extra subvariables are defined: * if `x` is of type `word` or `pointer`: diff --git a/src/main/scala/millfork/parser/MfParser.scala b/src/main/scala/millfork/parser/MfParser.scala index 3a07e78d..3525c822 100644 --- a/src/main/scala/millfork/parser/MfParser.scala +++ b/src/main/scala/millfork/parser/MfParser.scala @@ -105,25 +105,31 @@ abstract class MfParser[T](fileId: String, input: String, currentDirectory: Stri val globalVariableDefinition: P[Seq[DeclarationStatement]] = variableDefinition(true) val localVariableDefinition: P[Seq[DeclarationStatement]] = variableDefinition(false) + def singleVariableDefinition: P[(Position, String, Option[Expression], Option[Expression], Option[MemoryAlignment])] = for { + p <- position() + name <- identifier ~/ HWS ~/ Pass + addr <- ("@" ~/ HWS ~/ mfExpression(1, false)).?.opaque("
") ~ HWS + initialValue <- ("=" ~/ HWS ~/ mfExpression(1, false)).? ~ HWS + alignment = None // TODO + } yield (p, name, addr, initialValue, alignment) + def variableDefinition(implicitlyGlobal: Boolean): P[Seq[DeclarationStatement]] = for { p <- position() bank <- bankDeclaration flags <- variableFlags ~ HWS typ <- identifier ~ SWS - name <- identifier ~/ HWS ~/ Pass - addr <- ("@" ~/ HWS ~/ mfExpression(1, false)).?.opaque("
") ~ HWS - initialValue <- ("=" ~/ HWS ~/ mfExpression(1, false)).? ~ HWS - alignment = None // TODO + vars <- singleVariableDefinition.rep(min = 1, sep = "," ~/ HWS) _ <- &(EOL) ~/ "" } yield { - Seq(VariableDeclarationStatement(name, typ, + vars.map { case (p, name, addr, initialValue, alignment) => VariableDeclarationStatement(name, typ, bank, global = implicitlyGlobal || flags("static"), stack = flags("stack"), constant = flags("const"), volatile = flags("volatile"), register = flags("register"), - initialValue, addr, alignment).pos(p)) + initialValue, addr, alignment).pos(p) + } } val paramDefinition: P[ParameterDeclaration] = for { diff --git a/src/test/scala/millfork/test/ByteMathSuite.scala b/src/test/scala/millfork/test/ByteMathSuite.scala index d915f41d..181840bc 100644 --- a/src/test/scala/millfork/test/ByteMathSuite.scala +++ b/src/test/scala/millfork/test/ByteMathSuite.scala @@ -43,8 +43,7 @@ class ByteMathSuite extends FunSuite with Matchers with AppendedClues { test("Byte addition") { EmuCrossPlatformBenchmarkRun(Cpu.Mos, Cpu.Z80, Cpu.Intel8080, Cpu.Sharp, Cpu.Intel8086)( """ - | byte output @$c000 - | byte a + | byte output @$c000, a | void main () { | a = 1 | output = a + a @@ -55,8 +54,7 @@ class ByteMathSuite extends FunSuite with Matchers with AppendedClues { test("Byte addition 2") { EmuCrossPlatformBenchmarkRun(Cpu.Mos, Cpu.Z80, Cpu.Intel8080, Cpu.Sharp, Cpu.Intel8086)( """ - | byte output @$c000 - | byte a + | byte output @$c000, a | void main () { | a = 1 | output = a + 65 @@ -123,10 +121,7 @@ class ByteMathSuite extends FunSuite with Matchers with AppendedClues { """ | array output[3] @$c000 | void main () { - | byte x - | byte y - | byte tmpx - | byte tmpy + | byte x, y, tmpx, tmpy | tmpx = one() | tmpy = one() | x = tmpx @@ -201,9 +196,7 @@ class ByteMathSuite extends FunSuite with Matchers with AppendedClues { EmuCrossPlatformBenchmarkRun(Cpu.Mos, Cpu.Z80, Cpu.Intel8080, Cpu.Sharp)( """ | import zp_reg - | byte output1 @$c001 - | byte output2 @$c002 - | byte output3 @$c003 + | byte output1 @$c001, output2 @$c002, output3 @$c003 | void main () { | calc1() | crash_if_bad() @@ -309,10 +302,7 @@ class ByteMathSuite extends FunSuite with Matchers with AppendedClues { EmuCrossPlatformBenchmarkRun(Cpu.Mos, Cpu.Z80, Cpu.Intel8080, Cpu.Sharp, Cpu.Intel8086)( s""" | import zp_reg - | byte output_q1 @$$c000 - | byte output_m1 @$$c001 - | byte output_q2 @$$c002 - | byte output_m2 @$$c003 + | byte output_q1 @$$c000, output_m1 @$$c001, output_q2 @$$c002, output_m2 @$$c003 | void main () { | byte a | a = f() @@ -351,10 +341,8 @@ class ByteMathSuite extends FunSuite with Matchers with AppendedClues { EmuCrossPlatformBenchmarkRun(Cpu.Mos, Cpu.Z80, Cpu.Intel8080, Cpu.Sharp, Cpu.Intel8086)( s""" | import zp_reg - | byte output_q1 @$$c000 - | byte output_m1 @$$c001 - | byte output_q2 @$$c002 - | byte output_m2 @$$c003 + | byte output_q1 @$$c000, output_m1 @$$c001 + | byte output_q2 @$$c002, output_m2 @$$c003 | void main () { | byte a | byte b @@ -412,10 +400,8 @@ class ByteMathSuite extends FunSuite with Matchers with AppendedClues { EmuCrossPlatformBenchmarkRun(Cpu.Mos, Cpu.Z80, Cpu.Intel8080, Cpu.Sharp, Cpu.Intel8086)( s""" | import zp_reg - | byte output_q1 @$$c000 - | byte output_m1 @$$c001 - | byte output_q2 @$$c002 - | byte output_m2 @$$c003 + | byte output_q1 @$$c000, output_m1 @$$c001 + | byte output_q2 @$$c002, output_m2 @$$c003 | void main () { | byte a | output_q2 = g() diff --git a/src/test/scala/millfork/test/StackVarSuite.scala b/src/test/scala/millfork/test/StackVarSuite.scala index 0a5e27d9..04b5e70b 100644 --- a/src/test/scala/millfork/test/StackVarSuite.scala +++ b/src/test/scala/millfork/test/StackVarSuite.scala @@ -13,8 +13,7 @@ class StackVarSuite extends FunSuite with Matchers { EmuCrossPlatformBenchmarkRun(Cpu.StrictMos, Cpu.Z80, Cpu.Intel8080, Cpu.Intel8085, Cpu.Sharp, Cpu.Intel8086)(""" | byte output @$c000 | void main () { - | stack byte a - | stack byte b + | stack byte a, b | b = 4 | a = b | output = a @@ -27,8 +26,7 @@ class StackVarSuite extends FunSuite with Matchers { EmuCrossPlatformBenchmarkRun(Cpu.StrictMos, Cpu.Z80, Cpu.Intel8080, Cpu.Sharp, Cpu.Intel8086)(""" | byte output @$c000 | void main () { - | stack byte a - | stack byte b + | stack byte a, b | a = $11 | b = $44 | b += zzz() @@ -74,8 +72,7 @@ class StackVarSuite extends FunSuite with Matchers { """ | byte output @$c000 | void main () { - | stack byte a - | stack byte b + | stack byte a, b | b = $77 | a = $11 | b -= zzz() @@ -94,8 +91,7 @@ class StackVarSuite extends FunSuite with Matchers { EmuCrossPlatformBenchmarkRun(Cpu.StrictMos, Cpu.Z80, Cpu.Intel8080, Cpu.Intel8085, Cpu.Sharp, Cpu.Intel8086)(""" | word output @$c000 | void main () { - | stack word a - | stack word b + | stack word a, b | a = $111 | b = $444 | b += zzz() @@ -123,9 +119,7 @@ class StackVarSuite extends FunSuite with Matchers { | } | word fib(byte i) { | stack byte j - | stack word sum - | stack word w - | stack word v + | stack word sum, w, v | j = i | if j < 2 { | return 1 @@ -208,8 +202,7 @@ class StackVarSuite extends FunSuite with Matchers { EmuCrossPlatformBenchmarkRun(Cpu.StrictMos, Cpu.Z80, Cpu.Intel8080, Cpu.Sharp, Cpu.Intel8086)(""" | array output [200] @$c000 | void main () { - | stack byte a - | stack byte b + | stack byte a, b | a = $11 | b = $44 | output[a + b] = $66 @@ -286,8 +279,7 @@ class StackVarSuite extends FunSuite with Matchers { """ | int32 output @$c000 | void main () { - | stack int32 a - | stack int32 b + | stack int32 a, b | a = f() | barrier() | b = a @@ -406,9 +398,7 @@ class StackVarSuite extends FunSuite with Matchers { | noinline byte f() = 6 | noinline void g(byte x) {} | void main () { - | stack byte b - | stack byte a - | stack byte c + | stack byte b, a, c | b = b | c = c | a = f() @@ -435,10 +425,7 @@ class StackVarSuite extends FunSuite with Matchers { | p[0] = __loop.addr + 1 | } | void main () { - | stack word b - | stack word a - | stack word c - | stack word d + | stack word b, a, c, d | h(a.pointer) | h(b.pointer) | h(c.pointer)