mirror of
https://github.com/irmen/prog8.git
synced 2024-11-26 11:49:22 +00:00
arrays without init value are once again cleared with zeros
This commit is contained in:
parent
16d7927d2f
commit
17be722e2b
@ -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()
|
||||||
|
@ -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)
|
||||||
|
@ -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")
|
||||||
|
@ -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")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -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)
|
||||||
|
@ -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
|
||||||
-----
|
-----
|
||||||
|
@ -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
|
||||||
---------
|
---------
|
||||||
|
@ -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
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user