mirror of
https://github.com/irmen/prog8.git
synced 2024-11-22 15:33:02 +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")
|
||||
when(dt) {
|
||||
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(
|
||||
success = { (address, _) -> asmInfo.extraVars.add(Triple(dt, counterVar, address)) },
|
||||
failure = { asmInfo.extraVars.add(Triple(dt, counterVar, null)) } // allocate normally
|
||||
|
@ -292,7 +292,7 @@ $loopLabel sty $indexVar
|
||||
}
|
||||
if(length>=16) {
|
||||
// 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(
|
||||
success = { (address,_)-> asmgen.out("""$indexVar = $address ; auto zp UBYTE""") },
|
||||
failure = { asmgen.out("$indexVar .byte 0") }
|
||||
@ -333,7 +333,7 @@ $loopLabel sty $indexVar
|
||||
}
|
||||
if(length>=16) {
|
||||
// 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(
|
||||
success = { (address,_)-> asmgen.out("""$indexVar = $address ; auto zp UBYTE""") },
|
||||
failure = { asmgen.out("$indexVar .byte 0") }
|
||||
|
@ -2,8 +2,10 @@ package prog8.codegen.cpu6502
|
||||
|
||||
import prog8.ast.Program
|
||||
import prog8.ast.antlr.escape
|
||||
import prog8.ast.base.*
|
||||
import prog8.ast.expressions.*
|
||||
import prog8.ast.base.ArrayDatatypes
|
||||
import prog8.ast.base.ByteDatatypes
|
||||
import prog8.ast.base.DataType
|
||||
import prog8.ast.base.RegisterOrPair
|
||||
import prog8.ast.statements.*
|
||||
import prog8.ast.toHex
|
||||
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
|
||||
val stringVarsWithInitInZp = allocator.zeropageVars.filter { it.value.dt==DataType.STR && it.value.initialStringValue!=null }
|
||||
val arrayVarsWithInitInZp = allocator.zeropageVars.filter { it.value.dt in ArrayDatatypes && it.value.initialArrayValue!=null }
|
||||
val stringVarsWithInitInZp = getZpStringVarsWithInitvalue()
|
||||
val arrayVarsWithInitInZp = getZpArrayVarsWithInitvalue()
|
||||
if(stringVarsWithInitInZp.isNotEmpty() || arrayVarsWithInitInZp.isNotEmpty()) {
|
||||
asmgen.out("; zp str and array initializations")
|
||||
stringVarsWithInitInZp.forEach {
|
||||
val name = asmgen.asmVariableName(it.key)
|
||||
val name = asmgen.asmVariableName(it.name)
|
||||
asmgen.out("""
|
||||
lda #<${name}
|
||||
ldy #>${name}
|
||||
@ -393,8 +395,8 @@ internal class ProgramAndVarsGen(
|
||||
jsr prog8_lib.strcpy""")
|
||||
}
|
||||
arrayVarsWithInitInZp.forEach {
|
||||
val size = it.value.size
|
||||
val name = asmgen.asmVariableName(it.key)
|
||||
val size = it.alloc.size
|
||||
val name = asmgen.asmVariableName(it.name)
|
||||
asmgen.out("""
|
||||
lda #<${name}_init_value
|
||||
ldy #>${name}_init_value
|
||||
@ -412,14 +414,13 @@ internal class ProgramAndVarsGen(
|
||||
}
|
||||
|
||||
stringVarsWithInitInZp.forEach {
|
||||
val varname = asmgen.asmVariableName(it.key)+"_init_value"
|
||||
val stringvalue = it.value.initialStringValue!!
|
||||
outputStringvar(varname, it.value.dt, stringvalue.encoding, stringvalue.value)
|
||||
val varname = asmgen.asmVariableName(it.name)+"_init_value"
|
||||
outputStringvar(varname, it.value.second, it.value.first)
|
||||
}
|
||||
|
||||
arrayVarsWithInitInZp.forEach {
|
||||
val varname = asmgen.asmVariableName(it.key)+"_init_value"
|
||||
arrayVariable2asm(varname, it.value.dt, it.value.initialArrayValue!!, null)
|
||||
val varname = asmgen.asmVariableName(it.name)+"_init_value"
|
||||
arrayVariable2asm(varname, it.alloc.dt, it.value, null)
|
||||
}
|
||||
|
||||
asmgen.out("""+ tsx
|
||||
@ -429,6 +430,40 @@ internal class ProgramAndVarsGen(
|
||||
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>>) {
|
||||
val zpVariables = allocator.zeropageVars.filter { it.key in varNames }
|
||||
for ((scopedName, zpvar) in zpVariables) {
|
||||
@ -443,8 +478,7 @@ internal class ProgramAndVarsGen(
|
||||
asmgen.out("; non-zeropage variables")
|
||||
val (stringvars, othervars) = variables.partition { it.dt==DataType.STR }
|
||||
stringvars.forEach {
|
||||
val stringvalue = it.initialvalue as StringLiteral
|
||||
outputStringvar(it.name, it.dt, stringvalue.encoding, stringvalue.value)
|
||||
outputStringvar(it.name, it.initialStringValue!!.second, it.initialStringValue!!.first)
|
||||
}
|
||||
othervars.sortedBy { it.type }.forEach {
|
||||
staticVariable2asm(it)
|
||||
@ -453,45 +487,38 @@ internal class ProgramAndVarsGen(
|
||||
|
||||
private fun staticVariable2asm(variable: StStaticVariable) {
|
||||
val name = variable.name
|
||||
val value = variable.initialvalue
|
||||
val staticValue: Number =
|
||||
if(value!=null) {
|
||||
if(value is NumericLiteral) {
|
||||
if(value.type== DataType.FLOAT)
|
||||
value.number
|
||||
val initialValue: Number =
|
||||
if(variable.initialNumericValue!=null) {
|
||||
if(variable.dt== DataType.FLOAT)
|
||||
variable.initialNumericValue!!
|
||||
else
|
||||
value.number.toInt()
|
||||
} else {
|
||||
if(variable.dt in NumericDatatypes)
|
||||
throw AssemblyError("can only deal with constant numeric values for global vars")
|
||||
else 0
|
||||
}
|
||||
variable.initialNumericValue!!.toInt()
|
||||
} else 0
|
||||
|
||||
when (variable.dt) {
|
||||
DataType.UBYTE -> asmgen.out("$name\t.byte ${staticValue.toHex()}")
|
||||
DataType.BYTE -> asmgen.out("$name\t.char $staticValue")
|
||||
DataType.UWORD -> asmgen.out("$name\t.word ${staticValue.toHex()}")
|
||||
DataType.WORD -> asmgen.out("$name\t.sint $staticValue")
|
||||
DataType.UBYTE -> asmgen.out("$name\t.byte ${initialValue.toHex()}")
|
||||
DataType.BYTE -> asmgen.out("$name\t.char $initialValue")
|
||||
DataType.UWORD -> asmgen.out("$name\t.word ${initialValue.toHex()}")
|
||||
DataType.WORD -> asmgen.out("$name\t.sint $initialValue")
|
||||
DataType.FLOAT -> {
|
||||
if(staticValue==0) {
|
||||
if(initialValue==0) {
|
||||
asmgen.out("$name\t.byte 0,0,0,0,0 ; float")
|
||||
} else {
|
||||
val floatFill = compTarget.machine.getFloat(staticValue).makeFloatFillAsm()
|
||||
asmgen.out("$name\t.byte $floatFill ; float $staticValue")
|
||||
val floatFill = compTarget.machine.getFloat(initialValue).makeFloatFillAsm()
|
||||
asmgen.out("$name\t.byte $floatFill ; float $initialValue")
|
||||
}
|
||||
}
|
||||
DataType.STR -> {
|
||||
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 -> {
|
||||
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) {
|
||||
DataType.ARRAY_UB -> {
|
||||
val data = makeArrayFillDataUnsigned(dt, value, orNumberOfZeros)
|
||||
@ -534,11 +561,9 @@ internal class ProgramAndVarsGen(
|
||||
}
|
||||
}
|
||||
DataType.ARRAY_F -> {
|
||||
val array = value?.value ?:
|
||||
Array(orNumberOfZeros!!) { defaultZero(ArrayToElementTypes.getValue(dt), Position.DUMMY) }
|
||||
val array = value ?: DoubleArray(orNumberOfZeros!!)
|
||||
val floatFills = array.map {
|
||||
val number = (it as NumericLiteral).number
|
||||
compTarget.machine.getFloat(number).makeFloatFillAsm()
|
||||
compTarget.machine.getFloat(it).makeFloatFillAsm()
|
||||
}
|
||||
asmgen.out(varname)
|
||||
for (f in array.zip(floatFills))
|
||||
@ -569,56 +594,56 @@ internal class ProgramAndVarsGen(
|
||||
}
|
||||
}
|
||||
|
||||
private fun outputStringvar(varname: String, dt: DataType, encoding: Encoding, value: String) {
|
||||
asmgen.out("$varname\t; $dt $encoding:\"${escape(value).replace("\u0000", "<NULL>")}\"")
|
||||
private fun outputStringvar(varname: String, encoding: Encoding, value: String) {
|
||||
asmgen.out("$varname\t; $encoding:\"${escape(value).replace("\u0000", "<NULL>")}\"")
|
||||
val bytes = compTarget.encodeString(value, encoding).plus(0.toUByte())
|
||||
val outputBytes = bytes.map { "$" + it.toString(16).padStart(2, '0') }
|
||||
for (chunk in outputBytes.chunked(16))
|
||||
asmgen.out(" .byte " + chunk.joinToString())
|
||||
}
|
||||
|
||||
private fun makeArrayFillDataUnsigned(dt: DataType, value: ArrayLiteral?, orNumberOfZeros: Int?): List<String> {
|
||||
val array = value?.value ?:
|
||||
Array(orNumberOfZeros!!) { defaultZero(ArrayToElementTypes.getValue(dt), Position.DUMMY) }
|
||||
private fun makeArrayFillDataUnsigned(dt: DataType, value: DoubleArray?, orNumberOfZeros: Int?): List<String> {
|
||||
val array = value ?: DoubleArray(orNumberOfZeros!!)
|
||||
return when (dt) {
|
||||
DataType.ARRAY_UB ->
|
||||
// byte array can never contain pointer-to types, so treat values as all integers
|
||||
array.map {
|
||||
val number = (it as NumericLiteral).number.toInt()
|
||||
val number = it.toInt()
|
||||
"$"+number.toString(16).padStart(2, '0')
|
||||
}
|
||||
DataType.ARRAY_UW -> array.map {
|
||||
when (it) {
|
||||
is NumericLiteral -> {
|
||||
"$" + it.number.toInt().toString(16).padStart(4, '0')
|
||||
}
|
||||
is AddressOf -> {
|
||||
asmgen.asmSymbolName(it.identifier)
|
||||
}
|
||||
is IdentifierReference -> {
|
||||
asmgen.asmSymbolName(it)
|
||||
}
|
||||
else -> throw AssemblyError("weird array elt dt")
|
||||
}
|
||||
"$" + it.toInt().toString(16).padStart(4, '0')
|
||||
// TODO: initial array literals with address-of, or just variable references, are no longer possible at this time
|
||||
// when (it) {
|
||||
// is NumericLiteral -> {
|
||||
// "$" + it.number.toInt().toString(16).padStart(4, '0')
|
||||
// }
|
||||
// is AddressOf -> {
|
||||
// asmgen.asmSymbolName(it.identifier)
|
||||
// }
|
||||
// is IdentifierReference -> {
|
||||
// asmgen.asmSymbolName(it)
|
||||
// }
|
||||
// else -> throw AssemblyError("weird array elt dt")
|
||||
// }
|
||||
}
|
||||
else -> throw AssemblyError("invalid dt")
|
||||
}
|
||||
}
|
||||
|
||||
private fun makeArrayFillDataSigned(dt: DataType, value: ArrayLiteral?, orNumberOfZeros: Int?): List<String> {
|
||||
val array = value?.value ?:
|
||||
Array(orNumberOfZeros!!) { defaultZero(ArrayToElementTypes.getValue(dt), Position.DUMMY) }
|
||||
private fun makeArrayFillDataSigned(dt: DataType, value: DoubleArray?, orNumberOfZeros: Int?): List<String> {
|
||||
val array = value ?: DoubleArray(orNumberOfZeros!!)
|
||||
return when (dt) {
|
||||
DataType.ARRAY_UB ->
|
||||
// byte array can never contain pointer-to types, so treat values as all integers
|
||||
array.map {
|
||||
val number = (it as NumericLiteral).number.toInt()
|
||||
val number = it.toInt()
|
||||
"$"+number.toString(16).padStart(2, '0')
|
||||
}
|
||||
DataType.ARRAY_B ->
|
||||
// byte array can never contain pointer-to types, so treat values as all integers
|
||||
array.map {
|
||||
val number = (it as NumericLiteral).number.toInt()
|
||||
val number = it.toInt()
|
||||
val hexnum = number.absoluteValue.toString(16).padStart(2, '0')
|
||||
if(number>=0)
|
||||
"$$hexnum"
|
||||
@ -626,11 +651,11 @@ internal class ProgramAndVarsGen(
|
||||
"-$$hexnum"
|
||||
}
|
||||
DataType.ARRAY_UW -> array.map {
|
||||
val number = (it as NumericLiteral).number.toInt()
|
||||
val number = it.toInt()
|
||||
"$" + number.toString(16).padStart(4, '0')
|
||||
}
|
||||
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')
|
||||
if(number>=0)
|
||||
"$$hexnum"
|
||||
|
@ -5,7 +5,6 @@ import com.github.michaelbull.result.onSuccess
|
||||
import prog8.ast.base.ArrayDatatypes
|
||||
import prog8.ast.base.DataType
|
||||
import prog8.ast.base.IntegerDatatypes
|
||||
import prog8.ast.expressions.StringLiteral
|
||||
import prog8.ast.statements.Subroutine
|
||||
import prog8.ast.statements.ZeropageWish
|
||||
import prog8.compilerinterface.*
|
||||
@ -53,7 +52,6 @@ internal class VariableAllocator(private val symboltable: SymbolTable,
|
||||
variable.scopedName,
|
||||
variable.dt,
|
||||
numElements,
|
||||
variable.initialvalue,
|
||||
variable.position,
|
||||
errors
|
||||
)
|
||||
@ -74,7 +72,6 @@ internal class VariableAllocator(private val symboltable: SymbolTable,
|
||||
variable.scopedName,
|
||||
variable.dt,
|
||||
numElements,
|
||||
variable.initialvalue,
|
||||
variable.position,
|
||||
errors
|
||||
)
|
||||
@ -95,7 +92,6 @@ internal class VariableAllocator(private val symboltable: SymbolTable,
|
||||
variable.scopedName,
|
||||
variable.dt,
|
||||
numElements,
|
||||
variable.initialvalue,
|
||||
variable.position,
|
||||
errors
|
||||
)
|
||||
@ -130,7 +126,7 @@ internal class VariableAllocator(private val symboltable: SymbolTable,
|
||||
|
||||
private fun numArrayElements(variable: StStaticVariable) =
|
||||
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!!
|
||||
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.
|
||||
// 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) {
|
||||
allocatedVariables[listOf("cx16", "r${reg}")] = ZpAllocation((2+reg*2).toUInt(), DataType.UWORD, 2, null, null) // 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}L")] = ZpAllocation((2+reg*2).toUInt(), DataType.UBYTE, 1, null, null) // 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}sL")] = ZpAllocation((2+reg*2).toUInt(), DataType.BYTE, 1, null, null) // 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}")] = 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) // cx16.r0s .. cx16.r15s
|
||||
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) // cx16.r0H .. cx16.r15H
|
||||
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) // cx16.r0sH .. cx16.r15sH
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -3,7 +3,9 @@ package prog8.compiler.astprocessing
|
||||
import prog8.ast.Program
|
||||
import prog8.ast.base.Position
|
||||
import prog8.ast.base.VarDeclType
|
||||
import prog8.ast.expressions.ArrayLiteral
|
||||
import prog8.ast.expressions.NumericLiteral
|
||||
import prog8.ast.expressions.StringLiteral
|
||||
import prog8.ast.statements.Block
|
||||
import prog8.ast.statements.Label
|
||||
import prog8.ast.statements.Subroutine
|
||||
@ -49,7 +51,14 @@ internal class SymbolTableMaker: IAstVisitor {
|
||||
override fun visit(decl: VarDecl) {
|
||||
val node =
|
||||
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.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
|
||||
}
|
||||
|
||||
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) {
|
||||
val node = StNode(label.name, StNodeType.LABEL, label.position)
|
||||
scopestack.peek().add(node)
|
||||
|
@ -71,10 +71,10 @@ private fun makeSt(): SymbolTable {
|
||||
block1.add(sub12)
|
||||
block1.add(StConstant("c1", DataType.UWORD, 12345.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("v2", DataType.BYTE, null, null, ZeropageWish.DONTCARE, Position.DUMMY))
|
||||
sub12.add(StStaticVariable("v1", DataType.BYTE, null, null, ZeropageWish.DONTCARE, Position.DUMMY))
|
||||
sub12.add(StStaticVariable("v2", 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, 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, null, null, ZeropageWish.DONTCARE, Position.DUMMY))
|
||||
|
||||
val block2 = StNode("block2", StNodeType.BLOCK, Position.DUMMY)
|
||||
val sub21 = StNode("sub1", StNodeType.SUBROUTINE, Position.DUMMY)
|
||||
|
@ -64,26 +64,26 @@ class TestC64Zeropage: FunSpec({
|
||||
test("testNames") {
|
||||
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 = zp.allocate(emptyList(), DataType.UBYTE, null, null, null, errors)
|
||||
result = zp.allocate(emptyList(), DataType.UBYTE, null, null, errors)
|
||||
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()) }
|
||||
shouldThrow<IllegalArgumentException> { zp.allocate(listOf("varname"), DataType.UBYTE,null, null, null, errors) }
|
||||
result = zp.allocate(listOf("varname2"), 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, errors)
|
||||
result.onFailure { fail(it.toString()) }
|
||||
}
|
||||
|
||||
test("testZpFloatEnable") {
|
||||
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" }
|
||||
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" }
|
||||
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") {
|
||||
@ -105,7 +105,7 @@ class TestC64Zeropage: FunSpec({
|
||||
val zp = C64Zeropage(CompilationOptions(OutputType.RAW, CbmPrgLauncherType.NONE, ZeropageType.DONTUSE, emptyList(), false, false, c64target))
|
||||
println(zp.free)
|
||||
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" }
|
||||
}
|
||||
|
||||
@ -118,9 +118,9 @@ class TestC64Zeropage: FunSpec({
|
||||
zp3.availableBytes() shouldBe 125
|
||||
val zp4 = C64Zeropage(CompilationOptions(OutputType.RAW, CbmPrgLauncherType.NONE, ZeropageType.FULL, emptyList(), false, false, c64target))
|
||||
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.allocate(listOf("test2"), DataType.UBYTE, null, null, null, errors)
|
||||
zp4.allocate(listOf("test2"), DataType.UBYTE, null, null, errors)
|
||||
zp4.availableBytes() shouldBe 237
|
||||
}
|
||||
|
||||
@ -151,19 +151,19 @@ class TestC64Zeropage: FunSpec({
|
||||
zp.hasByteAvailable() 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" }
|
||||
|
||||
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 }
|
||||
}
|
||||
zp.availableBytes() shouldBe 0
|
||||
zp.hasByteAvailable() 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 = zp.allocate(emptyList(), DataType.UWORD, null, null, null, errors)
|
||||
result = zp.allocate(emptyList(), DataType.UWORD, null, null, errors)
|
||||
result.expectError { "expected allocation error" }
|
||||
}
|
||||
|
||||
@ -172,47 +172,47 @@ class TestC64Zeropage: FunSpec({
|
||||
zp.availableBytes() shouldBe 239
|
||||
zp.hasByteAvailable() 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
|
||||
loc shouldBeGreaterThan 3u
|
||||
loc shouldNotBeIn zp.free
|
||||
val num = zp.availableBytes() / 2
|
||||
|
||||
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
|
||||
|
||||
// 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" }
|
||||
|
||||
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.hasByteAvailable() 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" }
|
||||
}
|
||||
|
||||
test("testEfficientAllocation") {
|
||||
val zp = C64Zeropage(CompilationOptions(OutputType.RAW, CbmPrgLauncherType.NONE, ZeropageType.BASICSAFE, emptyList(), true, false, c64target))
|
||||
zp.availableBytes() shouldBe 18
|
||||
zp.allocate(emptyList(), DataType.WORD, null, 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, 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, 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, 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.UBYTE, null, 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, 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.WORD, null, null, errors).getOrElse{throw it}.first shouldBe 0x04u
|
||||
zp.allocate(emptyList(), DataType.UBYTE, null, null, errors).getOrElse{throw it}.first shouldBe 0x06u
|
||||
zp.allocate(emptyList(), DataType.UBYTE, null, null, errors).getOrElse{throw it}.first shouldBe 0x0au
|
||||
zp.allocate(emptyList(), DataType.UWORD, null, null, errors).getOrElse{throw it}.first shouldBe 0x9bu
|
||||
zp.allocate(emptyList(), DataType.UWORD, null, null, errors).getOrElse{throw it}.first shouldBe 0x9eu
|
||||
zp.allocate(emptyList(), DataType.UWORD, null, null, errors).getOrElse{throw it}.first shouldBe 0xa5u
|
||||
zp.allocate(emptyList(), DataType.UWORD, null, null, errors).getOrElse{throw it}.first shouldBe 0xb0u
|
||||
zp.allocate(emptyList(), DataType.UWORD, null, null, errors).getOrElse{throw it}.first shouldBe 0xbeu
|
||||
zp.allocate(emptyList(), DataType.UBYTE, null, null, errors).getOrElse{throw it}.first shouldBe 0x0eu
|
||||
zp.allocate(emptyList(), DataType.UBYTE, null, null, errors).getOrElse{throw it}.first shouldBe 0x92u
|
||||
zp.allocate(emptyList(), DataType.UBYTE, null, null, errors).getOrElse{throw it}.first shouldBe 0x96u
|
||||
zp.allocate(emptyList(), DataType.UBYTE, null, null, errors).getOrElse{throw it}.first shouldBe 0xf9u
|
||||
zp.availableBytes() shouldBe 0
|
||||
}
|
||||
|
||||
@ -243,9 +243,9 @@ class TestCx16Zeropage: FunSpec({
|
||||
zp2.availableBytes() shouldBe 175
|
||||
val zp3 = CX16Zeropage(CompilationOptions(OutputType.RAW, CbmPrgLauncherType.NONE, ZeropageType.FULL, emptyList(), false, false, cx16target))
|
||||
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.allocate(listOf("test2"), DataType.UBYTE, null, null, null, errors)
|
||||
zp3.allocate(listOf("test2"), DataType.UBYTE, null, null, errors)
|
||||
zp3.availableBytes() shouldBe 214
|
||||
}
|
||||
|
||||
|
@ -3,7 +3,6 @@ package prog8.compilerinterface
|
||||
import prog8.ast.Node
|
||||
import prog8.ast.base.DataType
|
||||
import prog8.ast.base.Position
|
||||
import prog8.ast.expressions.Expression
|
||||
import prog8.ast.statements.ZeropageWish
|
||||
import prog8.ast.toHex
|
||||
|
||||
@ -123,15 +122,26 @@ open class StNode(val name: String,
|
||||
|
||||
class StStaticVariable(name: String,
|
||||
val dt: DataType,
|
||||
val initialvalue: Expression?,
|
||||
val initialNumericValue: Double?,
|
||||
val initialStringValue: Pair<String, Encoding>?,
|
||||
val initialArrayValue: DoubleArray?,
|
||||
val arraysize: Int?,
|
||||
val zpw: ZeropageWish,
|
||||
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() {
|
||||
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) :
|
||||
StNode(name, StNodeType.CONSTANT, position) {
|
||||
override fun printProperties() {
|
||||
|
@ -4,9 +4,6 @@ import com.github.michaelbull.result.Err
|
||||
import com.github.michaelbull.result.Ok
|
||||
import com.github.michaelbull.result.Result
|
||||
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)
|
||||
@ -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_W2 : UInt // temp storage 2 for a word $fb+$fc
|
||||
|
||||
data class ZpAllocation(val address: UInt,
|
||||
val dt: DataType,
|
||||
val size: Int,
|
||||
val initialStringValue: StringLiteral?,
|
||||
val initialArrayValue: ArrayLiteral?)
|
||||
data class ZpAllocation(val address: UInt, val dt: DataType, val size: Int)
|
||||
|
||||
// the variables allocated into Zeropage.
|
||||
// name (scoped) ==> pair of address to (Datatype + bytesize)
|
||||
@ -52,7 +45,6 @@ abstract class Zeropage(protected val options: CompilationOptions) {
|
||||
fun allocate(name: List<String>,
|
||||
datatype: DataType,
|
||||
numElements: Int?,
|
||||
initValue: Expression?,
|
||||
position: Position?,
|
||||
errors: IErrorReporter): Result<Pair<UInt, Int>, ZeropageAllocationError> {
|
||||
|
||||
@ -90,13 +82,13 @@ abstract class Zeropage(protected val options: CompilationOptions) {
|
||||
if(size==1) {
|
||||
for(candidate in free.minOrNull()!! .. free.maxOrNull()!!+1u) {
|
||||
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) {
|
||||
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 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)
|
||||
free.removeAll(address until address+size.toUInt())
|
||||
if(name.isNotEmpty()) {
|
||||
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
|
||||
DataType.STR -> ZpAllocation(address, datatype, size, initValue as? StringLiteral, null)
|
||||
in ArrayDatatypes -> ZpAllocation(address, datatype, size, null, initValue as? ArrayLiteral)
|
||||
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)
|
||||
in ArrayDatatypes -> ZpAllocation(address, datatype, size)
|
||||
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 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