diff --git a/codeGenCpu6502/src/prog8/codegen/cpu6502/AsmGen.kt b/codeGenCpu6502/src/prog8/codegen/cpu6502/AsmGen.kt index 1efdf0096..14eb698c2 100644 --- a/codeGenCpu6502/src/prog8/codegen/cpu6502/AsmGen.kt +++ b/codeGenCpu6502/src/prog8/codegen/cpu6502/AsmGen.kt @@ -18,7 +18,6 @@ import kotlin.io.path.Path import kotlin.io.path.writeLines -internal const val generatedLabelPrefix = "prog8_label_" internal const val subroutineFloatEvalResultVar1 = "prog8_float_eval_result1" internal const val subroutineFloatEvalResultVar2 = "prog8_float_eval_result2" @@ -73,13 +72,6 @@ class AsmGen(internal val program: Program, internal fun isTargetCpu(cpu: CpuType) = options.compTarget.machine.cpu == cpu - private var generatedLabelSequenceNumber: Int = 0 - - internal fun makeLabel(postfix: String): String { - generatedLabelSequenceNumber++ - return "${generatedLabelPrefix}${generatedLabelSequenceNumber}_$postfix" - } - internal fun outputSourceLine(node: Node) { out(" ;\tsrc line: ${node.position.file}:${node.position.line}") } @@ -543,7 +535,7 @@ class AsmGen(internal val program: Program, if(jump is Jump) { translateCompareAndJumpIfTrue(booleanCondition, jump) } else { - val endLabel = makeLabel("if_end") + val endLabel = program.makeLabel("if_end") translateCompareAndJumpIfFalse(booleanCondition, endLabel) translate(stmt.truepart) out(endLabel) @@ -551,8 +543,8 @@ class AsmGen(internal val program: Program, } else { // both true and else parts - val elseLabel = makeLabel("if_else") - val endLabel = makeLabel("if_end") + val elseLabel = program.makeLabel("if_else") + val endLabel = program.makeLabel("if_end") translateCompareAndJumpIfFalse(booleanCondition, elseLabel) translate(stmt.truepart) jmp(endLabel) @@ -568,7 +560,7 @@ class AsmGen(internal val program: Program, } private fun translate(stmt: RepeatLoop) { - val endLabel = makeLabel("repeatend") + val endLabel = program.makeLabel("repeatend") loopEndLabels.push(endLabel) when (stmt.iterations) { @@ -621,7 +613,7 @@ class AsmGen(internal val program: Program, private fun repeatWordCount(count: Int, stmt: RepeatLoop) { require(count in 257..65535) - val repeatLabel = makeLabel("repeat") + val repeatLabel = program.makeLabel("repeat") if(isTargetCpu(CpuType.CPU65c02)) { val counterVar = createRepeatCounterVar(DataType.UWORD, true, stmt) out(""" @@ -662,7 +654,7 @@ $repeatLabel""") private fun repeatWordCountInAY(endLabel: String, stmt: RepeatLoop) { // note: A/Y must have been loaded with the number of iterations! // no need to explicitly test for 0 iterations as this is done in the countdown logic below - val repeatLabel = makeLabel("repeat") + val repeatLabel = program.makeLabel("repeat") val counterVar = createRepeatCounterVar(DataType.UWORD, false, stmt) out(""" sta $counterVar @@ -683,7 +675,7 @@ $repeatLabel lda $counterVar private fun repeatByteCount(count: Int, stmt: RepeatLoop) { require(count in 2..256) - val repeatLabel = makeLabel("repeat") + val repeatLabel = program.makeLabel("repeat") if(isTargetCpu(CpuType.CPU65c02)) { val counterVar = createRepeatCounterVar(DataType.UBYTE, true, stmt) out(" lda #${count and 255} | sta $counterVar") @@ -701,7 +693,7 @@ $repeatLabel lda $counterVar private fun repeatCountInY(stmt: RepeatLoop, endLabel: String) { // note: Y must just have been loaded with the (variable) number of loops to be performed! - val repeatLabel = makeLabel("repeat") + val repeatLabel = program.makeLabel("repeat") if(isTargetCpu(CpuType.CPU65c02)) { val counterVar = createRepeatCounterVar(DataType.UBYTE, true, stmt) out(" beq $endLabel | sty $counterVar") @@ -738,7 +730,7 @@ $repeatLabel lda $counterVar } } - val counterVar = makeLabel("counter") + val counterVar = program.makeLabel("counter") when(dt) { DataType.UBYTE, DataType.UWORD -> { val result = zeropage.allocate(listOf(counterVar), dt, null, stmt.position, errors) @@ -753,7 +745,7 @@ $repeatLabel lda $counterVar } private fun translate(stmt: When) { - val endLabel = makeLabel("choice_end") + val endLabel = program.makeLabel("choice_end") val choiceBlocks = mutableListOf>() val conditionDt = stmt.condition.inferType(program) if(!conditionDt.isKnown) @@ -764,7 +756,7 @@ $repeatLabel lda $counterVar assignExpressionToRegister(stmt.condition, RegisterOrPair.AY) for(choice in stmt.choices) { - val choiceLabel = makeLabel("choice") + val choiceLabel = program.makeLabel("choice") if(choice.values==null) { // the else choice translate(choice.statements) @@ -828,14 +820,14 @@ $repeatLabel lda $counterVar } else { if(stmt.elsepart.isEmpty()) { val instruction = branchInstruction(stmt.condition, true) - val elseLabel = makeLabel("branch_else") + val elseLabel = program.makeLabel("branch_else") out(" $instruction $elseLabel") translate(stmt.truepart) out(elseLabel) } else { val instruction = branchInstruction(stmt.condition, true) - val elseLabel = makeLabel("branch_else") - val endLabel = makeLabel("branch_end") + val elseLabel = program.makeLabel("branch_else") + val endLabel = program.makeLabel("branch_end") out(" $instruction $elseLabel") translate(stmt.truepart) jmp(endLabel) diff --git a/codeGenCpu6502/src/prog8/codegen/cpu6502/AssemblyProgram.kt b/codeGenCpu6502/src/prog8/codegen/cpu6502/AssemblyProgram.kt index da518f042..87442d812 100644 --- a/codeGenCpu6502/src/prog8/codegen/cpu6502/AssemblyProgram.kt +++ b/codeGenCpu6502/src/prog8/codegen/cpu6502/AssemblyProgram.kt @@ -3,6 +3,7 @@ package prog8.codegen.cpu6502 import com.github.michaelbull.result.Ok import com.github.michaelbull.result.Result import com.github.michaelbull.result.mapError +import prog8.ast.generatedLabelPrefix import prog8.code.core.* import java.io.File import java.nio.file.Path diff --git a/codeGenCpu6502/src/prog8/codegen/cpu6502/ForLoopsAsmGen.kt b/codeGenCpu6502/src/prog8/codegen/cpu6502/ForLoopsAsmGen.kt index 76b65acf8..f3cdb6084 100644 --- a/codeGenCpu6502/src/prog8/codegen/cpu6502/ForLoopsAsmGen.kt +++ b/codeGenCpu6502/src/prog8/codegen/cpu6502/ForLoopsAsmGen.kt @@ -31,10 +31,10 @@ internal class ForLoopsAsmGen(private val program: Program, private val asmgen: } private fun translateForOverNonconstRange(stmt: ForLoop, iterableDt: DataType, range: RangeExpression) { - val loopLabel = asmgen.makeLabel("for_loop") - val endLabel = asmgen.makeLabel("for_end") - val modifiedLabel = asmgen.makeLabel("for_modified") - val modifiedLabel2 = asmgen.makeLabel("for_modifiedb") + val loopLabel = program.makeLabel("for_loop") + val endLabel = program.makeLabel("for_end") + val modifiedLabel = program.makeLabel("for_modified") + val modifiedLabel2 = program.makeLabel("for_modifiedb") asmgen.loopEndLabels.push(endLabel) val stepsize=range.step.constValue(program)!!.number.toInt() @@ -238,8 +238,8 @@ $endLabel""") } private fun translateForOverIterableVar(stmt: ForLoop, iterableDt: DataType, ident: IdentifierReference) { - val loopLabel = asmgen.makeLabel("for_loop") - val endLabel = asmgen.makeLabel("for_end") + val loopLabel = program.makeLabel("for_loop") + val endLabel = program.makeLabel("for_end") asmgen.loopEndLabels.push(endLabel) val iterableName = asmgen.asmVariableName(ident) val decl = ident.targetVarDecl(program)!! @@ -263,7 +263,7 @@ $endLabel""") } DataType.ARRAY_UB, DataType.ARRAY_B -> { val length = decl.arraysize!!.constIndex()!! - val indexVar = asmgen.makeLabel("for_index") + val indexVar = program.makeLabel("for_index") asmgen.out(""" ldy #0 $loopLabel sty $indexVar @@ -299,7 +299,7 @@ $loopLabel sty $indexVar } DataType.ARRAY_W, DataType.ARRAY_UW -> { val length = decl.arraysize!!.constIndex()!! * 2 - val indexVar = asmgen.makeLabel("for_index") + val indexVar = program.makeLabel("for_index") val loopvarName = asmgen.asmVariableName(stmt.loopVar) asmgen.out(""" ldy #0 @@ -359,8 +359,8 @@ $loopLabel sty $indexVar } // not one of the easy cases, generate more complex code... - val loopLabel = asmgen.makeLabel("for_loop") - val endLabel = asmgen.makeLabel("for_end") + val loopLabel = program.makeLabel("for_loop") + val endLabel = program.makeLabel("for_end") asmgen.loopEndLabels.push(endLabel) when(iterableDt) { DataType.ARRAY_B, DataType.ARRAY_UB -> { @@ -471,8 +471,8 @@ $loopLabel""") } private fun translateForSimpleByteRangeAsc(stmt: ForLoop, range: IntProgression) { - val loopLabel = asmgen.makeLabel("for_loop") - val endLabel = asmgen.makeLabel("for_end") + val loopLabel = program.makeLabel("for_loop") + val endLabel = program.makeLabel("for_end") asmgen.loopEndLabels.push(endLabel) val varname = asmgen.asmVariableName(stmt.loopVar) asmgen.out(""" @@ -497,8 +497,8 @@ $endLabel""") } private fun translateForSimpleByteRangeDesc(stmt: ForLoop, range: IntProgression) { - val loopLabel = asmgen.makeLabel("for_loop") - val endLabel = asmgen.makeLabel("for_end") + val loopLabel = program.makeLabel("for_loop") + val endLabel = program.makeLabel("for_end") asmgen.loopEndLabels.push(endLabel) val varname = asmgen.asmVariableName(stmt.loopVar) asmgen.out(""" @@ -534,8 +534,8 @@ $endLabel""") } private fun translateForSimpleWordRangeAsc(stmt: ForLoop, range: IntProgression) { - val loopLabel = asmgen.makeLabel("for_loop") - val endLabel = asmgen.makeLabel("for_end") + val loopLabel = program.makeLabel("for_loop") + val endLabel = program.makeLabel("for_end") asmgen.loopEndLabels.push(endLabel) val varname = asmgen.asmVariableName(stmt.loopVar) asmgen.out(""" @@ -561,8 +561,8 @@ $loopLabel""") } private fun translateForSimpleWordRangeDesc(stmt: ForLoop, range: IntProgression) { - val loopLabel = asmgen.makeLabel("for_loop") - val endLabel = asmgen.makeLabel("for_end") + val loopLabel = program.makeLabel("for_loop") + val endLabel = program.makeLabel("for_end") asmgen.loopEndLabels.push(endLabel) val varname = asmgen.asmVariableName(stmt.loopVar) asmgen.out(""" diff --git a/compiler/src/prog8/compiler/astprocessing/CodeDesugarer.kt b/compiler/src/prog8/compiler/astprocessing/CodeDesugarer.kt index 602e12da4..8152697b1 100644 --- a/compiler/src/prog8/compiler/astprocessing/CodeDesugarer.kt +++ b/compiler/src/prog8/compiler/astprocessing/CodeDesugarer.kt @@ -12,9 +12,8 @@ import prog8.code.core.IErrorReporter import prog8.code.core.Position -private var generatedLabelSequenceNumber: Int = 0 - -internal class CodeDesugarer(val program: Program, private val errors: IErrorReporter) : AstWalker() { +internal class CodeDesugarer(val program: Program, + private val errors: IErrorReporter) : AstWalker() { // Some more code shuffling to simplify the Ast that the codegenerator has to process. // Several changes have already been done by the StatementReorderer ! @@ -28,13 +27,6 @@ internal class CodeDesugarer(val program: Program, private val errors: IErrorRep // - repeat-forever loops replaced by label+jump. - private val generatedLabelPrefix = "prog8_label_" - - private fun makeLabel(postfix: String, position: Position): Label { - generatedLabelSequenceNumber++ - return Label("${generatedLabelPrefix}${generatedLabelSequenceNumber}_$postfix", position) - } - private fun jumpLabel(label: Label): Jump { val ident = IdentifierReference(listOf(label.name), label.position) return Jump(null, ident, null, label.position) @@ -42,7 +34,7 @@ internal class CodeDesugarer(val program: Program, private val errors: IErrorRep override fun before(breakStmt: Break, parent: Node): Iterable { fun jumpAfter(stmt: Statement): Iterable { - val label = makeLabel("after", breakStmt.position) + val label = program.makeLabel("after", breakStmt.position) return listOf( IAstModification.ReplaceNode(breakStmt, jumpLabel(label), parent), IAstModification.InsertAfter(stmt, label, stmt.parent as IStatementContainer) @@ -75,7 +67,7 @@ if not CONDITION goto _loop */ val pos = untilLoop.position - val loopLabel = makeLabel("untilloop", pos) + val loopLabel = program.makeLabel("untilloop", pos) val notCondition = PrefixExpression("not", untilLoop.condition, pos) val replacement = AnonymousScope(mutableListOf( loopLabel, @@ -99,8 +91,8 @@ _whileloop: _after: */ val pos = whileLoop.position - val loopLabel = makeLabel("whileloop", pos) - val afterLabel = makeLabel("afterwhile", pos) + val loopLabel = program.makeLabel("whileloop", pos) + val afterLabel = program.makeLabel("afterwhile", pos) val notCondition = PrefixExpression("not", whileLoop.condition, pos) val replacement = AnonymousScope(mutableListOf( loopLabel, @@ -138,7 +130,7 @@ _after: override fun after(repeatLoop: RepeatLoop, parent: Node): Iterable { if(repeatLoop.iterations==null) { - val label = makeLabel("repeat", repeatLoop.position) + val label = program.makeLabel("repeat", repeatLoop.position) val jump = jumpLabel(label) return listOf( IAstModification.InsertFirst(label, repeatLoop.body), diff --git a/compiler/test/codegeneration/TestAsmGenSymbols.kt b/compiler/test/codegeneration/TestAsmGenSymbols.kt index 8fdf583d1..4f616b2ee 100644 --- a/compiler/test/codegeneration/TestAsmGenSymbols.kt +++ b/compiler/test/codegeneration/TestAsmGenSymbols.kt @@ -2,6 +2,7 @@ package prog8tests.codegeneration import io.kotest.core.spec.style.StringSpec import io.kotest.matchers.shouldBe +import io.kotest.matchers.shouldNotBe import prog8.ast.Module import prog8.ast.Program import prog8.ast.expressions.AddressOf @@ -13,10 +14,12 @@ import prog8.code.target.C64Target import prog8.code.target.c64.C64Zeropage import prog8.codegen.cpu6502.AsmGen import prog8.compiler.astprocessing.SymbolTableMaker +import prog8tests.helpers.* import prog8tests.helpers.DummyFunctions import prog8tests.helpers.DummyMemsizer import prog8tests.helpers.DummyStringEncoder import prog8tests.helpers.ErrorReporterForTests +import prog8tests.helpers.compileText class TestAsmGenSymbols: StringSpec({ fun createTestProgram(): Program { @@ -153,4 +156,26 @@ main { asmgen.asmSymbolName(id1) shouldBe "P8ZP_SCRATCH_REG" asmgen.asmSymbolName(id2) shouldBe "P8ZP_SCRATCH_W2" } + + "no double labels with various loops" { + val text=""" + main { + sub start() { + if true { + } + + repeat 4 { + } + + while true { + } + + repeat { + } + } + } + """ + val result = compileText(C64Target(), false, text, writeAssembly = true) + result shouldNotBe null + } }) diff --git a/compilerAst/src/prog8/ast/Program.kt b/compilerAst/src/prog8/ast/Program.kt index 59c9dffb8..5974fb5d9 100644 --- a/compilerAst/src/prog8/ast/Program.kt +++ b/compilerAst/src/prog8/ast/Program.kt @@ -143,4 +143,19 @@ class Program(val name: String, } } + private var generatedLabelSequenceNumber: Int = 0 + + fun makeLabel(postfix: String): String { + generatedLabelSequenceNumber++ + return "${generatedLabelPrefix}${generatedLabelSequenceNumber}_$postfix" + } + + fun makeLabel(postfix: String, position: Position): Label { + val strLabel = makeLabel(postfix) + return Label(strLabel, position) + } + } + + +const val generatedLabelPrefix = "prog8_label_" diff --git a/docs/source/todo.rst b/docs/source/todo.rst index 12bd142b2..f3e20e8ba 100644 --- a/docs/source/todo.rst +++ b/docs/source/todo.rst @@ -3,7 +3,6 @@ TODO For next release ^^^^^^^^^^^^^^^^ -- bug: 2 repeats in same subroutine -> duplicate label error? see repeat_bug.p8 - bug: f_read() can't deal with running out of banked ram? maybe only cx16diskio.f_read()? - add McCarthy evaluation to shortcircuit and/or expressions. Both conditional expressions and assignments! - add some more optimizations in vmPeepholeOptimizer