arrays without init value are once again cleared with zeros

This commit is contained in:
Irmen de Jong 2019-07-15 23:05:04 +02:00
parent 16d7927d2f
commit 17be722e2b
8 changed files with 101 additions and 126 deletions

View File

@ -93,6 +93,21 @@ private fun prog8Parser.StatementContext.toAst() : IStatement {
) )
} }
structvardecl()?.let {
return VarDecl(
VarDeclType.VAR,
DataType.STRUCT,
ZeropageWish.NOT_IN_ZEROPAGE,
null,
it.varname.text,
it.structname.text,
null,
false,
false,
it.toPosition()
)
}
constdecl()?.let { constdecl()?.let {
val cvarinit = it.varinitializer() val cvarinit = it.varinitializer()
val vd = cvarinit.vardecl() val vd = cvarinit.vardecl()

View File

@ -76,6 +76,11 @@ internal class AstIdentifiersChecker(private val program: Program) : IAstModifyi
if(decl.struct!!.statements.any { (it as VarDecl).datatype !in NumericDatatypes}) if(decl.struct!!.statements.any { (it as VarDecl).datatype !in NumericDatatypes})
return super.visit(decl) // a non-numeric member, not supported. proper error is given by AstChecker later return super.visit(decl) // a non-numeric member, not supported. proper error is given by AstChecker later
if(decl.value is NumericLiteralValue) {
checkResult.add(ExpressionError("you cannot initialize a struct using a single value", decl.position))
return super.visit(decl)
}
val decls = decl.flattenStructMembers() val decls = decl.flattenStructMembers()
decls.add(decl) decls.add(decl)
val result = AnonymousScope(decls, decl.position) val result = AnonymousScope(decls, decl.position)

View File

@ -16,7 +16,7 @@ import java.nio.file.Path
class IntermediateProgram(val name: String, var loadAddress: Int, val heap: HeapValues, val source: Path) { class IntermediateProgram(val name: String, var loadAddress: Int, val heap: HeapValues, val source: Path) {
class VariableParameters (val zp: ZeropageWish, val memberOfStruct: StructDecl?, val uninitializedArraySize: Int?) class VariableParameters (val zp: ZeropageWish, val memberOfStruct: StructDecl?)
class Variable(val scopedname: String, val value: RuntimeValue, val params: VariableParameters) class Variable(val scopedname: String, val value: RuntimeValue, val params: VariableParameters)
class ProgramBlock(val name: String, class ProgramBlock(val name: String,
@ -403,7 +403,7 @@ class IntermediateProgram(val name: String, var loadAddress: Int, val heap: Heap
if(decl.parent is StructDecl) if(decl.parent is StructDecl)
return return
val valueparams = VariableParameters(decl.zeropage, decl.struct, null) val valueparams = VariableParameters(decl.zeropage, decl.struct)
val value = when(decl.datatype) { val value = when(decl.datatype) {
in NumericDatatypes -> { in NumericDatatypes -> {
RuntimeValue(decl.datatype, (decl.value as NumericLiteralValue).number) RuntimeValue(decl.datatype, (decl.value as NumericLiteralValue).number)
@ -421,11 +421,21 @@ class IntermediateProgram(val name: String, var loadAddress: Int, val heap: Heap
if(litval!=null){ if(litval!=null){
RuntimeValue(decl.datatype, heapId = litval.heapId) RuntimeValue(decl.datatype, heapId = litval.heapId)
} else { } else {
// uninitialized array rather than one filled with zero // uninitialized array. fill it with zeros.
val value = RuntimeValue(decl.datatype, heapId=-999) val arraysize = decl.arraysize!!.size()!!
currentBlock.variables.add(Variable(scopedname, value, val heapId =
VariableParameters(ZeropageWish.NOT_IN_ZEROPAGE, null, decl.arraysize!!.size()!!))) when(decl.datatype){
return DataType.ARRAY_UB, DataType.ARRAY_B, DataType.ARRAY_UW, DataType.ARRAY_W -> {
val array = Array(arraysize) { IntegerOrAddressOf(0, null) }
heap.addIntegerArray(decl.datatype, array)
}
DataType.ARRAY_F -> {
val array = DoubleArray(arraysize) { 0.0 }
heap.addDoublesArray(array)
}
else -> throw CompilerException("weird array dt")
}
RuntimeValue(decl.datatype, heapId=heapId)
} }
} }
DataType.STRUCT -> { DataType.STRUCT -> {
@ -533,7 +543,7 @@ class IntermediateProgram(val name: String, var loadAddress: Int, val heap: Heap
throw CompilerException("zp conflict") throw CompilerException("zp conflict")
val valuestr = variable.value.toString() val valuestr = variable.value.toString()
val struct = if(variable.params.memberOfStruct==null) "" else "struct=${variable.params.memberOfStruct.name}" val struct = if(variable.params.memberOfStruct==null) "" else "struct=${variable.params.memberOfStruct.name}"
out.println("${variable.scopedname} ${variable.value.type.name.toLowerCase()} $valuestr zp=${variable.params.zp} s=$struct u=${variable.params.uninitializedArraySize}") out.println("${variable.scopedname} ${variable.value.type.name.toLowerCase()} $valuestr zp=${variable.params.zp} s=$struct")
} }
out.println("%end_variables") out.println("%end_variables")
out.println("%memorypointers") out.println("%memorypointers")

View File

@ -329,9 +329,6 @@ class AsmGen(private val options: CompilationOptions, private val program: Inter
} }
DataType.ARRAY_UB -> { DataType.ARRAY_UB -> {
// unsigned integer byte arraysize // unsigned integer byte arraysize
if(parameters.uninitializedArraySize!=null) {
out("$varname\t.fill ${parameters.uninitializedArraySize}") // uninitialized array
} else {
val data = makeArrayFillDataUnsigned(value) val data = makeArrayFillDataUnsigned(value)
if (data.size <= 16) if (data.size <= 16)
out("$varname\t.byte ${data.joinToString()}") out("$varname\t.byte ${data.joinToString()}")
@ -341,12 +338,8 @@ class AsmGen(private val options: CompilationOptions, private val program: Inter
out(" .byte " + chunk.joinToString()) out(" .byte " + chunk.joinToString())
} }
} }
}
DataType.ARRAY_B -> { DataType.ARRAY_B -> {
// signed integer byte arraysize // signed integer byte arraysize
if(parameters.uninitializedArraySize!=null) {
out("$varname\t.fill ${parameters.uninitializedArraySize}") // uninitialized array
} else {
val data = makeArrayFillDataSigned(value) val data = makeArrayFillDataSigned(value)
if (data.size <= 16) if (data.size <= 16)
out("$varname\t.char ${data.joinToString()}") out("$varname\t.char ${data.joinToString()}")
@ -356,12 +349,8 @@ class AsmGen(private val options: CompilationOptions, private val program: Inter
out(" .char " + chunk.joinToString()) out(" .char " + chunk.joinToString())
} }
} }
}
DataType.ARRAY_UW -> { DataType.ARRAY_UW -> {
// unsigned word arraysize // unsigned word arraysize
if(parameters.uninitializedArraySize!=null) {
out("$varname\t.fill ${parameters.uninitializedArraySize}*2") // uninitialized array
} else {
val data = makeArrayFillDataUnsigned(value) val data = makeArrayFillDataUnsigned(value)
if (data.size <= 16) if (data.size <= 16)
out("$varname\t.word ${data.joinToString()}") out("$varname\t.word ${data.joinToString()}")
@ -371,12 +360,8 @@ class AsmGen(private val options: CompilationOptions, private val program: Inter
out(" .word " + chunk.joinToString()) out(" .word " + chunk.joinToString())
} }
} }
}
DataType.ARRAY_W -> { DataType.ARRAY_W -> {
// signed word arraysize // signed word arraysize
if(parameters.uninitializedArraySize!=null) {
out("$varname\t.fill ${parameters.uninitializedArraySize}*2") // uninitialized array
} else {
val data = makeArrayFillDataSigned(value) val data = makeArrayFillDataSigned(value)
if (data.size <= 16) if (data.size <= 16)
out("$varname\t.sint ${data.joinToString()}") out("$varname\t.sint ${data.joinToString()}")
@ -386,19 +371,14 @@ class AsmGen(private val options: CompilationOptions, private val program: Inter
out(" .sint " + chunk.joinToString()) out(" .sint " + chunk.joinToString())
} }
} }
}
DataType.ARRAY_F -> { DataType.ARRAY_F -> {
// float arraysize // float arraysize
if(parameters.uninitializedArraySize!=null) {
out("$varname\t.fill ${parameters.uninitializedArraySize}*${MachineDefinition.Mflpt5.MemorySize}") // uninitialized array
} else {
val array = heap.get(value.heapId!!).doubleArray!! val array = heap.get(value.heapId!!).doubleArray!!
val floatFills = array.map { makeFloatFill(MachineDefinition.Mflpt5.fromNumber(it)) } val floatFills = array.map { makeFloatFill(MachineDefinition.Mflpt5.fromNumber(it)) }
out(varname) out(varname)
for (f in array.zip(floatFills)) for (f in array.zip(floatFills))
out(" .byte ${f.second} ; float ${f.first}") out(" .byte ${f.second} ; float ${f.first}")
} }
}
DataType.STRUCT -> throw AssemblyError("vars of type STRUCT should have been removed because flattened") DataType.STRUCT -> throw AssemblyError("vars of type STRUCT should have been removed because flattened")
} }
} }

View File

@ -140,7 +140,7 @@ class ConstantFolding(private val program: Program) : IAstModifyingVisitor {
// arraysize initializer is a single int, and we know the size. // arraysize initializer is a single int, and we know the size.
val fillvalue = litval.number.toDouble() val fillvalue = litval.number.toDouble()
if (fillvalue < FLOAT_MAX_NEGATIVE || fillvalue > FLOAT_MAX_POSITIVE) if (fillvalue < FLOAT_MAX_NEGATIVE || fillvalue > FLOAT_MAX_POSITIVE)
errors.add(ExpressionError("float value overflow", litval.position ?: decl.position)) errors.add(ExpressionError("float value overflow", litval.position))
else { else {
val heapId = program.heap.addDoublesArray(DoubleArray(size) { fillvalue }) val heapId = program.heap.addDoublesArray(DoubleArray(size) { fillvalue })
decl.value = ReferenceLiteralValue(DataType.ARRAY_F, initHeapId = heapId, position = litval.position) decl.value = ReferenceLiteralValue(DataType.ARRAY_F, initHeapId = heapId, position = litval.position)

View File

@ -237,6 +237,7 @@ Arrays
^^^^^^ ^^^^^^
Array types are also supported. They can be made of bytes, words or floats:: Array types are also supported. They can be made of bytes, words or floats::
byte[10] array ; array of 10 bytes, initially set to 0
byte[] array = [1, 2, 3, 4] ; initialize the array, size taken from value byte[] array = [1, 2, 3, 4] ; initialize the array, size taken from value
byte[99] array = 255 ; initialize array with 99 times 255 [255, 255, 255, 255, ...] byte[99] array = 255 ; initialize array with 99 times 255 [255, 255, 255, 255, ...]
byte[] array = 100 to 199 ; initialize array with [100, 101, ..., 198, 199] byte[] array = 100 to 199 ; initialize array with [100, 101, ..., 198, 199]
@ -285,9 +286,9 @@ Structs are a bit limited in Prog8: you can only use numerical variables
as member of a struct, so strings and arrays and other structs can not be part of a struct. as member of a struct, so strings and arrays and other structs can not be part of a struct.
Also, it is not possible to use a struct itself inside an array. Also, it is not possible to use a struct itself inside an array.
Structs are mainly syntactic sugar for repeated groups of vardecls Structs are mainly syntactic sugar for repeated groups of vardecls
and assignments that belong together. However, *they are layed out and assignments that belong together. However,
in sequence in memory as the members are defined* which may be useful *they are layed out in sequence in memory as the members are defined*
if you want to pass pointers around which may be usefulif you want to pass pointers around.
To create a variable of a struct type you need to define the struct itself, To create a variable of a struct type you need to define the struct itself,
and then create a variable with it:: and then create a variable with it::
@ -298,7 +299,7 @@ and then create a variable with it::
ubyte blue ubyte blue
} }
Color rgb = [255,122,0] Color rgb = {255,122,0} ; note the curly braces here instead of brackets
Color another ; the init value is optional, like arrays Color another ; the init value is optional, like arrays
another = rgb ; assign all of the values of rgb to another another = rgb ; assign all of the values of rgb to another
@ -354,10 +355,17 @@ 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 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, the program reaches the declaration again. This can be in loops, multiple subroutine calls,
or even multiple invocations of the entire program. If you omit an initial value, it will or even multiple invocations of the entire program. If you omit an initial value, it will
be set to zero only for the first run of the program. A second run will utilize the last value 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 where it left off (but your code will be a bit smaller because no initialization instructions
are generated) are generated)
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
a second run.
If you do modify them in-place, you should take care yourself that they work as
expected when the program is restarted.
(This is an optimization choice to avoid having to store two copies of every string and array)
.. caution:: .. caution::
variables that get allocated in zero-page will *not* have a zero starting value when you omit variables that get allocated in zero-page will *not* have a zero starting value when you omit
the variable's initialization. They'll be whatever the last value in that zero page the variable's initialization. They'll be whatever the last value in that zero page
@ -367,12 +375,6 @@ are generated)
this behavior may change in a future version so that subsequent runs always this behavior may change in a future version so that subsequent runs always
use the same initial values use the same initial values
This only works for simple types, *and not for string variables and arrays*.
It is assumed these are left unchanged by the program.
If you do modify them in-place, you should take care yourself that they work as
expected when the program is restarted.
(This is an optimization choice to avoid having to store two copies of every string and array)
Loops Loops
----- -----

View File

@ -231,10 +231,11 @@ Various examples::
str name = "my name is Irmen" str name = "my name is Irmen"
uword address = &counter uword address = &counter
byte[] values = [11, 22, 33, 44, 55] byte[] values = [11, 22, 33, 44, 55]
byte[5] values ; array of 5 bytes, initially set to zero
byte[5] values = 255 ; initialize with five 255 bytes byte[5] values = 255 ; initialize with five 255 bytes
word @zp zpword = 9999 ; prioritize this when selecting vars for zeropage storage word @zp zpword = 9999 ; prioritize this when selecting vars for zeropage storage
Color rgb = [1,255,0] ; a struct variable Color rgb = {1,255,0} ; a struct variable with initial values
Data types Data types
@ -374,6 +375,10 @@ and other structs can not be part of a struct. Vice versa, a struct can not occu
After defining a struct you can use the name of the struct as a data type to declare variables with. After defining a struct you can use the name of the struct as a data type to declare variables with.
Struct variables can be assigned a struct literal value (also in their declaration as initial value)::
Color rgb = {255, 100, 0} ; curly braces instead of brackets
Operators Operators
--------- ---------

View File

@ -5,60 +5,18 @@
~ main { ~ main {
struct Color {
word red
byte green
float blue
}
sub start() { sub start() {
byte[] array=[1,2,3,4,5] Color rgb1
word[5] warray Color rgb2
float[5] flarray
warray[0]=flarray[0] as word c64scr.print_b(rgb1.green)
c64scr.print_b(rgb2.green)
ubyte length = len(array)
c64scr.print_ub(length)
c64.CHROUT(',')
ubyte length1 = any(array)
c64scr.print_ub(length1)
c64.CHROUT(',')
ubyte length1b = all(array)
c64scr.print_ub(length1b)
c64.CHROUT(',')
ubyte length1c = max(array)
c64scr.print_ub(length1c)
c64.CHROUT(',')
ubyte length1d = min(array)
c64scr.print_ub(length1d)
c64.CHROUT(',')
ubyte xlength = len([1,2,3])
c64scr.print_ub(xlength)
c64.CHROUT('\n')
ubyte xlength1 = any([1,0,3])
c64scr.print_ub(xlength1)
c64.CHROUT(',')
ubyte xlength1b = all([1,0,3])
c64scr.print_ub(xlength1b)
c64.CHROUT(',')
ubyte xlength1c = max([1,2,3])
c64scr.print_ub(xlength1c)
c64.CHROUT(',')
ubyte xlength1d = min([1,2,3])
c64scr.print_ub(xlength1d)
c64.CHROUT('\n')
word s1 = sum(array)
c64scr.print_w(s1)
c64.CHROUT(',')
uword s2 = sum([1,23])
c64scr.print_uw(s2)
c64.CHROUT(',')
float ff1=avg(array)
c64flt.print_f(ff1)
c64.CHROUT(',')
float ff2=avg([1,2,3])
c64flt.print_f(ff2)
c64.CHROUT('\n')
return
} }
} }