diff --git a/examples/crossplatform/fizzbuzz2.mfk b/examples/crossplatform/fizzbuzz2.mfk index c41b60ce..287d1f4a 100644 --- a/examples/crossplatform/fizzbuzz2.mfk +++ b/examples/crossplatform/fizzbuzz2.mfk @@ -9,13 +9,9 @@ struct stage { pointer text } -// can't put text literals directly in struct constructors yet -array fizz = "fizz"z -array buzz = "buzz"z - array(stage) stages = [ - stage(divisible3.pointer, fizz), - stage(divisible5.pointer, buzz) + stage(divisible3.pointer, "fizz"z), + stage(divisible5.pointer, "buzz"z) ] void main() { diff --git a/src/main/scala/millfork/compiler/AbstractStatementPreprocessor.scala b/src/main/scala/millfork/compiler/AbstractStatementPreprocessor.scala index bc37e2d8..bd8c1389 100644 --- a/src/main/scala/millfork/compiler/AbstractStatementPreprocessor.scala +++ b/src/main/scala/millfork/compiler/AbstractStatementPreprocessor.scala @@ -250,14 +250,6 @@ abstract class AbstractStatementPreprocessor(protected val ctx: CompilationConte } } - def genName(characters: List[Expression]): String = { - "textliteral$" ++ characters.flatMap{ - case LiteralExpression(n, _) => - f"$n%02x" - case _ => ??? - } - } - def optimizeExpr(expr: Expression, currentVarValues: VV): Expression = { val pos = expr.position // stdlib: @@ -448,11 +440,8 @@ abstract class AbstractStatementPreprocessor(protected val ctx: CompilationConte DerefExpression(optimizeExpr(inner, currentVarValues), 0, env.get[VariableType]("byte")).pos(pos) case DerefDebuggingExpression(inner, 2) => DerefExpression(optimizeExpr(inner, currentVarValues), 0, env.get[VariableType]("word")).pos(pos) - case TextLiteralExpression(characters) => - val name = genName(characters) - if (ctx.env.maybeGet[Thing](name).isEmpty) { - ctx.env.root.registerArray(ArrayDeclarationStatement(name, None, None, "byte", None, const = true, Some(LiteralContents(characters)), None).pos(pos), ctx.options) - } + case e@TextLiteralExpression(characters) => + val name = ctx.env.getTextLiteralArrayName(e) VariableExpression(name).pos(pos) case VariableExpression(v) if currentVarValues.contains(v) => val constant = currentVarValues(v) diff --git a/src/main/scala/millfork/env/Environment.scala b/src/main/scala/millfork/env/Environment.scala index e9fda4f7..cf6e22cd 100644 --- a/src/main/scala/millfork/env/Environment.scala +++ b/src/main/scala/millfork/env/Environment.scala @@ -599,7 +599,7 @@ class Environment(val parent: Option[Environment], val prefix: String, val cpuFa private def evalImpl(e: Expression, vv: Option[Map[String, Constant]]): Option[Constant] = { e match { case LiteralExpression(value, size) => Some(NumericConstant(value, size)) - case _:TextLiteralExpression => ??? + case tl:TextLiteralExpression => Some(getPointy(getTextLiteralArrayName(tl)).asInstanceOf[ConstantPointy].value) case ConstantArrayElementExpression(c) => Some(c) case GeneratedConstantExpression(c, t) => Some(c) case VariableExpression(name) => @@ -1160,6 +1160,19 @@ class Environment(val parent: Option[Environment], val prefix: String, val cpuFa get[Type]("function." + p.name + ".to." + f.returnType.name) } + def getTextLiteralArrayName(literal: TextLiteralExpression): String = { + val name = "textliteral$" ++ literal.characters.flatMap { + case LiteralExpression(n, _) => + f"$n%02x" + case _ => ??? + } + if (maybeGet[Thing](name).isEmpty) { + println("registering text literal") + root.registerArray(ArrayDeclarationStatement(name, None, None, "byte", None, const = true, Some(LiteralContents(literal.characters)), None).pos(literal.position), options) + } + name + } + private def registerAddressConstant(thing: ThingInMemory, position: Option[Position], options: CompilationOptions, targetType: Option[Type]): Unit = { val b = get[Type]("byte") if (!thing.zeropage && options.flag(CompilationFlag.LUnixRelocatableCode)) { diff --git a/src/main/scala/millfork/output/AbstractAssembler.scala b/src/main/scala/millfork/output/AbstractAssembler.scala index de4d0c3f..2cf6f31e 100644 --- a/src/main/scala/millfork/output/AbstractAssembler.scala +++ b/src/main/scala/millfork/output/AbstractAssembler.scala @@ -339,6 +339,15 @@ abstract class AbstractAssembler[T <: AbstractCode](private val program: Program case _ => } + // force early allocation of text literals: + env.allPreallocatables.filterNot(o => unusedRuntimeObjects(o.name)).foreach{ + case thing@InitializedArray(_, _, items, _, _, _, _, _) => + items.foreach(env.eval(_)) + case InitializedMemoryVariable(_, _, _, value, _, _, _) => + env.eval(value) + case _ => + } + if (options.flag(CompilationFlag.LUnixRelocatableCode)) { env.allThings.things.foreach { case (_, m@UninitializedMemoryVariable(name, typ, _, _, _, _)) if name.endsWith(".addr") || env.maybeGet[Thing](name + ".array").isDefined =>