diff --git a/codeCore/src/prog8/code/ast/AstBase.kt b/codeCore/src/prog8/code/ast/AstBase.kt index 50c31a880..90a3d3912 100644 --- a/codeCore/src/prog8/code/ast/AstBase.kt +++ b/codeCore/src/prog8/code/ast/AstBase.kt @@ -96,7 +96,12 @@ class PtInlineAssembly(val assembly: String, val isIR: Boolean, position: Positi } -class PtLabel(name: String, position: Position) : PtNamedNode(name, position) +class PtLabel(name: String, position: Position) : PtNamedNode(name, position) { + companion object { + // all automatically generated labels everywhere need to have the same label name prefix: + const val GeneratedLabelPrefix = "p8_label_gen_" + } +} class PtBreakpoint(position: Position): PtNode(position) diff --git a/codeGenCpu6502/src/prog8/codegen/cpu6502/AsmGen.kt b/codeGenCpu6502/src/prog8/codegen/cpu6502/AsmGen.kt index 2dd7dc079..67f482349 100644 --- a/codeGenCpu6502/src/prog8/codegen/cpu6502/AsmGen.kt +++ b/codeGenCpu6502/src/prog8/codegen/cpu6502/AsmGen.kt @@ -16,15 +16,15 @@ import kotlin.io.path.writeLines internal const val subroutineFloatEvalResultVar1 = "prog8_float_eval_result1" internal const val subroutineFloatEvalResultVar2 = "prog8_float_eval_result2" -class AsmGen6502(val prefixSymbols: Boolean): ICodeGeneratorBackend { +class AsmGen6502(val prefixSymbols: Boolean, private val lastGeneratedLabelSequenceNr: Int): ICodeGeneratorBackend { override fun generate( program: PtProgram, symbolTable: SymbolTable, options: CompilationOptions, - errors: IErrorReporter + errors: IErrorReporter, ): IAssemblyProgram? { val st = if(prefixSymbols) prefixSymbols(program, options, symbolTable) else symbolTable - val asmgen = AsmGen6502Internal(program, st, options, errors) + val asmgen = AsmGen6502Internal(program, st, options, errors, lastGeneratedLabelSequenceNr) return asmgen.compileToAssembly() } @@ -36,7 +36,7 @@ class AsmGen6502(val prefixSymbols: Boolean): ICodeGeneratorBackend { when(node) { is PtAsmSub, is PtSub -> node.name = "p8s_${node.name}" is PtBlock -> node.name = "p8b_${node.name}" - is PtLabel -> node.name = "p8l_${node.name}" + is PtLabel -> if(!node.name.startsWith(PtLabel.GeneratedLabelPrefix)) node.name = "p8l_${node.name}" is PtConstant -> node.name = "p8c_${node.name}" is PtVariable, is PtMemMapped, is PtSubroutineParameter -> node.name = "p8v_${node.name}" else -> node.name = "p8_${node.name}" @@ -126,11 +126,15 @@ class AsmGen6502(val prefixSymbols: Boolean): ICodeGeneratorBackend { } private fun prefixScopedName(name: String, type: Char): String { - if('.' !in name) + if('.' !in name) { + if(name.startsWith(PtLabel.GeneratedLabelPrefix)) + return name return "p8${type}_$name" + } val parts = name.split('.') val firstPrefixed = "p8b_${parts[0]}" - val lastPrefixed = "p8${type}_${parts.last()}" + val lastPart = parts.last() + val lastPrefixed = if(lastPart.startsWith(PtLabel.GeneratedLabelPrefix)) lastPart else "p8${type}_$lastPart" // the parts in between are assumed to be subroutine scopes. val inbetweenPrefixed = parts.drop(1).dropLast(1).map{ "p8s_$it" } val prefixed = listOf(firstPrefixed) + inbetweenPrefixed + listOf(lastPrefixed) @@ -221,7 +225,8 @@ class AsmGen6502Internal ( val program: PtProgram, internal val symbolTable: SymbolTable, internal val options: CompilationOptions, - internal val errors: IErrorReporter + internal val errors: IErrorReporter, + private var generatedLabelSequenceNumber: Int ) { internal val optimizedByteMultiplications = setOf(3,5,6,7,9,10,11,12,13,14,15,20,25,40,50,80,100) @@ -1364,11 +1369,9 @@ $repeatLabel""") extra } - private var generatedLabelSequenceNumber: Int = 0 - internal fun makeLabel(postfix: String): String { generatedLabelSequenceNumber++ - return "label_asm_${generatedLabelSequenceNumber}_$postfix" + return "${PtLabel.GeneratedLabelPrefix}${generatedLabelSequenceNumber}_$postfix" } fun assignConstFloatToPointerAY(number: PtNumber) { diff --git a/codeGenCpu6502/src/prog8/codegen/cpu6502/AssemblyProgram.kt b/codeGenCpu6502/src/prog8/codegen/cpu6502/AssemblyProgram.kt index 7395b1782..5d13094ba 100644 --- a/codeGenCpu6502/src/prog8/codegen/cpu6502/AssemblyProgram.kt +++ b/codeGenCpu6502/src/prog8/codegen/cpu6502/AssemblyProgram.kt @@ -1,5 +1,6 @@ package prog8.codegen.cpu6502 +import prog8.code.ast.PtLabel import prog8.code.core.* import prog8.code.target.AtariTarget import prog8.code.target.C64Target @@ -9,7 +10,7 @@ import java.nio.file.Path internal class AssemblyProgram( override val name: String, - outputDir: Path, + private val outputDir: Path, private val compTarget: ICompilationTarget) : IAssemblyProgram { private val assemblyFile = outputDir.resolve("$name.asm") @@ -147,7 +148,7 @@ internal class AssemblyProgram( } private fun removeGeneratedLabelsFromMonlist() { - val pattern = Regex("""al (\w+) \S+prog8_label_.+?""") + val pattern = Regex("""al (\w+) \S+${PtLabel.GeneratedLabelPrefix}.+?""") val lines = viceMonListFile.toFile().readLines() viceMonListFile.toFile().outputStream().bufferedWriter().use { for (line in lines) { diff --git a/codeGenCpu6502/test/TestCodegen.kt b/codeGenCpu6502/test/TestCodegen.kt index 001496128..b3a57c0f3 100644 --- a/codeGenCpu6502/test/TestCodegen.kt +++ b/codeGenCpu6502/test/TestCodegen.kt @@ -44,7 +44,7 @@ class TestCodegen: FunSpec({ // xx += cx16.r0 // } //} - val codegen = AsmGen6502(prefixSymbols = false) + val codegen = AsmGen6502(prefixSymbols = false, 0) val program = PtProgram("test", DummyMemsizer, DummyStringEncoder) val block = PtBlock("main",false, SourceCode.Generated("test"), PtBlock.Options(), Position.DUMMY) val sub = PtSub("start", emptyList(), null, Position.DUMMY) diff --git a/codeGenIntermediate/src/prog8/codegen/intermediate/IRCodeGen.kt b/codeGenIntermediate/src/prog8/codegen/intermediate/IRCodeGen.kt index 1cc153b0f..b76bbe345 100644 --- a/codeGenIntermediate/src/prog8/codegen/intermediate/IRCodeGen.kt +++ b/codeGenIntermediate/src/prog8/codegen/intermediate/IRCodeGen.kt @@ -1752,7 +1752,7 @@ class IRCodeGen( private var labelSequenceNumber = 0 internal fun createLabelName(): String { labelSequenceNumber++ - return "label_gen_$labelSequenceNumber" + return "${PtLabel.GeneratedLabelPrefix}$labelSequenceNumber" } internal fun translateBuiltinFunc(call: PtBuiltinFunctionCall): ExpressionCodeResult diff --git a/compiler/src/prog8/compiler/Compiler.kt b/compiler/src/prog8/compiler/Compiler.kt index 4fb469810..ab882c36a 100644 --- a/compiler/src/prog8/compiler/Compiler.kt +++ b/compiler/src/prog8/compiler/Compiler.kt @@ -149,7 +149,7 @@ fun compileProgram(args: CompilerArguments): CompilationResult? { verifyFinalAstBeforeAsmGen(intermediateAst, compilationOptions, symbolTable, args.errors) args.errors.report() - if(!createAssemblyAndAssemble(intermediateAst, args.errors, compilationOptions)) { + if(!createAssemblyAndAssemble(intermediateAst, args.errors, compilationOptions, program.generatedLabelSequenceNumber)) { System.err.println("Error in codegeneration or assembler") return null } @@ -489,13 +489,14 @@ private fun postprocessAst(program: Program, errors: IErrorReporter, compilerOpt private fun createAssemblyAndAssemble(program: PtProgram, errors: IErrorReporter, - compilerOptions: CompilationOptions + compilerOptions: CompilationOptions, + lastGeneratedLabelSequenceNr: Int ): Boolean { val asmgen = if(compilerOptions.experimentalCodegen) prog8.codegen.experimental.ExperiCodeGen() else if (compilerOptions.compTarget.machine.cpu in arrayOf(CpuType.CPU6502, CpuType.CPU65c02)) - prog8.codegen.cpu6502.AsmGen6502(prefixSymbols = true) + prog8.codegen.cpu6502.AsmGen6502(prefixSymbols = true, lastGeneratedLabelSequenceNr+1) else if (compilerOptions.compTarget.name == VMTarget.NAME) VmCodeGen() else diff --git a/compiler/test/codegeneration/TestAsmGenSymbols.kt b/compiler/test/codegeneration/TestAsmGenSymbols.kt index ba226c4f8..8879f85ba 100644 --- a/compiler/test/codegeneration/TestAsmGenSymbols.kt +++ b/compiler/test/codegeneration/TestAsmGenSymbols.kt @@ -77,7 +77,7 @@ class TestAsmGenSymbols: StringSpec({ val options = CompilationOptions(OutputType.RAW, CbmPrgLauncherType.NONE, ZeropageType.FULL, emptyList(), CompilationOptions.AllZeropageAllowed, false, true, C64Target(), 999u, 0xffffu) val ptProgram = IntermediateAstMaker(program, errors).transform() val st = SymbolTableMaker(ptProgram, options).make() - return AsmGen6502Internal(ptProgram, st, options, errors) + return AsmGen6502Internal(ptProgram, st, options, errors, 0) } "symbol and variable names from strings" { diff --git a/compilerAst/src/prog8/ast/Program.kt b/compilerAst/src/prog8/ast/Program.kt index fd88dc470..83db3db4d 100644 --- a/compilerAst/src/prog8/ast/Program.kt +++ b/compilerAst/src/prog8/ast/Program.kt @@ -5,6 +5,7 @@ import prog8.ast.expressions.IdentifierReference import prog8.ast.expressions.StringLiteral import prog8.ast.statements.* import prog8.ast.walk.IAstVisitor +import prog8.code.ast.PtLabel import prog8.code.core.* /*********** Everything starts from here, the Program; zero or more modules *************/ @@ -144,11 +145,12 @@ class Program(val name: String, } } - private var generatedLabelSequenceNumber: Int = 0 + var generatedLabelSequenceNumber: Int = 0 + private set fun makeLabel(postfix: String): String { generatedLabelSequenceNumber++ - return "label_${generatedLabelSequenceNumber}_$postfix" + return "${PtLabel.GeneratedLabelPrefix}${generatedLabelSequenceNumber}_$postfix" } fun makeLabel(postfix: String, position: Position): Label { diff --git a/docs/source/todo.rst b/docs/source/todo.rst index 5962e27eb..2d3a6b05c 100644 --- a/docs/source/todo.rst +++ b/docs/source/todo.rst @@ -7,9 +7,9 @@ TODO Future Things and Ideas ^^^^^^^^^^^^^^^^^^^^^^^ -- Port the diskio module to the PET using lower level serial kernal IO calls? - something to reduce the need to use fully qualified names all the time. 'with' ? Or 'using '? - Why are blocks without an addr moved BEHIND a block with an address? That's done in the StatementReorderer. +- on the C64: make the floating point routines @banked so that basic can be permanently banked out even if you use floats? But this will crash when the call is done from program code at $a000+ - Libraries: improve ability to create library files in prog8; for instance there's still stuff injected into the start of the start() routine AND there is separate setup logic going on before calling it. Make up our mind! Maybe all setup does need to be put into start() ? because the program cannot function correctly when the variables aren't initialized properly bss is not cleared etc. etc. Add a -library $xxxx command line option to preselect every setting that is required to make a library at $xxxx rather than a normal loadable and runnable program? diff --git a/examples/test.p8 b/examples/test.p8 index c9c330962..ab3414a41 100644 --- a/examples/test.p8 +++ b/examples/test.p8 @@ -1,31 +1,16 @@ %import textio %zeropage basicsafe - +%option no_sysinit main { sub start() { - txt.print_ubbin(c128.getbanks(), true) - txt.spc() - txt.print_ub(@($4000)) - txt.spc() - txt.print_ub(@($8000)) - txt.nl() + repeat 100 { + cx16.r0++ + if cx16.r0!=0 + goto mylabel + } - @($4000)++ - @($8000)++ - txt.print_ub(@($4000)) - txt.spc() - txt.print_ub(@($8000)) - txt.nl() +mylabel: - c128.banks(0) - txt.print_ubbin(c128.getbanks(), true) - txt.spc() - @($4000)++ - @($8000)++ - txt.print_ub(@($4000)) - txt.spc() - txt.print_ub(@($8000)) - txt.nl() } } diff --git a/gradle.properties b/gradle.properties index e04fc14a6..aed39f747 100644 --- a/gradle.properties +++ b/gradle.properties @@ -5,4 +5,4 @@ org.gradle.daemon=true kotlin.code.style=official javaVersion=11 kotlinVersion=2.0.21 -version=10.5 +version=10.5.1-SNAPSHOT