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 {
val cvarinit = it.varinitializer()
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})
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()
decls.add(decl)
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 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 ProgramBlock(val name: String,
@ -403,7 +403,7 @@ class IntermediateProgram(val name: String, var loadAddress: Int, val heap: Heap
if(decl.parent is StructDecl)
return
val valueparams = VariableParameters(decl.zeropage, decl.struct, null)
val valueparams = VariableParameters(decl.zeropage, decl.struct)
val value = when(decl.datatype) {
in NumericDatatypes -> {
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){
RuntimeValue(decl.datatype, heapId = litval.heapId)
} else {
// uninitialized array rather than one filled with zero
val value = RuntimeValue(decl.datatype, heapId=-999)
currentBlock.variables.add(Variable(scopedname, value,
VariableParameters(ZeropageWish.NOT_IN_ZEROPAGE, null, decl.arraysize!!.size()!!)))
return
// uninitialized array. fill it with zeros.
val arraysize = decl.arraysize!!.size()!!
val heapId =
when(decl.datatype){
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 -> {
@ -533,7 +543,7 @@ class IntermediateProgram(val name: String, var loadAddress: Int, val heap: Heap
throw CompilerException("zp conflict")
val valuestr = variable.value.toString()
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("%memorypointers")

View File

@ -329,75 +329,55 @@ class AsmGen(private val options: CompilationOptions, private val program: Inter
}
DataType.ARRAY_UB -> {
// unsigned integer byte arraysize
if(parameters.uninitializedArraySize!=null) {
out("$varname\t.fill ${parameters.uninitializedArraySize}") // uninitialized array
} else {
val data = makeArrayFillDataUnsigned(value)
if (data.size <= 16)
out("$varname\t.byte ${data.joinToString()}")
else {
out(varname)
for (chunk in data.chunked(16))
out(" .byte " + chunk.joinToString())
}
val data = makeArrayFillDataUnsigned(value)
if (data.size <= 16)
out("$varname\t.byte ${data.joinToString()}")
else {
out(varname)
for (chunk in data.chunked(16))
out(" .byte " + chunk.joinToString())
}
}
DataType.ARRAY_B -> {
// signed integer byte arraysize
if(parameters.uninitializedArraySize!=null) {
out("$varname\t.fill ${parameters.uninitializedArraySize}") // uninitialized array
} else {
val data = makeArrayFillDataSigned(value)
if (data.size <= 16)
out("$varname\t.char ${data.joinToString()}")
else {
out(varname)
for (chunk in data.chunked(16))
out(" .char " + chunk.joinToString())
}
val data = makeArrayFillDataSigned(value)
if (data.size <= 16)
out("$varname\t.char ${data.joinToString()}")
else {
out(varname)
for (chunk in data.chunked(16))
out(" .char " + chunk.joinToString())
}
}
DataType.ARRAY_UW -> {
// unsigned word arraysize
if(parameters.uninitializedArraySize!=null) {
out("$varname\t.fill ${parameters.uninitializedArraySize}*2") // uninitialized array
} else {
val data = makeArrayFillDataUnsigned(value)
if (data.size <= 16)
out("$varname\t.word ${data.joinToString()}")
else {
out(varname)
for (chunk in data.chunked(16))
out(" .word " + chunk.joinToString())
}
val data = makeArrayFillDataUnsigned(value)
if (data.size <= 16)
out("$varname\t.word ${data.joinToString()}")
else {
out(varname)
for (chunk in data.chunked(16))
out(" .word " + chunk.joinToString())
}
}
DataType.ARRAY_W -> {
// signed word arraysize
if(parameters.uninitializedArraySize!=null) {
out("$varname\t.fill ${parameters.uninitializedArraySize}*2") // uninitialized array
} else {
val data = makeArrayFillDataSigned(value)
if (data.size <= 16)
out("$varname\t.sint ${data.joinToString()}")
else {
out(varname)
for (chunk in data.chunked(16))
out(" .sint " + chunk.joinToString())
}
val data = makeArrayFillDataSigned(value)
if (data.size <= 16)
out("$varname\t.sint ${data.joinToString()}")
else {
out(varname)
for (chunk in data.chunked(16))
out(" .sint " + chunk.joinToString())
}
}
DataType.ARRAY_F -> {
// 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 floatFills = array.map { makeFloatFill(MachineDefinition.Mflpt5.fromNumber(it)) }
out(varname)
for (f in array.zip(floatFills))
out(" .byte ${f.second} ; float ${f.first}")
}
val array = heap.get(value.heapId!!).doubleArray!!
val floatFills = array.map { makeFloatFill(MachineDefinition.Mflpt5.fromNumber(it)) }
out(varname)
for (f in array.zip(floatFills))
out(" .byte ${f.second} ; float ${f.first}")
}
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.
val fillvalue = litval.number.toDouble()
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 {
val heapId = program.heap.addDoublesArray(DoubleArray(size) { fillvalue })
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::
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[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]
@ -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.
Also, it is not possible to use a struct itself inside an array.
Structs are mainly syntactic sugar for repeated groups of vardecls
and assignments that belong together. However, *they are layed out
in sequence in memory as the members are defined* which may be useful
if you want to pass pointers around
and assignments that belong together. However,
*they are layed out in sequence in memory as the members are defined*
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,
and then create a variable with it::
@ -298,7 +299,7 @@ and then create a variable with it::
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
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
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
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
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::
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
@ -367,12 +375,6 @@ are generated)
this behavior may change in a future version so that subsequent runs always
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
-----

View File

@ -231,10 +231,11 @@ Various examples::
str name = "my name is Irmen"
uword address = &counter
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
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
@ -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.
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
---------

View File

@ -5,60 +5,18 @@
~ main {
struct Color {
word red
byte green
float blue
}
sub start() {
byte[] array=[1,2,3,4,5]
word[5] warray
float[5] flarray
Color rgb1
Color rgb2
warray[0]=flarray[0] as word
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
c64scr.print_b(rgb1.green)
c64scr.print_b(rgb2.green)
}
}