From 3a99115070462407ebc03fcd2da648f0fb275142 Mon Sep 17 00:00:00 2001 From: Irmen de Jong Date: Sun, 22 Mar 2020 15:12:26 +0100 Subject: [PATCH] Initial variable values semantics changed: now always sets value at program (re)start (except strings/arrays). This may change later by introducing a compiler option to choose a strategy, perhaps. --- .../prog8/ast/processing/TypecastsAdder.kt | 9 +- .../src/prog8/ast/statements/AstStatements.kt | 2 +- .../compiler/target/c64/codegen/AsmGen.kt | 8 +- .../target/c64/codegen/ExpressionsAsmGen.kt | 2 + docs/source/programming.rst | 13 +-- docs/source/syntaxreference.rst | 5 +- docs/source/todo.rst | 4 +- examples/test.p8 | 95 +++++++++++-------- 8 files changed, 75 insertions(+), 63 deletions(-) diff --git a/compiler/src/prog8/ast/processing/TypecastsAdder.kt b/compiler/src/prog8/ast/processing/TypecastsAdder.kt index 6b7b1122d..831a94a8c 100644 --- a/compiler/src/prog8/ast/processing/TypecastsAdder.kt +++ b/compiler/src/prog8/ast/processing/TypecastsAdder.kt @@ -19,8 +19,13 @@ class TypecastsAdder(val program: Program, val errors: ErrorReporter) : AstWalke override fun after(decl: VarDecl, parent: Node): Iterable { // collect all variables that have an initialisation value - if(decl.value!=null && decl.type== VarDeclType.VAR && decl.datatype in NumericDatatypes) - decl.definingBlock().initialValues += decl + val declValue = decl.value + if(declValue!=null + && decl.type== VarDeclType.VAR + && decl.datatype in NumericDatatypes + && declValue.constValue(program)!=null) { + decl.definingBlock().initialValues[decl.scopedname] = decl + } return emptyList() } diff --git a/compiler/src/prog8/ast/statements/AstStatements.kt b/compiler/src/prog8/ast/statements/AstStatements.kt index 3af07dac3..778effe61 100644 --- a/compiler/src/prog8/ast/statements/AstStatements.kt +++ b/compiler/src/prog8/ast/statements/AstStatements.kt @@ -73,7 +73,7 @@ class Block(override val name: String, val idx = statements.indexOf(node) statements[idx] = replacement } - val initialValues = mutableListOf() // will be gathered by one of the Ast processing steps + val initialValues = mutableMapOf() // will be gathered by one of the Ast processing steps override fun accept(visitor: IAstModifyingVisitor) = visitor.visit(this) override fun accept(visitor: IAstVisitor) = visitor.visit(this) diff --git a/compiler/src/prog8/compiler/target/c64/codegen/AsmGen.kt b/compiler/src/prog8/compiler/target/c64/codegen/AsmGen.kt index 49e4fd43e..b551feb4e 100644 --- a/compiler/src/prog8/compiler/target/c64/codegen/AsmGen.kt +++ b/compiler/src/prog8/compiler/target/c64/codegen/AsmGen.kt @@ -175,10 +175,10 @@ internal class AsmGen(private val program: Program, // it will be called from program init. if(block.initialValues.isNotEmpty()) { out("prog8_init_vars\t.proc\n") - block.initialValues.forEach { - val target = AssignTarget(null, IdentifierReference(listOf(it.scopedname), it.position), null, null, it.position) - val assign = Assignment(target, null, it.value!!, it.position) - assign.linkParents(it.parent) + block.initialValues.forEach { (scopedName, decl) -> + val target = AssignTarget(null, IdentifierReference(scopedName.split('.'), decl.position), null, null, decl.position) + val assign = Assignment(target, null, decl.value!!, decl.position) + assign.linkParents(decl.parent) assignmentAsmGen.translate(assign) } out(" rts\n .pend") diff --git a/compiler/src/prog8/compiler/target/c64/codegen/ExpressionsAsmGen.kt b/compiler/src/prog8/compiler/target/c64/codegen/ExpressionsAsmGen.kt index 84b064ed6..799592d63 100644 --- a/compiler/src/prog8/compiler/target/c64/codegen/ExpressionsAsmGen.kt +++ b/compiler/src/prog8/compiler/target/c64/codegen/ExpressionsAsmGen.kt @@ -198,6 +198,7 @@ internal class ExpressionsAsmGen(private val program: Program, private val asmge when(expr.operator) { ">>" -> { // bit-shifts are always by a constant number (for now) + // TODO for everything except UBYTE, if shifting > 2 bits, use a subroutine translateExpression(expr.left) val amount = expr.right.constValue(program)!!.number.toInt() when (leftDt) { @@ -211,6 +212,7 @@ internal class ExpressionsAsmGen(private val program: Program, private val asmge } "<<" -> { // bit-shifts are always by a constant number (for now) + // TODO for the word types, if shifting > 3 bits, use a subroutine translateExpression(expr.left) val amount = expr.right.constValue(program)!!.number.toInt() if (leftDt in ByteDatatypes) diff --git a/docs/source/programming.rst b/docs/source/programming.rst index ca2f77ecf..71a29de45 100644 --- a/docs/source/programming.rst +++ b/docs/source/programming.rst @@ -369,18 +369,7 @@ Initial values across multiple runs of the program When declaring values with an initial value, this value will be set into the variable each time the program reaches the declaration again. This can be in loops, multiple subroutine calls, or even multiple invocations of the entire program. - -.. sidebar:: - Zeroing not for ZP - - If a variable gets allocated in zero-page, it will *not* be set to zero for you at - the start of the program. Instead, it will simply be whatever the last value in that zero page - location was. Code should not depend on the uninitialized starting value of such variables. - -If you omit an initial value, it will -be set to zero *but only for the first run of the program*. A second run will utilize the last value -where it left off (but your code will be a bit smaller because no initialization instructions -are generated) +If you omit the initial value, zero will be used instead. This only works for simple types, *and not for string variables and arrays*. It is assumed these are left unchanged by the program; they are not re-initialized on diff --git a/docs/source/syntaxreference.rst b/docs/source/syntaxreference.rst index 796854d1f..9f36ff03b 100644 --- a/docs/source/syntaxreference.rst +++ b/docs/source/syntaxreference.rst @@ -216,7 +216,8 @@ Variable declarations Variables should be declared with their exact type and size so the compiler can allocate storage for them. You can give them an initial value as well. That value can be a simple literal value, -or an expression. You can add a ``@zp`` zeropage-tag, to tell the compiler to prioritize it +or an expression. If you don't provide an intial value yourself, zero will be used. +You can add a ``@zp`` zeropage-tag, to tell the compiler to prioritize it when selecting variables to be put into zeropage. The syntax is:: @@ -321,7 +322,7 @@ Constants ^^^^^^^^^ All variables can be assigned new values unless you use the ``const`` keyword. -The initial value will now be evaluated at compile time (it must be a compile time constant expression). +The initial value must be known at compile time (it must be a compile time constant expression). This is only valid for the simple numeric types (byte, word, float):: const byte max_age = 99 diff --git a/docs/source/todo.rst b/docs/source/todo.rst index 0e8ffeb7b..b521d044c 100644 --- a/docs/source/todo.rst +++ b/docs/source/todo.rst @@ -4,7 +4,9 @@ TODO - remove statements after an exit() or return - fix warnings about that unreachable code? -- why are some programs for example cube3d increasing in size when compiling with optimizations??? + +- add a compiler option to not include variable initialization code (useful if the program is expected to run only once, such as a game) + the program will then rely solely on the values as they are in memory at the time of program startup. - create real assembly routines for the bresenham line and circle code - also add assembly routines in c64scr for drawing rectangles (filled/open) diff --git a/examples/test.p8 b/examples/test.p8 index 0d3a71279..30b878095 100644 --- a/examples/test.p8 +++ b/examples/test.p8 @@ -1,55 +1,68 @@ %import c64utils ;%import c64flt ;%option enable_floats -%zeropage basicsafe +%zeropage dontuse main { + sub subje() { + ubyte xyz = 123 + ubyte foo + c64scr.print_ub(xyz) + c64.CHROUT('\n') + c64scr.print_ub(foo) + c64.CHROUT('\n') + xyz++ + foo++ + } + sub start() { ubyte xyz = 99 ; TODO fix compiler error when removing unused var word wcosa = cos8(xyz) word wcosa_sinb = wcosa / 128 - ; TODO fix too much assembly in prog8_init_vars + subje() + subje() + subje() - ubyte ub1 - ubyte ub2 = 99 - uword uw1 - uword uw2 = 9999 - ubyte[5] array1 - ubyte[5] array2 = [22,33,44,55,66] - - c64scr.print_ub(ub1) - c64.CHROUT(',') - c64scr.print_ub(ub2) - c64.CHROUT(',') - c64scr.print_uw(uw1) - c64.CHROUT(',') - c64scr.print_uw(uw2) - c64.CHROUT(',') - c64scr.print_ub(array1[0]) - c64.CHROUT(',') - c64scr.print_ub(array2[0]) - c64.CHROUT('\n') - - ub1++ - ub2++ - uw1++ - uw2++ - array1[0]++ - array2[0]++ - - c64scr.print_ub(ub1) - c64.CHROUT(',') - c64scr.print_ub(ub2) - c64.CHROUT(',') - c64scr.print_uw(uw1) - c64.CHROUT(',') - c64scr.print_uw(uw2) - c64.CHROUT(',') - c64scr.print_ub(array1[0]) - c64.CHROUT(',') - c64scr.print_ub(array2[0]) - c64.CHROUT('\n') +; ubyte ub1 +; ubyte ub2 = 99 +; uword uw1 +; uword uw2 = 9999 +; ubyte[5] array1 +; ubyte[5] array2 = [22,33,44,55,66] +; +; c64scr.print_ub(ub1) +; c64.CHROUT(',') +; c64scr.print_ub(ub2) +; c64.CHROUT(',') +; c64scr.print_uw(uw1) +; c64.CHROUT(',') +; c64scr.print_uw(uw2) +; c64.CHROUT(',') +; c64scr.print_ub(array1[0]) +; c64.CHROUT(',') +; c64scr.print_ub(array2[0]) +; c64.CHROUT('\n') +; +; ub1++ +; ub2++ +; uw1++ +; uw2++ +; array1[0]++ +; array2[0]++ +; +; c64scr.print_ub(ub1) +; c64.CHROUT(',') +; c64scr.print_ub(ub2) +; c64.CHROUT(',') +; c64scr.print_uw(uw1) +; c64.CHROUT(',') +; c64scr.print_uw(uw2) +; c64.CHROUT(',') +; c64scr.print_ub(array1[0]) +; c64.CHROUT(',') +; c64scr.print_ub(array2[0]) +; c64.CHROUT('\n') } }