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.
This commit is contained in:
Irmen de Jong 2020-03-22 15:12:26 +01:00
parent 7232134931
commit 3a99115070
8 changed files with 75 additions and 63 deletions

View File

@ -19,8 +19,13 @@ class TypecastsAdder(val program: Program, val errors: ErrorReporter) : AstWalke
override fun after(decl: VarDecl, parent: Node): Iterable<IAstModification> {
// 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()
}

View File

@ -73,7 +73,7 @@ class Block(override val name: String,
val idx = statements.indexOf(node)
statements[idx] = replacement
}
val initialValues = mutableListOf<VarDecl>() // will be gathered by one of the Ast processing steps
val initialValues = mutableMapOf<String, VarDecl>() // 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)

View File

@ -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")

View File

@ -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)

View File

@ -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

View File

@ -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

View File

@ -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)

View File

@ -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')
}
}