diff --git a/compiler/examples/sprites.p8 b/compiler/examples/sprites.p8 index a89f2120e..a379fc6bb 100644 --- a/compiler/examples/sprites.p8 +++ b/compiler/examples/sprites.p8 @@ -1,10 +1,10 @@ %import c64lib %import c64utils +%option force_output, enable_floats -~ main { - const uword SP0X = $d000 - const uword SP0Y = $d001 +~ spritedata $0a00 { + %option force_output ; make sure the data appears in the program ubyte[63] balloonsprite = [ %00000000,%01111111,%00000000, %00000001,%11111111,%11000000, @@ -27,23 +27,26 @@ %00000000,%00111110,%00000000, %00000000,%00111110,%00000000, %00000000,%00011100,%00000000 ] +} - const uword sprite_data_address = 13*64 ; // safe area inside the tape buffer +~ main { + + const uword SP0X = $d000 + const uword SP0Y = $d001 sub start() { c64.STROUT("balloon sprites!\n") c64.STROUT("...we are all floating...\n") - memcopy(balloonsprite, sprite_data_address, 63) - c64.SPRPTR0 = sprite_data_address//64 - c64.SPRPTR1 = sprite_data_address//64 - c64.SPRPTR2 = sprite_data_address//64 - c64.SPRPTR3 = sprite_data_address//64 - c64.SPRPTR4 = sprite_data_address//64 - c64.SPRPTR5 = sprite_data_address//64 - c64.SPRPTR6 = sprite_data_address//64 - c64.SPRPTR7 = sprite_data_address//64 + c64.SPRPTR0 = $0a00//64 + c64.SPRPTR1 = $0a00//64 + c64.SPRPTR2 = $0a00//64 + c64.SPRPTR3 = $0a00//64 + c64.SPRPTR4 = $0a00//64 + c64.SPRPTR5 = $0a00//64 + c64.SPRPTR6 = $0a00//64 + c64.SPRPTR7 = $0a00//64 for ubyte i in 0 to 7 { @(SP0X+i*2) = 50+25*i diff --git a/compiler/examples/test.p8 b/compiler/examples/test.p8 index 7ae258080..76070bca2 100644 --- a/compiler/examples/test.p8 +++ b/compiler/examples/test.p8 @@ -1,6 +1,8 @@ %import c64utils +%option enable_floats ~ main { + ubyte[3] balloonsprite = [ %00000000,%01111111,%00000000 ] sub start() { @@ -14,8 +16,5 @@ @($d020) = @($d020+i) + 1 @($d020+i) = @($d020+i) + 1 c64scr.print_ub(X) - - i = 2+balloonsprite - } } diff --git a/compiler/src/prog8/ast/AST.kt b/compiler/src/prog8/ast/AST.kt index a0761f874..0311411c4 100644 --- a/compiler/src/prog8/ast/AST.kt +++ b/compiler/src/prog8/ast/AST.kt @@ -523,6 +523,8 @@ class Block(override val name: String, override fun toString(): String { return "Block(name=$name, address=$address, ${statements.size} statements)" } + + val options = statements.filter { it is Directive && it.directive == "%option" }.flatMap { (it as Directive).args }.map {it.name!!}.toSet() } diff --git a/compiler/src/prog8/ast/AstChecker.kt b/compiler/src/prog8/ast/AstChecker.kt index c8560060c..bea8642a5 100644 --- a/compiler/src/prog8/ast/AstChecker.kt +++ b/compiler/src/prog8/ast/AstChecker.kt @@ -617,17 +617,17 @@ class AstChecker(private val namespace: INameScope, err("invalid import directive, cannot import itself") } "%breakpoint" -> { - if(directive.parent is Module) err("this directive may only occur in a block") + if(directive.parent !is Block) err("this directive may only occur in a block") if(directive.args.isNotEmpty()) err("invalid breakpoint directive, expected no arguments") } "%asminclude" -> { - if(directive.parent is Module) err("this directive may only occur in a block") + if(directive.parent !is Block) err("this directive may only occur in a block") if(directive.args.size!=2 || directive.args[0].str==null || directive.args[1].name==null) err("invalid asminclude directive, expected arguments: \"filename\", scopelabel") } "%asmbinary" -> { - if(directive.parent is Module) err("this directive may only occur in a block") + if(directive.parent !is Block) err("this directive may only occur in a block") val errormsg = "invalid asmbinary directive, expected arguments: \"filename\" [, offset [, length ] ]" if(directive.args.isEmpty()) err(errormsg) if(directive.args.isNotEmpty() && directive.args[0].str==null) err(errormsg) @@ -636,8 +636,10 @@ class AstChecker(private val namespace: INameScope, if(directive.args.size>3) err(errormsg) } "%option" -> { - if(directive.parent !is Module) err("this directive may only occur at module level") - if(directive.args.size!=1 || directive.args[0].name != "enable_floats") + if(directive.parent !is Block && directive.parent !is Module) err("this directive may only occur in a block or at module level") + if(directive.args.isEmpty()) + err("missing option directive argument(s)") + else if(directive.args.map{it.name in setOf("enable_floats", "force_output")}.any { !it }) err("invalid option directive argument(s)") } else -> throw SyntaxError("invalid directive ${directive.directive}", directive.position) diff --git a/compiler/src/prog8/compiler/Compiler.kt b/compiler/src/prog8/compiler/Compiler.kt index e97848b66..4274b02a9 100644 --- a/compiler/src/prog8/compiler/Compiler.kt +++ b/compiler/src/prog8/compiler/Compiler.kt @@ -151,7 +151,7 @@ private class StatementTranslator(private val prog: IntermediateProgram, val continueStmtLabelStack : Stack = Stack() override fun process(block: Block): IStatement { - prog.newBlock(block.scopedname, block.name, block.address) + prog.newBlock(block.scopedname, block.name, block.address, block.options) processVariables(block) // @todo optimize initializations with same value: load the value only once (sort on initalization value, datatype ?) prog.label("block."+block.scopedname) prog.line(block.position) diff --git a/compiler/src/prog8/compiler/intermediate/IntermediateProgram.kt b/compiler/src/prog8/compiler/intermediate/IntermediateProgram.kt index 05b839a15..17c44add8 100644 --- a/compiler/src/prog8/compiler/intermediate/IntermediateProgram.kt +++ b/compiler/src/prog8/compiler/intermediate/IntermediateProgram.kt @@ -14,7 +14,8 @@ class IntermediateProgram(val name: String, var loadAddress: Int, val heap: Heap val instructions: MutableList = mutableListOf(), val variables: MutableMap = mutableMapOf(), val memoryPointers: MutableMap> = mutableMapOf(), - val labels: MutableMap = mutableMapOf()) + val labels: MutableMap = mutableMapOf(), + val force_output: Boolean) { val numVariables: Int get() { return variables.size } @@ -368,8 +369,8 @@ class IntermediateProgram(val name: String, var loadAddress: Int, val heap: Heap currentBlock.memoryPointers[name] = Pair(address, datatype) } - fun newBlock(scopedname: String, shortname: String, address: Int?) { - currentBlock = ProgramBlock(scopedname, shortname, address) + fun newBlock(scopedname: String, shortname: String, address: Int?, options: Set) { + currentBlock = ProgramBlock(scopedname, shortname, address, force_output="force_output" in options) blocks.add(currentBlock) } diff --git a/compiler/src/prog8/compiler/target/c64/AsmGen.kt b/compiler/src/prog8/compiler/target/c64/AsmGen.kt index 3b0c0b0f9..2514495ed 100644 --- a/compiler/src/prog8/compiler/target/c64/AsmGen.kt +++ b/compiler/src/prog8/compiler/target/c64/AsmGen.kt @@ -49,7 +49,8 @@ class AsmGen(val options: CompilationOptions, val program: IntermediateProgram, newinstructions, newvars, newConstants, - newlabels)) + newlabels, + force_output = block.force_output)) } program.blocks.clear() program.blocks.addAll(newblocks) @@ -196,7 +197,8 @@ class AsmGen(val options: CompilationOptions, val program: IntermediateProgram, out(".cerror * > ${block.address?.toHex()}, 'block address overlaps by ', *-${block.address?.toHex()},' bytes'") out("* = ${block.address?.toHex()}") } - out("${block.shortname}\t.proc\n") + if(!blk.force_output) + out("${block.shortname}\t.proc\n") out("\n; memdefs and kernel subroutines") memdefs2asm(block) out("\n; variables") @@ -218,7 +220,8 @@ class AsmGen(val options: CompilationOptions, val program: IntermediateProgram, processed-- } if (trace) println("END BLOCK: ${block.scopedname}") - out("\n\t.pend\n") + if(!blk.force_output) + out("\n\t.pend\n") } private fun memdefs2asm(block: IntermediateProgram.ProgramBlock) { diff --git a/docs/source/syntaxreference.rst b/docs/source/syntaxreference.rst index 7c3174b92..f4bc6e534 100644 --- a/docs/source/syntaxreference.rst +++ b/docs/source/syntaxreference.rst @@ -103,11 +103,14 @@ Directives .. data:: %option