mirror of
https://github.com/irmen/prog8.git
synced 2024-11-23 07:32:10 +00:00
unravel more dependency of SymbolTable on the ASt nodes (Expression), and fix initializing zp-allocated array
This commit is contained in:
parent
a58e5a3399
commit
5a54066f81
@ -751,7 +751,7 @@ $repeatLabel lda $counterVar
|
|||||||
val counterVar = makeLabel("counter")
|
val counterVar = makeLabel("counter")
|
||||||
when(dt) {
|
when(dt) {
|
||||||
DataType.UBYTE, DataType.UWORD -> {
|
DataType.UBYTE, DataType.UWORD -> {
|
||||||
val result = zeropage.allocate(listOf(counterVar), dt, null, null, stmt.position, errors)
|
val result = zeropage.allocate(listOf(counterVar), dt, null, stmt.position, errors)
|
||||||
result.fold(
|
result.fold(
|
||||||
success = { (address, _) -> asmInfo.extraVars.add(Triple(dt, counterVar, address)) },
|
success = { (address, _) -> asmInfo.extraVars.add(Triple(dt, counterVar, address)) },
|
||||||
failure = { asmInfo.extraVars.add(Triple(dt, counterVar, null)) } // allocate normally
|
failure = { asmInfo.extraVars.add(Triple(dt, counterVar, null)) } // allocate normally
|
||||||
|
@ -292,7 +292,7 @@ $loopLabel sty $indexVar
|
|||||||
}
|
}
|
||||||
if(length>=16) {
|
if(length>=16) {
|
||||||
// allocate index var on ZP if possible
|
// allocate index var on ZP if possible
|
||||||
val result = zeropage.allocate(listOf(indexVar), DataType.UBYTE, null, null, stmt.position, asmgen.errors)
|
val result = zeropage.allocate(listOf(indexVar), DataType.UBYTE, null, stmt.position, asmgen.errors)
|
||||||
result.fold(
|
result.fold(
|
||||||
success = { (address,_)-> asmgen.out("""$indexVar = $address ; auto zp UBYTE""") },
|
success = { (address,_)-> asmgen.out("""$indexVar = $address ; auto zp UBYTE""") },
|
||||||
failure = { asmgen.out("$indexVar .byte 0") }
|
failure = { asmgen.out("$indexVar .byte 0") }
|
||||||
@ -333,7 +333,7 @@ $loopLabel sty $indexVar
|
|||||||
}
|
}
|
||||||
if(length>=16) {
|
if(length>=16) {
|
||||||
// allocate index var on ZP if possible
|
// allocate index var on ZP if possible
|
||||||
val result = zeropage.allocate(listOf(indexVar), DataType.UBYTE, null, null, stmt.position, asmgen.errors)
|
val result = zeropage.allocate(listOf(indexVar), DataType.UBYTE, null, stmt.position, asmgen.errors)
|
||||||
result.fold(
|
result.fold(
|
||||||
success = { (address,_)-> asmgen.out("""$indexVar = $address ; auto zp UBYTE""") },
|
success = { (address,_)-> asmgen.out("""$indexVar = $address ; auto zp UBYTE""") },
|
||||||
failure = { asmgen.out("$indexVar .byte 0") }
|
failure = { asmgen.out("$indexVar .byte 0") }
|
||||||
|
@ -2,8 +2,10 @@ package prog8.codegen.cpu6502
|
|||||||
|
|
||||||
import prog8.ast.Program
|
import prog8.ast.Program
|
||||||
import prog8.ast.antlr.escape
|
import prog8.ast.antlr.escape
|
||||||
import prog8.ast.base.*
|
import prog8.ast.base.ArrayDatatypes
|
||||||
import prog8.ast.expressions.*
|
import prog8.ast.base.ByteDatatypes
|
||||||
|
import prog8.ast.base.DataType
|
||||||
|
import prog8.ast.base.RegisterOrPair
|
||||||
import prog8.ast.statements.*
|
import prog8.ast.statements.*
|
||||||
import prog8.ast.toHex
|
import prog8.ast.toHex
|
||||||
import prog8.codegen.cpu6502.assignment.AsmAssignTarget
|
import prog8.codegen.cpu6502.assignment.AsmAssignTarget
|
||||||
@ -377,12 +379,12 @@ internal class ProgramAndVarsGen(
|
|||||||
}
|
}
|
||||||
|
|
||||||
// string and array variables in zeropage that have initializer value, should be initialized
|
// string and array variables in zeropage that have initializer value, should be initialized
|
||||||
val stringVarsWithInitInZp = allocator.zeropageVars.filter { it.value.dt==DataType.STR && it.value.initialStringValue!=null }
|
val stringVarsWithInitInZp = getZpStringVarsWithInitvalue()
|
||||||
val arrayVarsWithInitInZp = allocator.zeropageVars.filter { it.value.dt in ArrayDatatypes && it.value.initialArrayValue!=null }
|
val arrayVarsWithInitInZp = getZpArrayVarsWithInitvalue()
|
||||||
if(stringVarsWithInitInZp.isNotEmpty() || arrayVarsWithInitInZp.isNotEmpty()) {
|
if(stringVarsWithInitInZp.isNotEmpty() || arrayVarsWithInitInZp.isNotEmpty()) {
|
||||||
asmgen.out("; zp str and array initializations")
|
asmgen.out("; zp str and array initializations")
|
||||||
stringVarsWithInitInZp.forEach {
|
stringVarsWithInitInZp.forEach {
|
||||||
val name = asmgen.asmVariableName(it.key)
|
val name = asmgen.asmVariableName(it.name)
|
||||||
asmgen.out("""
|
asmgen.out("""
|
||||||
lda #<${name}
|
lda #<${name}
|
||||||
ldy #>${name}
|
ldy #>${name}
|
||||||
@ -393,8 +395,8 @@ internal class ProgramAndVarsGen(
|
|||||||
jsr prog8_lib.strcpy""")
|
jsr prog8_lib.strcpy""")
|
||||||
}
|
}
|
||||||
arrayVarsWithInitInZp.forEach {
|
arrayVarsWithInitInZp.forEach {
|
||||||
val size = it.value.size
|
val size = it.alloc.size
|
||||||
val name = asmgen.asmVariableName(it.key)
|
val name = asmgen.asmVariableName(it.name)
|
||||||
asmgen.out("""
|
asmgen.out("""
|
||||||
lda #<${name}_init_value
|
lda #<${name}_init_value
|
||||||
ldy #>${name}_init_value
|
ldy #>${name}_init_value
|
||||||
@ -412,14 +414,13 @@ internal class ProgramAndVarsGen(
|
|||||||
}
|
}
|
||||||
|
|
||||||
stringVarsWithInitInZp.forEach {
|
stringVarsWithInitInZp.forEach {
|
||||||
val varname = asmgen.asmVariableName(it.key)+"_init_value"
|
val varname = asmgen.asmVariableName(it.name)+"_init_value"
|
||||||
val stringvalue = it.value.initialStringValue!!
|
outputStringvar(varname, it.value.second, it.value.first)
|
||||||
outputStringvar(varname, it.value.dt, stringvalue.encoding, stringvalue.value)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
arrayVarsWithInitInZp.forEach {
|
arrayVarsWithInitInZp.forEach {
|
||||||
val varname = asmgen.asmVariableName(it.key)+"_init_value"
|
val varname = asmgen.asmVariableName(it.name)+"_init_value"
|
||||||
arrayVariable2asm(varname, it.value.dt, it.value.initialArrayValue!!, null)
|
arrayVariable2asm(varname, it.alloc.dt, it.value, null)
|
||||||
}
|
}
|
||||||
|
|
||||||
asmgen.out("""+ tsx
|
asmgen.out("""+ tsx
|
||||||
@ -429,6 +430,40 @@ internal class ProgramAndVarsGen(
|
|||||||
clc""")
|
clc""")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private class ZpStringWithInitial(
|
||||||
|
val name: List<String>,
|
||||||
|
val alloc: Zeropage.ZpAllocation,
|
||||||
|
val value: Pair<String, Encoding>
|
||||||
|
)
|
||||||
|
|
||||||
|
private class ZpArrayWithInitial(
|
||||||
|
val name: List<String>,
|
||||||
|
val alloc: Zeropage.ZpAllocation,
|
||||||
|
val value: DoubleArray
|
||||||
|
)
|
||||||
|
|
||||||
|
private fun getZpStringVarsWithInitvalue(): Collection<ZpStringWithInitial> {
|
||||||
|
val result = mutableListOf<ZpStringWithInitial>()
|
||||||
|
val vars = allocator.zeropageVars.filter { it.value.dt==DataType.STR }
|
||||||
|
for (variable in vars) {
|
||||||
|
val svar = symboltable.lookup(variable.key) as StStaticVariable // TODO faster in flat lookup table
|
||||||
|
if(svar.initialStringValue!=null)
|
||||||
|
result.add(ZpStringWithInitial(variable.key, variable.value, svar.initialStringValue!!))
|
||||||
|
}
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun getZpArrayVarsWithInitvalue(): Collection<ZpArrayWithInitial> {
|
||||||
|
val result = mutableListOf<ZpArrayWithInitial>()
|
||||||
|
val vars = allocator.zeropageVars.filter { it.value.dt in ArrayDatatypes }
|
||||||
|
for (variable in vars) {
|
||||||
|
val svar = symboltable.lookup(variable.key) as StStaticVariable // TODO faster in flat lookup table
|
||||||
|
if(svar.initialArrayValue!=null)
|
||||||
|
result.add(ZpArrayWithInitial(variable.key, variable.value, svar.initialArrayValue!!))
|
||||||
|
}
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
|
||||||
private fun zeropagevars2asm(varNames: Set<List<String>>) {
|
private fun zeropagevars2asm(varNames: Set<List<String>>) {
|
||||||
val zpVariables = allocator.zeropageVars.filter { it.key in varNames }
|
val zpVariables = allocator.zeropageVars.filter { it.key in varNames }
|
||||||
for ((scopedName, zpvar) in zpVariables) {
|
for ((scopedName, zpvar) in zpVariables) {
|
||||||
@ -443,8 +478,7 @@ internal class ProgramAndVarsGen(
|
|||||||
asmgen.out("; non-zeropage variables")
|
asmgen.out("; non-zeropage variables")
|
||||||
val (stringvars, othervars) = variables.partition { it.dt==DataType.STR }
|
val (stringvars, othervars) = variables.partition { it.dt==DataType.STR }
|
||||||
stringvars.forEach {
|
stringvars.forEach {
|
||||||
val stringvalue = it.initialvalue as StringLiteral
|
outputStringvar(it.name, it.initialStringValue!!.second, it.initialStringValue!!.first)
|
||||||
outputStringvar(it.name, it.dt, stringvalue.encoding, stringvalue.value)
|
|
||||||
}
|
}
|
||||||
othervars.sortedBy { it.type }.forEach {
|
othervars.sortedBy { it.type }.forEach {
|
||||||
staticVariable2asm(it)
|
staticVariable2asm(it)
|
||||||
@ -453,45 +487,38 @@ internal class ProgramAndVarsGen(
|
|||||||
|
|
||||||
private fun staticVariable2asm(variable: StStaticVariable) {
|
private fun staticVariable2asm(variable: StStaticVariable) {
|
||||||
val name = variable.name
|
val name = variable.name
|
||||||
val value = variable.initialvalue
|
val initialValue: Number =
|
||||||
val staticValue: Number =
|
if(variable.initialNumericValue!=null) {
|
||||||
if(value!=null) {
|
if(variable.dt== DataType.FLOAT)
|
||||||
if(value is NumericLiteral) {
|
variable.initialNumericValue!!
|
||||||
if(value.type== DataType.FLOAT)
|
|
||||||
value.number
|
|
||||||
else
|
else
|
||||||
value.number.toInt()
|
variable.initialNumericValue!!.toInt()
|
||||||
} else {
|
|
||||||
if(variable.dt in NumericDatatypes)
|
|
||||||
throw AssemblyError("can only deal with constant numeric values for global vars")
|
|
||||||
else 0
|
|
||||||
}
|
|
||||||
} else 0
|
} else 0
|
||||||
|
|
||||||
when (variable.dt) {
|
when (variable.dt) {
|
||||||
DataType.UBYTE -> asmgen.out("$name\t.byte ${staticValue.toHex()}")
|
DataType.UBYTE -> asmgen.out("$name\t.byte ${initialValue.toHex()}")
|
||||||
DataType.BYTE -> asmgen.out("$name\t.char $staticValue")
|
DataType.BYTE -> asmgen.out("$name\t.char $initialValue")
|
||||||
DataType.UWORD -> asmgen.out("$name\t.word ${staticValue.toHex()}")
|
DataType.UWORD -> asmgen.out("$name\t.word ${initialValue.toHex()}")
|
||||||
DataType.WORD -> asmgen.out("$name\t.sint $staticValue")
|
DataType.WORD -> asmgen.out("$name\t.sint $initialValue")
|
||||||
DataType.FLOAT -> {
|
DataType.FLOAT -> {
|
||||||
if(staticValue==0) {
|
if(initialValue==0) {
|
||||||
asmgen.out("$name\t.byte 0,0,0,0,0 ; float")
|
asmgen.out("$name\t.byte 0,0,0,0,0 ; float")
|
||||||
} else {
|
} else {
|
||||||
val floatFill = compTarget.machine.getFloat(staticValue).makeFloatFillAsm()
|
val floatFill = compTarget.machine.getFloat(initialValue).makeFloatFillAsm()
|
||||||
asmgen.out("$name\t.byte $floatFill ; float $staticValue")
|
asmgen.out("$name\t.byte $floatFill ; float $initialValue")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
DataType.STR -> {
|
DataType.STR -> {
|
||||||
throw AssemblyError("all string vars should have been interned into prog")
|
throw AssemblyError("all string vars should have been interned into prog")
|
||||||
}
|
}
|
||||||
in ArrayDatatypes -> arrayVariable2asm(name, variable.dt, value as? ArrayLiteral, variable.arraysize)
|
in ArrayDatatypes -> arrayVariable2asm(name, variable.dt, variable.initialArrayValue, variable.arraysize)
|
||||||
else -> {
|
else -> {
|
||||||
throw AssemblyError("weird dt")
|
throw AssemblyError("weird dt")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun arrayVariable2asm(varname: String, dt: DataType, value: ArrayLiteral?, orNumberOfZeros: Int?) {
|
private fun arrayVariable2asm(varname: String, dt: DataType, value: DoubleArray?, orNumberOfZeros: Int?) {
|
||||||
when(dt) {
|
when(dt) {
|
||||||
DataType.ARRAY_UB -> {
|
DataType.ARRAY_UB -> {
|
||||||
val data = makeArrayFillDataUnsigned(dt, value, orNumberOfZeros)
|
val data = makeArrayFillDataUnsigned(dt, value, orNumberOfZeros)
|
||||||
@ -534,11 +561,9 @@ internal class ProgramAndVarsGen(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
DataType.ARRAY_F -> {
|
DataType.ARRAY_F -> {
|
||||||
val array = value?.value ?:
|
val array = value ?: DoubleArray(orNumberOfZeros!!)
|
||||||
Array(orNumberOfZeros!!) { defaultZero(ArrayToElementTypes.getValue(dt), Position.DUMMY) }
|
|
||||||
val floatFills = array.map {
|
val floatFills = array.map {
|
||||||
val number = (it as NumericLiteral).number
|
compTarget.machine.getFloat(it).makeFloatFillAsm()
|
||||||
compTarget.machine.getFloat(number).makeFloatFillAsm()
|
|
||||||
}
|
}
|
||||||
asmgen.out(varname)
|
asmgen.out(varname)
|
||||||
for (f in array.zip(floatFills))
|
for (f in array.zip(floatFills))
|
||||||
@ -569,56 +594,56 @@ internal class ProgramAndVarsGen(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun outputStringvar(varname: String, dt: DataType, encoding: Encoding, value: String) {
|
private fun outputStringvar(varname: String, encoding: Encoding, value: String) {
|
||||||
asmgen.out("$varname\t; $dt $encoding:\"${escape(value).replace("\u0000", "<NULL>")}\"")
|
asmgen.out("$varname\t; $encoding:\"${escape(value).replace("\u0000", "<NULL>")}\"")
|
||||||
val bytes = compTarget.encodeString(value, encoding).plus(0.toUByte())
|
val bytes = compTarget.encodeString(value, encoding).plus(0.toUByte())
|
||||||
val outputBytes = bytes.map { "$" + it.toString(16).padStart(2, '0') }
|
val outputBytes = bytes.map { "$" + it.toString(16).padStart(2, '0') }
|
||||||
for (chunk in outputBytes.chunked(16))
|
for (chunk in outputBytes.chunked(16))
|
||||||
asmgen.out(" .byte " + chunk.joinToString())
|
asmgen.out(" .byte " + chunk.joinToString())
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun makeArrayFillDataUnsigned(dt: DataType, value: ArrayLiteral?, orNumberOfZeros: Int?): List<String> {
|
private fun makeArrayFillDataUnsigned(dt: DataType, value: DoubleArray?, orNumberOfZeros: Int?): List<String> {
|
||||||
val array = value?.value ?:
|
val array = value ?: DoubleArray(orNumberOfZeros!!)
|
||||||
Array(orNumberOfZeros!!) { defaultZero(ArrayToElementTypes.getValue(dt), Position.DUMMY) }
|
|
||||||
return when (dt) {
|
return when (dt) {
|
||||||
DataType.ARRAY_UB ->
|
DataType.ARRAY_UB ->
|
||||||
// byte array can never contain pointer-to types, so treat values as all integers
|
// byte array can never contain pointer-to types, so treat values as all integers
|
||||||
array.map {
|
array.map {
|
||||||
val number = (it as NumericLiteral).number.toInt()
|
val number = it.toInt()
|
||||||
"$"+number.toString(16).padStart(2, '0')
|
"$"+number.toString(16).padStart(2, '0')
|
||||||
}
|
}
|
||||||
DataType.ARRAY_UW -> array.map {
|
DataType.ARRAY_UW -> array.map {
|
||||||
when (it) {
|
"$" + it.toInt().toString(16).padStart(4, '0')
|
||||||
is NumericLiteral -> {
|
// TODO: initial array literals with address-of, or just variable references, are no longer possible at this time
|
||||||
"$" + it.number.toInt().toString(16).padStart(4, '0')
|
// when (it) {
|
||||||
}
|
// is NumericLiteral -> {
|
||||||
is AddressOf -> {
|
// "$" + it.number.toInt().toString(16).padStart(4, '0')
|
||||||
asmgen.asmSymbolName(it.identifier)
|
// }
|
||||||
}
|
// is AddressOf -> {
|
||||||
is IdentifierReference -> {
|
// asmgen.asmSymbolName(it.identifier)
|
||||||
asmgen.asmSymbolName(it)
|
// }
|
||||||
}
|
// is IdentifierReference -> {
|
||||||
else -> throw AssemblyError("weird array elt dt")
|
// asmgen.asmSymbolName(it)
|
||||||
}
|
// }
|
||||||
|
// else -> throw AssemblyError("weird array elt dt")
|
||||||
|
// }
|
||||||
}
|
}
|
||||||
else -> throw AssemblyError("invalid dt")
|
else -> throw AssemblyError("invalid dt")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun makeArrayFillDataSigned(dt: DataType, value: ArrayLiteral?, orNumberOfZeros: Int?): List<String> {
|
private fun makeArrayFillDataSigned(dt: DataType, value: DoubleArray?, orNumberOfZeros: Int?): List<String> {
|
||||||
val array = value?.value ?:
|
val array = value ?: DoubleArray(orNumberOfZeros!!)
|
||||||
Array(orNumberOfZeros!!) { defaultZero(ArrayToElementTypes.getValue(dt), Position.DUMMY) }
|
|
||||||
return when (dt) {
|
return when (dt) {
|
||||||
DataType.ARRAY_UB ->
|
DataType.ARRAY_UB ->
|
||||||
// byte array can never contain pointer-to types, so treat values as all integers
|
// byte array can never contain pointer-to types, so treat values as all integers
|
||||||
array.map {
|
array.map {
|
||||||
val number = (it as NumericLiteral).number.toInt()
|
val number = it.toInt()
|
||||||
"$"+number.toString(16).padStart(2, '0')
|
"$"+number.toString(16).padStart(2, '0')
|
||||||
}
|
}
|
||||||
DataType.ARRAY_B ->
|
DataType.ARRAY_B ->
|
||||||
// byte array can never contain pointer-to types, so treat values as all integers
|
// byte array can never contain pointer-to types, so treat values as all integers
|
||||||
array.map {
|
array.map {
|
||||||
val number = (it as NumericLiteral).number.toInt()
|
val number = it.toInt()
|
||||||
val hexnum = number.absoluteValue.toString(16).padStart(2, '0')
|
val hexnum = number.absoluteValue.toString(16).padStart(2, '0')
|
||||||
if(number>=0)
|
if(number>=0)
|
||||||
"$$hexnum"
|
"$$hexnum"
|
||||||
@ -626,11 +651,11 @@ internal class ProgramAndVarsGen(
|
|||||||
"-$$hexnum"
|
"-$$hexnum"
|
||||||
}
|
}
|
||||||
DataType.ARRAY_UW -> array.map {
|
DataType.ARRAY_UW -> array.map {
|
||||||
val number = (it as NumericLiteral).number.toInt()
|
val number = it.toInt()
|
||||||
"$" + number.toString(16).padStart(4, '0')
|
"$" + number.toString(16).padStart(4, '0')
|
||||||
}
|
}
|
||||||
DataType.ARRAY_W -> array.map {
|
DataType.ARRAY_W -> array.map {
|
||||||
val number = (it as NumericLiteral).number.toInt()
|
val number = it.toInt()
|
||||||
val hexnum = number.absoluteValue.toString(16).padStart(4, '0')
|
val hexnum = number.absoluteValue.toString(16).padStart(4, '0')
|
||||||
if(number>=0)
|
if(number>=0)
|
||||||
"$$hexnum"
|
"$$hexnum"
|
||||||
|
@ -5,7 +5,6 @@ import com.github.michaelbull.result.onSuccess
|
|||||||
import prog8.ast.base.ArrayDatatypes
|
import prog8.ast.base.ArrayDatatypes
|
||||||
import prog8.ast.base.DataType
|
import prog8.ast.base.DataType
|
||||||
import prog8.ast.base.IntegerDatatypes
|
import prog8.ast.base.IntegerDatatypes
|
||||||
import prog8.ast.expressions.StringLiteral
|
|
||||||
import prog8.ast.statements.Subroutine
|
import prog8.ast.statements.Subroutine
|
||||||
import prog8.ast.statements.ZeropageWish
|
import prog8.ast.statements.ZeropageWish
|
||||||
import prog8.compilerinterface.*
|
import prog8.compilerinterface.*
|
||||||
@ -53,7 +52,6 @@ internal class VariableAllocator(private val symboltable: SymbolTable,
|
|||||||
variable.scopedName,
|
variable.scopedName,
|
||||||
variable.dt,
|
variable.dt,
|
||||||
numElements,
|
numElements,
|
||||||
variable.initialvalue,
|
|
||||||
variable.position,
|
variable.position,
|
||||||
errors
|
errors
|
||||||
)
|
)
|
||||||
@ -74,7 +72,6 @@ internal class VariableAllocator(private val symboltable: SymbolTable,
|
|||||||
variable.scopedName,
|
variable.scopedName,
|
||||||
variable.dt,
|
variable.dt,
|
||||||
numElements,
|
numElements,
|
||||||
variable.initialvalue,
|
|
||||||
variable.position,
|
variable.position,
|
||||||
errors
|
errors
|
||||||
)
|
)
|
||||||
@ -95,7 +92,6 @@ internal class VariableAllocator(private val symboltable: SymbolTable,
|
|||||||
variable.scopedName,
|
variable.scopedName,
|
||||||
variable.dt,
|
variable.dt,
|
||||||
numElements,
|
numElements,
|
||||||
variable.initialvalue,
|
|
||||||
variable.position,
|
variable.position,
|
||||||
errors
|
errors
|
||||||
)
|
)
|
||||||
@ -130,7 +126,7 @@ internal class VariableAllocator(private val symboltable: SymbolTable,
|
|||||||
|
|
||||||
private fun numArrayElements(variable: StStaticVariable) =
|
private fun numArrayElements(variable: StStaticVariable) =
|
||||||
when(variable.dt) {
|
when(variable.dt) {
|
||||||
DataType.STR -> (variable.initialvalue as StringLiteral).value.length
|
DataType.STR -> variable.initialStringValue!!.first.length+1 // 1 extra because of 0 termination char
|
||||||
in ArrayDatatypes -> variable.arraysize!!
|
in ArrayDatatypes -> variable.arraysize!!
|
||||||
else -> null
|
else -> null
|
||||||
}
|
}
|
||||||
|
@ -43,12 +43,12 @@ class CX16Zeropage(options: CompilationOptions) : Zeropage(options) {
|
|||||||
// note: the 16 virtual registers R0-R15 are not regular allocated variables, they're *memory mapped* elsewhere to fixed addresses.
|
// note: the 16 virtual registers R0-R15 are not regular allocated variables, they're *memory mapped* elsewhere to fixed addresses.
|
||||||
// however, to be able for the compiler to "see" them as zero page variables, we have to register them here as well.
|
// however, to be able for the compiler to "see" them as zero page variables, we have to register them here as well.
|
||||||
for(reg in 0..15) {
|
for(reg in 0..15) {
|
||||||
allocatedVariables[listOf("cx16", "r${reg}")] = ZpAllocation((2+reg*2).toUInt(), DataType.UWORD, 2, null, null) // cx16.r0 .. cx16.r15
|
allocatedVariables[listOf("cx16", "r${reg}")] = ZpAllocation((2+reg*2).toUInt(), DataType.UWORD, 2) // cx16.r0 .. cx16.r15
|
||||||
allocatedVariables[listOf("cx16", "r${reg}s")] = ZpAllocation((2+reg*2).toUInt(), DataType.WORD, 2, null, null) // cx16.r0s .. cx16.r15s
|
allocatedVariables[listOf("cx16", "r${reg}s")] = ZpAllocation((2+reg*2).toUInt(), DataType.WORD, 2) // cx16.r0s .. cx16.r15s
|
||||||
allocatedVariables[listOf("cx16", "r${reg}L")] = ZpAllocation((2+reg*2).toUInt(), DataType.UBYTE, 1, null, null) // cx16.r0L .. cx16.r15L
|
allocatedVariables[listOf("cx16", "r${reg}L")] = ZpAllocation((2+reg*2).toUInt(), DataType.UBYTE, 1) // cx16.r0L .. cx16.r15L
|
||||||
allocatedVariables[listOf("cx16", "r${reg}H")] = ZpAllocation((3+reg*2).toUInt(), DataType.UBYTE, 1, null, null) // cx16.r0H .. cx16.r15H
|
allocatedVariables[listOf("cx16", "r${reg}H")] = ZpAllocation((3+reg*2).toUInt(), DataType.UBYTE, 1) // cx16.r0H .. cx16.r15H
|
||||||
allocatedVariables[listOf("cx16", "r${reg}sL")] = ZpAllocation((2+reg*2).toUInt(), DataType.BYTE, 1, null, null) // cx16.r0sL .. cx16.r15sL
|
allocatedVariables[listOf("cx16", "r${reg}sL")] = ZpAllocation((2+reg*2).toUInt(), DataType.BYTE, 1) // cx16.r0sL .. cx16.r15sL
|
||||||
allocatedVariables[listOf("cx16", "r${reg}sH")] = ZpAllocation((3+reg*2).toUInt(), DataType.BYTE, 1, null, null) // cx16.r0sH .. cx16.r15sH
|
allocatedVariables[listOf("cx16", "r${reg}sH")] = ZpAllocation((3+reg*2).toUInt(), DataType.BYTE, 1) // cx16.r0sH .. cx16.r15sH
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -3,7 +3,9 @@ package prog8.compiler.astprocessing
|
|||||||
import prog8.ast.Program
|
import prog8.ast.Program
|
||||||
import prog8.ast.base.Position
|
import prog8.ast.base.Position
|
||||||
import prog8.ast.base.VarDeclType
|
import prog8.ast.base.VarDeclType
|
||||||
|
import prog8.ast.expressions.ArrayLiteral
|
||||||
import prog8.ast.expressions.NumericLiteral
|
import prog8.ast.expressions.NumericLiteral
|
||||||
|
import prog8.ast.expressions.StringLiteral
|
||||||
import prog8.ast.statements.Block
|
import prog8.ast.statements.Block
|
||||||
import prog8.ast.statements.Label
|
import prog8.ast.statements.Label
|
||||||
import prog8.ast.statements.Subroutine
|
import prog8.ast.statements.Subroutine
|
||||||
@ -49,7 +51,14 @@ internal class SymbolTableMaker: IAstVisitor {
|
|||||||
override fun visit(decl: VarDecl) {
|
override fun visit(decl: VarDecl) {
|
||||||
val node =
|
val node =
|
||||||
when(decl.type) {
|
when(decl.type) {
|
||||||
VarDeclType.VAR -> StStaticVariable(decl.name, decl.datatype, decl.value, decl.arraysize?.constIndex(), decl.zeropage, decl.position)
|
VarDeclType.VAR -> {
|
||||||
|
val initialNumeric = (decl.value as? NumericLiteral)?.number
|
||||||
|
val initialStringLit = decl.value as? StringLiteral
|
||||||
|
val initialString = if(initialStringLit==null) null else Pair(initialStringLit.value, initialStringLit.encoding)
|
||||||
|
val initialArrayLit = decl.value as? ArrayLiteral
|
||||||
|
val initialArray = makeInitialArray(initialArrayLit)
|
||||||
|
StStaticVariable(decl.name, decl.datatype, initialNumeric, initialString, initialArray, decl.arraysize?.constIndex(), decl.zeropage, decl.position)
|
||||||
|
}
|
||||||
VarDeclType.CONST -> StConstant(decl.name, decl.datatype, (decl.value as NumericLiteral).number, decl.position)
|
VarDeclType.CONST -> StConstant(decl.name, decl.datatype, (decl.value as NumericLiteral).number, decl.position)
|
||||||
VarDeclType.MEMORY -> StMemVar(decl.name, decl.datatype, (decl.value as NumericLiteral).number.toUInt(), decl.position)
|
VarDeclType.MEMORY -> StMemVar(decl.name, decl.datatype, (decl.value as NumericLiteral).number.toUInt(), decl.position)
|
||||||
}
|
}
|
||||||
@ -57,6 +66,17 @@ internal class SymbolTableMaker: IAstVisitor {
|
|||||||
st.origAstLinks[decl] = node
|
st.origAstLinks[decl] = node
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun makeInitialArray(arrayLit: ArrayLiteral?): DoubleArray? {
|
||||||
|
if(arrayLit==null)
|
||||||
|
return null
|
||||||
|
return arrayLit.value.map {
|
||||||
|
if(it !is NumericLiteral)
|
||||||
|
TODO("ability to have addressof or variables inside array literal currently not possible @ ${arrayLit.position}")
|
||||||
|
else
|
||||||
|
it.number
|
||||||
|
}.toDoubleArray()
|
||||||
|
}
|
||||||
|
|
||||||
override fun visit(label: Label) {
|
override fun visit(label: Label) {
|
||||||
val node = StNode(label.name, StNodeType.LABEL, label.position)
|
val node = StNode(label.name, StNodeType.LABEL, label.position)
|
||||||
scopestack.peek().add(node)
|
scopestack.peek().add(node)
|
||||||
|
@ -71,10 +71,10 @@ private fun makeSt(): SymbolTable {
|
|||||||
block1.add(sub12)
|
block1.add(sub12)
|
||||||
block1.add(StConstant("c1", DataType.UWORD, 12345.0, Position.DUMMY))
|
block1.add(StConstant("c1", DataType.UWORD, 12345.0, Position.DUMMY))
|
||||||
block1.add(StConstant("blockc", DataType.UWORD, 999.0, Position.DUMMY))
|
block1.add(StConstant("blockc", DataType.UWORD, 999.0, Position.DUMMY))
|
||||||
sub11.add(StStaticVariable("v1", DataType.BYTE, null, null, ZeropageWish.DONTCARE, Position.DUMMY))
|
sub11.add(StStaticVariable("v1", DataType.BYTE, null, null, null, null, ZeropageWish.DONTCARE, Position.DUMMY))
|
||||||
sub11.add(StStaticVariable("v2", DataType.BYTE, null, null, ZeropageWish.DONTCARE, Position.DUMMY))
|
sub11.add(StStaticVariable("v2", DataType.BYTE, null, null, null, null, ZeropageWish.DONTCARE, Position.DUMMY))
|
||||||
sub12.add(StStaticVariable("v1", DataType.BYTE, null, null, ZeropageWish.DONTCARE, Position.DUMMY))
|
sub12.add(StStaticVariable("v1", DataType.BYTE, null, null, null, null, ZeropageWish.DONTCARE, Position.DUMMY))
|
||||||
sub12.add(StStaticVariable("v2", DataType.BYTE, null, null, ZeropageWish.DONTCARE, Position.DUMMY))
|
sub12.add(StStaticVariable("v2", DataType.BYTE, null, null, null, null, ZeropageWish.DONTCARE, Position.DUMMY))
|
||||||
|
|
||||||
val block2 = StNode("block2", StNodeType.BLOCK, Position.DUMMY)
|
val block2 = StNode("block2", StNodeType.BLOCK, Position.DUMMY)
|
||||||
val sub21 = StNode("sub1", StNodeType.SUBROUTINE, Position.DUMMY)
|
val sub21 = StNode("sub1", StNodeType.SUBROUTINE, Position.DUMMY)
|
||||||
|
@ -64,26 +64,26 @@ class TestC64Zeropage: FunSpec({
|
|||||||
test("testNames") {
|
test("testNames") {
|
||||||
val zp = C64Zeropage(CompilationOptions(OutputType.RAW, CbmPrgLauncherType.NONE, ZeropageType.BASICSAFE, emptyList(), false, false, c64target))
|
val zp = C64Zeropage(CompilationOptions(OutputType.RAW, CbmPrgLauncherType.NONE, ZeropageType.BASICSAFE, emptyList(), false, false, c64target))
|
||||||
|
|
||||||
var result = zp.allocate(emptyList(), DataType.UBYTE, null, null, null, errors)
|
var result = zp.allocate(emptyList(), DataType.UBYTE, null, null, errors)
|
||||||
result.onFailure { fail(it.toString()) }
|
result.onFailure { fail(it.toString()) }
|
||||||
result = zp.allocate(emptyList(), DataType.UBYTE, null, null, null, errors)
|
result = zp.allocate(emptyList(), DataType.UBYTE, null, null, errors)
|
||||||
result.onFailure { fail(it.toString()) }
|
result.onFailure { fail(it.toString()) }
|
||||||
result = zp.allocate(listOf("varname"), DataType.UBYTE, null, null, null, errors)
|
result = zp.allocate(listOf("varname"), DataType.UBYTE, null, null, errors)
|
||||||
result.onFailure { fail(it.toString()) }
|
result.onFailure { fail(it.toString()) }
|
||||||
shouldThrow<IllegalArgumentException> { zp.allocate(listOf("varname"), DataType.UBYTE,null, null, null, errors) }
|
shouldThrow<IllegalArgumentException> { zp.allocate(listOf("varname"), DataType.UBYTE,null, null, errors) }
|
||||||
result = zp.allocate(listOf("varname2"), DataType.UBYTE, null, null, null, errors)
|
result = zp.allocate(listOf("varname2"), DataType.UBYTE, null, null, errors)
|
||||||
result.onFailure { fail(it.toString()) }
|
result.onFailure { fail(it.toString()) }
|
||||||
}
|
}
|
||||||
|
|
||||||
test("testZpFloatEnable") {
|
test("testZpFloatEnable") {
|
||||||
val zp = C64Zeropage(CompilationOptions(OutputType.RAW, CbmPrgLauncherType.NONE, ZeropageType.FULL, emptyList(), false, false, c64target))
|
val zp = C64Zeropage(CompilationOptions(OutputType.RAW, CbmPrgLauncherType.NONE, ZeropageType.FULL, emptyList(), false, false, c64target))
|
||||||
var result = zp.allocate(emptyList(), DataType.FLOAT, null, null, null, errors)
|
var result = zp.allocate(emptyList(), DataType.FLOAT, null, null, errors)
|
||||||
result.expectError { "should be allocation error due to disabled floats" }
|
result.expectError { "should be allocation error due to disabled floats" }
|
||||||
val zp2 = C64Zeropage(CompilationOptions(OutputType.RAW, CbmPrgLauncherType.NONE, ZeropageType.DONTUSE, emptyList(), true, false, c64target))
|
val zp2 = C64Zeropage(CompilationOptions(OutputType.RAW, CbmPrgLauncherType.NONE, ZeropageType.DONTUSE, emptyList(), true, false, c64target))
|
||||||
result = zp2.allocate(emptyList(), DataType.FLOAT, null, null, null, errors)
|
result = zp2.allocate(emptyList(), DataType.FLOAT, null, null, errors)
|
||||||
result.expectError { "should be allocation error due to disabled ZP use" }
|
result.expectError { "should be allocation error due to disabled ZP use" }
|
||||||
val zp3 = C64Zeropage(CompilationOptions(OutputType.RAW, CbmPrgLauncherType.NONE, ZeropageType.FLOATSAFE, emptyList(), true, false, c64target))
|
val zp3 = C64Zeropage(CompilationOptions(OutputType.RAW, CbmPrgLauncherType.NONE, ZeropageType.FLOATSAFE, emptyList(), true, false, c64target))
|
||||||
zp3.allocate(emptyList(), DataType.FLOAT, null, null, null, errors)
|
zp3.allocate(emptyList(), DataType.FLOAT, null, null, errors)
|
||||||
}
|
}
|
||||||
|
|
||||||
test("testZpModesWithFloats") {
|
test("testZpModesWithFloats") {
|
||||||
@ -105,7 +105,7 @@ class TestC64Zeropage: FunSpec({
|
|||||||
val zp = C64Zeropage(CompilationOptions(OutputType.RAW, CbmPrgLauncherType.NONE, ZeropageType.DONTUSE, emptyList(), false, false, c64target))
|
val zp = C64Zeropage(CompilationOptions(OutputType.RAW, CbmPrgLauncherType.NONE, ZeropageType.DONTUSE, emptyList(), false, false, c64target))
|
||||||
println(zp.free)
|
println(zp.free)
|
||||||
zp.availableBytes() shouldBe 0
|
zp.availableBytes() shouldBe 0
|
||||||
val result = zp.allocate(emptyList(), DataType.BYTE, null, null, null, errors)
|
val result = zp.allocate(emptyList(), DataType.BYTE, null, null, errors)
|
||||||
result.expectError { "expected error due to disabled ZP use" }
|
result.expectError { "expected error due to disabled ZP use" }
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -118,9 +118,9 @@ class TestC64Zeropage: FunSpec({
|
|||||||
zp3.availableBytes() shouldBe 125
|
zp3.availableBytes() shouldBe 125
|
||||||
val zp4 = C64Zeropage(CompilationOptions(OutputType.RAW, CbmPrgLauncherType.NONE, ZeropageType.FULL, emptyList(), false, false, c64target))
|
val zp4 = C64Zeropage(CompilationOptions(OutputType.RAW, CbmPrgLauncherType.NONE, ZeropageType.FULL, emptyList(), false, false, c64target))
|
||||||
zp4.availableBytes() shouldBe 239
|
zp4.availableBytes() shouldBe 239
|
||||||
zp4.allocate(listOf("test"), DataType.UBYTE, null, null, null, errors)
|
zp4.allocate(listOf("test"), DataType.UBYTE, null, null, errors)
|
||||||
zp4.availableBytes() shouldBe 238
|
zp4.availableBytes() shouldBe 238
|
||||||
zp4.allocate(listOf("test2"), DataType.UBYTE, null, null, null, errors)
|
zp4.allocate(listOf("test2"), DataType.UBYTE, null, null, errors)
|
||||||
zp4.availableBytes() shouldBe 237
|
zp4.availableBytes() shouldBe 237
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -151,19 +151,19 @@ class TestC64Zeropage: FunSpec({
|
|||||||
zp.hasByteAvailable() shouldBe true
|
zp.hasByteAvailable() shouldBe true
|
||||||
zp.hasWordAvailable() shouldBe true
|
zp.hasWordAvailable() shouldBe true
|
||||||
|
|
||||||
var result = zp.allocate(emptyList(), DataType.FLOAT, null, null, null, errors)
|
var result = zp.allocate(emptyList(), DataType.FLOAT, null, null, errors)
|
||||||
result.expectError { "expect allocation error: in regular zp there aren't 5 sequential bytes free" }
|
result.expectError { "expect allocation error: in regular zp there aren't 5 sequential bytes free" }
|
||||||
|
|
||||||
for (i in 0 until zp.availableBytes()) {
|
for (i in 0 until zp.availableBytes()) {
|
||||||
val alloc = zp.allocate(emptyList(), DataType.UBYTE, null, null, null, errors)
|
val alloc = zp.allocate(emptyList(), DataType.UBYTE, null, null, errors)
|
||||||
alloc.getOrElse { throw it }
|
alloc.getOrElse { throw it }
|
||||||
}
|
}
|
||||||
zp.availableBytes() shouldBe 0
|
zp.availableBytes() shouldBe 0
|
||||||
zp.hasByteAvailable() shouldBe false
|
zp.hasByteAvailable() shouldBe false
|
||||||
zp.hasWordAvailable() shouldBe false
|
zp.hasWordAvailable() shouldBe false
|
||||||
result = zp.allocate(emptyList(), DataType.UBYTE, null, null, null, errors)
|
result = zp.allocate(emptyList(), DataType.UBYTE, null, null, errors)
|
||||||
result.expectError { "expected allocation error" }
|
result.expectError { "expected allocation error" }
|
||||||
result = zp.allocate(emptyList(), DataType.UWORD, null, null, null, errors)
|
result = zp.allocate(emptyList(), DataType.UWORD, null, null, errors)
|
||||||
result.expectError { "expected allocation error" }
|
result.expectError { "expected allocation error" }
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -172,47 +172,47 @@ class TestC64Zeropage: FunSpec({
|
|||||||
zp.availableBytes() shouldBe 239
|
zp.availableBytes() shouldBe 239
|
||||||
zp.hasByteAvailable() shouldBe true
|
zp.hasByteAvailable() shouldBe true
|
||||||
zp.hasWordAvailable() shouldBe true
|
zp.hasWordAvailable() shouldBe true
|
||||||
var result = zp.allocate(emptyList(), DataType.UWORD, null, null, null, errors)
|
var result = zp.allocate(emptyList(), DataType.UWORD, null, null, errors)
|
||||||
val loc = result.getOrElse { throw it } .first
|
val loc = result.getOrElse { throw it } .first
|
||||||
loc shouldBeGreaterThan 3u
|
loc shouldBeGreaterThan 3u
|
||||||
loc shouldNotBeIn zp.free
|
loc shouldNotBeIn zp.free
|
||||||
val num = zp.availableBytes() / 2
|
val num = zp.availableBytes() / 2
|
||||||
|
|
||||||
for(i in 0..num-3) {
|
for(i in 0..num-3) {
|
||||||
zp.allocate(emptyList(), DataType.UWORD, null, null, null, errors)
|
zp.allocate(emptyList(), DataType.UWORD, null, null, errors)
|
||||||
}
|
}
|
||||||
zp.availableBytes() shouldBe 5
|
zp.availableBytes() shouldBe 5
|
||||||
|
|
||||||
// can't allocate because no more sequential bytes, only fragmented
|
// can't allocate because no more sequential bytes, only fragmented
|
||||||
result = zp.allocate(emptyList(), DataType.UWORD, null, null, null, errors)
|
result = zp.allocate(emptyList(), DataType.UWORD, null, null, errors)
|
||||||
result.expectError { "should give allocation error" }
|
result.expectError { "should give allocation error" }
|
||||||
|
|
||||||
for(i in 0..4) {
|
for(i in 0..4) {
|
||||||
zp.allocate(emptyList(), DataType.UBYTE, null, null, null, errors)
|
zp.allocate(emptyList(), DataType.UBYTE, null, null, errors)
|
||||||
}
|
}
|
||||||
|
|
||||||
zp.availableBytes() shouldBe 0
|
zp.availableBytes() shouldBe 0
|
||||||
zp.hasByteAvailable() shouldBe false
|
zp.hasByteAvailable() shouldBe false
|
||||||
zp.hasWordAvailable() shouldBe false
|
zp.hasWordAvailable() shouldBe false
|
||||||
result = zp.allocate(emptyList(), DataType.UBYTE, null, null, null, errors)
|
result = zp.allocate(emptyList(), DataType.UBYTE, null, null, errors)
|
||||||
result.expectError { "should give allocation error" }
|
result.expectError { "should give allocation error" }
|
||||||
}
|
}
|
||||||
|
|
||||||
test("testEfficientAllocation") {
|
test("testEfficientAllocation") {
|
||||||
val zp = C64Zeropage(CompilationOptions(OutputType.RAW, CbmPrgLauncherType.NONE, ZeropageType.BASICSAFE, emptyList(), true, false, c64target))
|
val zp = C64Zeropage(CompilationOptions(OutputType.RAW, CbmPrgLauncherType.NONE, ZeropageType.BASICSAFE, emptyList(), true, false, c64target))
|
||||||
zp.availableBytes() shouldBe 18
|
zp.availableBytes() shouldBe 18
|
||||||
zp.allocate(emptyList(), DataType.WORD, null, null, null, errors).getOrElse{throw it}.first shouldBe 0x04u
|
zp.allocate(emptyList(), DataType.WORD, null, null, errors).getOrElse{throw it}.first shouldBe 0x04u
|
||||||
zp.allocate(emptyList(), DataType.UBYTE, null, null, null, errors).getOrElse{throw it}.first shouldBe 0x06u
|
zp.allocate(emptyList(), DataType.UBYTE, null, null, errors).getOrElse{throw it}.first shouldBe 0x06u
|
||||||
zp.allocate(emptyList(), DataType.UBYTE, null, null, null, errors).getOrElse{throw it}.first shouldBe 0x0au
|
zp.allocate(emptyList(), DataType.UBYTE, null, null, errors).getOrElse{throw it}.first shouldBe 0x0au
|
||||||
zp.allocate(emptyList(), DataType.UWORD, null, null, null, errors).getOrElse{throw it}.first shouldBe 0x9bu
|
zp.allocate(emptyList(), DataType.UWORD, null, null, errors).getOrElse{throw it}.first shouldBe 0x9bu
|
||||||
zp.allocate(emptyList(), DataType.UWORD, null, null, null, errors).getOrElse{throw it}.first shouldBe 0x9eu
|
zp.allocate(emptyList(), DataType.UWORD, null, null, errors).getOrElse{throw it}.first shouldBe 0x9eu
|
||||||
zp.allocate(emptyList(), DataType.UWORD, null, null, null, errors).getOrElse{throw it}.first shouldBe 0xa5u
|
zp.allocate(emptyList(), DataType.UWORD, null, null, errors).getOrElse{throw it}.first shouldBe 0xa5u
|
||||||
zp.allocate(emptyList(), DataType.UWORD, null, null, null, errors).getOrElse{throw it}.first shouldBe 0xb0u
|
zp.allocate(emptyList(), DataType.UWORD, null, null, errors).getOrElse{throw it}.first shouldBe 0xb0u
|
||||||
zp.allocate(emptyList(), DataType.UWORD, null, null, null, errors).getOrElse{throw it}.first shouldBe 0xbeu
|
zp.allocate(emptyList(), DataType.UWORD, null, null, errors).getOrElse{throw it}.first shouldBe 0xbeu
|
||||||
zp.allocate(emptyList(), DataType.UBYTE, null, null, null, errors).getOrElse{throw it}.first shouldBe 0x0eu
|
zp.allocate(emptyList(), DataType.UBYTE, null, null, errors).getOrElse{throw it}.first shouldBe 0x0eu
|
||||||
zp.allocate(emptyList(), DataType.UBYTE, null, null, null, errors).getOrElse{throw it}.first shouldBe 0x92u
|
zp.allocate(emptyList(), DataType.UBYTE, null, null, errors).getOrElse{throw it}.first shouldBe 0x92u
|
||||||
zp.allocate(emptyList(), DataType.UBYTE, null, null, null, errors).getOrElse{throw it}.first shouldBe 0x96u
|
zp.allocate(emptyList(), DataType.UBYTE, null, null, errors).getOrElse{throw it}.first shouldBe 0x96u
|
||||||
zp.allocate(emptyList(), DataType.UBYTE, null, null, null, errors).getOrElse{throw it}.first shouldBe 0xf9u
|
zp.allocate(emptyList(), DataType.UBYTE, null, null, errors).getOrElse{throw it}.first shouldBe 0xf9u
|
||||||
zp.availableBytes() shouldBe 0
|
zp.availableBytes() shouldBe 0
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -243,9 +243,9 @@ class TestCx16Zeropage: FunSpec({
|
|||||||
zp2.availableBytes() shouldBe 175
|
zp2.availableBytes() shouldBe 175
|
||||||
val zp3 = CX16Zeropage(CompilationOptions(OutputType.RAW, CbmPrgLauncherType.NONE, ZeropageType.FULL, emptyList(), false, false, cx16target))
|
val zp3 = CX16Zeropage(CompilationOptions(OutputType.RAW, CbmPrgLauncherType.NONE, ZeropageType.FULL, emptyList(), false, false, cx16target))
|
||||||
zp3.availableBytes() shouldBe 216
|
zp3.availableBytes() shouldBe 216
|
||||||
zp3.allocate(listOf("test"), DataType.UBYTE, null, null, null, errors)
|
zp3.allocate(listOf("test"), DataType.UBYTE, null, null, errors)
|
||||||
zp3.availableBytes() shouldBe 215
|
zp3.availableBytes() shouldBe 215
|
||||||
zp3.allocate(listOf("test2"), DataType.UBYTE, null, null, null, errors)
|
zp3.allocate(listOf("test2"), DataType.UBYTE, null, null, errors)
|
||||||
zp3.availableBytes() shouldBe 214
|
zp3.availableBytes() shouldBe 214
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -3,7 +3,6 @@ package prog8.compilerinterface
|
|||||||
import prog8.ast.Node
|
import prog8.ast.Node
|
||||||
import prog8.ast.base.DataType
|
import prog8.ast.base.DataType
|
||||||
import prog8.ast.base.Position
|
import prog8.ast.base.Position
|
||||||
import prog8.ast.expressions.Expression
|
|
||||||
import prog8.ast.statements.ZeropageWish
|
import prog8.ast.statements.ZeropageWish
|
||||||
import prog8.ast.toHex
|
import prog8.ast.toHex
|
||||||
|
|
||||||
@ -123,15 +122,26 @@ open class StNode(val name: String,
|
|||||||
|
|
||||||
class StStaticVariable(name: String,
|
class StStaticVariable(name: String,
|
||||||
val dt: DataType,
|
val dt: DataType,
|
||||||
val initialvalue: Expression?,
|
val initialNumericValue: Double?,
|
||||||
|
val initialStringValue: Pair<String, Encoding>?,
|
||||||
|
val initialArrayValue: DoubleArray?,
|
||||||
val arraysize: Int?,
|
val arraysize: Int?,
|
||||||
val zpw: ZeropageWish,
|
val zpw: ZeropageWish,
|
||||||
position: Position) : StNode(name, StNodeType.STATICVAR, position) {
|
position: Position) : StNode(name, StNodeType.STATICVAR, position) {
|
||||||
|
|
||||||
|
init {
|
||||||
|
if(arraysize!=null && initialArrayValue!=null)
|
||||||
|
require(arraysize == initialArrayValue.size)
|
||||||
|
if(arraysize!=null || initialArrayValue!=null)
|
||||||
|
require(initialStringValue==null && initialNumericValue==null)
|
||||||
|
}
|
||||||
|
|
||||||
override fun printProperties() {
|
override fun printProperties() {
|
||||||
print("$name dt=$dt initialval=$initialvalue arraysize=$arraysize zpw=$zpw")
|
print("$name dt=$dt zpw=$zpw")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
class StConstant(name: String, val dt: DataType, val value: Double, position: Position) :
|
class StConstant(name: String, val dt: DataType, val value: Double, position: Position) :
|
||||||
StNode(name, StNodeType.CONSTANT, position) {
|
StNode(name, StNodeType.CONSTANT, position) {
|
||||||
override fun printProperties() {
|
override fun printProperties() {
|
||||||
|
@ -4,9 +4,6 @@ import com.github.michaelbull.result.Err
|
|||||||
import com.github.michaelbull.result.Ok
|
import com.github.michaelbull.result.Ok
|
||||||
import com.github.michaelbull.result.Result
|
import com.github.michaelbull.result.Result
|
||||||
import prog8.ast.base.*
|
import prog8.ast.base.*
|
||||||
import prog8.ast.expressions.ArrayLiteral
|
|
||||||
import prog8.ast.expressions.Expression
|
|
||||||
import prog8.ast.expressions.StringLiteral
|
|
||||||
|
|
||||||
|
|
||||||
class ZeropageAllocationError(message: String) : Exception(message)
|
class ZeropageAllocationError(message: String) : Exception(message)
|
||||||
@ -19,11 +16,7 @@ abstract class Zeropage(protected val options: CompilationOptions) {
|
|||||||
abstract val SCRATCH_W1 : UInt // temp storage 1 for a word $fb+$fc
|
abstract val SCRATCH_W1 : UInt // temp storage 1 for a word $fb+$fc
|
||||||
abstract val SCRATCH_W2 : UInt // temp storage 2 for a word $fb+$fc
|
abstract val SCRATCH_W2 : UInt // temp storage 2 for a word $fb+$fc
|
||||||
|
|
||||||
data class ZpAllocation(val address: UInt,
|
data class ZpAllocation(val address: UInt, val dt: DataType, val size: Int)
|
||||||
val dt: DataType,
|
|
||||||
val size: Int,
|
|
||||||
val initialStringValue: StringLiteral?,
|
|
||||||
val initialArrayValue: ArrayLiteral?)
|
|
||||||
|
|
||||||
// the variables allocated into Zeropage.
|
// the variables allocated into Zeropage.
|
||||||
// name (scoped) ==> pair of address to (Datatype + bytesize)
|
// name (scoped) ==> pair of address to (Datatype + bytesize)
|
||||||
@ -52,7 +45,6 @@ abstract class Zeropage(protected val options: CompilationOptions) {
|
|||||||
fun allocate(name: List<String>,
|
fun allocate(name: List<String>,
|
||||||
datatype: DataType,
|
datatype: DataType,
|
||||||
numElements: Int?,
|
numElements: Int?,
|
||||||
initValue: Expression?,
|
|
||||||
position: Position?,
|
position: Position?,
|
||||||
errors: IErrorReporter): Result<Pair<UInt, Int>, ZeropageAllocationError> {
|
errors: IErrorReporter): Result<Pair<UInt, Int>, ZeropageAllocationError> {
|
||||||
|
|
||||||
@ -90,13 +82,13 @@ abstract class Zeropage(protected val options: CompilationOptions) {
|
|||||||
if(size==1) {
|
if(size==1) {
|
||||||
for(candidate in free.minOrNull()!! .. free.maxOrNull()!!+1u) {
|
for(candidate in free.minOrNull()!! .. free.maxOrNull()!!+1u) {
|
||||||
if(oneSeparateByteFree(candidate))
|
if(oneSeparateByteFree(candidate))
|
||||||
return Ok(Pair(makeAllocation(candidate, 1, datatype, name, initValue), 1))
|
return Ok(Pair(makeAllocation(candidate, 1, datatype, name), 1))
|
||||||
}
|
}
|
||||||
return Ok(Pair(makeAllocation(free[0], 1, datatype, name, initValue), 1))
|
return Ok(Pair(makeAllocation(free[0], 1, datatype, name), 1))
|
||||||
}
|
}
|
||||||
for(candidate in free.minOrNull()!! .. free.maxOrNull()!!+1u) {
|
for(candidate in free.minOrNull()!! .. free.maxOrNull()!!+1u) {
|
||||||
if (sequentialFree(candidate, size))
|
if (sequentialFree(candidate, size))
|
||||||
return Ok(Pair(makeAllocation(candidate, size, datatype, name, initValue), size))
|
return Ok(Pair(makeAllocation(candidate, size, datatype, name), size))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -106,14 +98,14 @@ abstract class Zeropage(protected val options: CompilationOptions) {
|
|||||||
|
|
||||||
private fun reserve(range: UIntRange) = free.removeAll(range)
|
private fun reserve(range: UIntRange) = free.removeAll(range)
|
||||||
|
|
||||||
private fun makeAllocation(address: UInt, size: Int, datatype: DataType, name: List<String>, initValue: Expression?): UInt {
|
private fun makeAllocation(address: UInt, size: Int, datatype: DataType, name: List<String>): UInt {
|
||||||
require(size>=0)
|
require(size>=0)
|
||||||
free.removeAll(address until address+size.toUInt())
|
free.removeAll(address until address+size.toUInt())
|
||||||
if(name.isNotEmpty()) {
|
if(name.isNotEmpty()) {
|
||||||
allocatedVariables[name] = when(datatype) {
|
allocatedVariables[name] = when(datatype) {
|
||||||
in NumericDatatypes -> ZpAllocation(address, datatype, size, null, null) // numerical variables in zeropage never have an initial value here because they are set in separate initializer assignments
|
in NumericDatatypes -> ZpAllocation(address, datatype, size) // numerical variables in zeropage never have an initial value here because they are set in separate initializer assignments
|
||||||
DataType.STR -> ZpAllocation(address, datatype, size, initValue as? StringLiteral, null)
|
DataType.STR -> ZpAllocation(address, datatype, size)
|
||||||
in ArrayDatatypes -> ZpAllocation(address, datatype, size, null, initValue as? ArrayLiteral)
|
in ArrayDatatypes -> ZpAllocation(address, datatype, size)
|
||||||
else -> throw AssemblyError("invalid dt")
|
else -> throw AssemblyError("invalid dt")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -7,6 +7,9 @@ For next release
|
|||||||
no vardecls in it anymore (these are part of the symboltable) and baked types, so no inferType too.
|
no vardecls in it anymore (these are part of the symboltable) and baked types, so no inferType too.
|
||||||
no name lookup in the Ast, always do this in the symbol table.
|
no name lookup in the Ast, always do this in the symbol table.
|
||||||
|
|
||||||
|
- codegen makeInitialArray()/makeArrayFillDataUnsigned():
|
||||||
|
initial array literals with address-of, or just variable references, are no longer possible at this time!!
|
||||||
|
|
||||||
...
|
...
|
||||||
|
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user