retain constants in IR

some IR related cleanups
This commit is contained in:
Irmen de Jong 2024-12-23 23:29:33 +01:00
parent 4c1e2f3110
commit 5071da6784
15 changed files with 158 additions and 141 deletions

View File

@ -42,6 +42,7 @@ class SymbolTable(astProgram: PtProgram) : StNode(astProgram.name, StNodeType.GL
}
val allVariables: Collection<StStaticVariable> by lazy {
// can't be done with a generic function because those don't support local recursive functions yet
val vars = mutableListOf<StStaticVariable>()
fun collect(node: StNode) {
for(child in node.children) {
@ -56,6 +57,7 @@ class SymbolTable(astProgram: PtProgram) : StNode(astProgram.name, StNodeType.GL
}
val allMemMappedVariables: Collection<StMemVar> by lazy {
// can't be done with a generic function because those don't support local recursive functions yet
val vars = mutableListOf<StMemVar>()
fun collect(node: StNode) {
for(child in node.children) {
@ -70,6 +72,7 @@ class SymbolTable(astProgram: PtProgram) : StNode(astProgram.name, StNodeType.GL
}
val allMemorySlabs: Collection<StMemorySlab> by lazy {
// can't be done with a generic function because those don't support local recursive functions yet
val vars = mutableListOf<StMemorySlab>()
fun collect(node: StNode) {
for(child in node.children) {
@ -113,7 +116,7 @@ enum class StNodeType {
open class StNode(val name: String,
val type: StNodeType,
val astNode: PtNode,
val astNode: PtNode?,
val children: MutableMap<String, StNode> = mutableMapOf()
) {
@ -187,7 +190,7 @@ class StStaticVariable(name: String,
val length: Int?, // for arrays: the number of elements, for strings: number of characters *including* the terminating 0-byte
val zpwish: ZeropageWish, // used in the variable allocator
val align: Int,
astNode: PtNode) : StNode(name, StNodeType.STATICVAR, astNode) {
astNode: PtNode?) : StNode(name, StNodeType.STATICVAR, astNode) {
var initializationNumericValue: Double? = null
private set
@ -229,7 +232,7 @@ class StStaticVariable(name: String,
}
class StConstant(name: String, val dt: BaseDataType, val value: Double, astNode: PtNode) :
class StConstant(name: String, val dt: BaseDataType, val value: Double, astNode: PtNode?) :
StNode(name, StNodeType.CONSTANT, astNode)
@ -237,7 +240,7 @@ class StMemVar(name: String,
val dt: DataType,
val address: UInt,
val length: Int?, // for arrays: the number of elements, for strings: number of characters *including* the terminating 0-byte
astNode: PtNode) :
astNode: PtNode?) :
StNode(name, StNodeType.MEMVAR, astNode) {
init{
@ -251,7 +254,7 @@ class StMemorySlab(
name: String,
val size: UInt,
val align: UInt,
astNode: PtNode
astNode: PtNode?
):
StNode(name, StNodeType.MEMORYSLAB, astNode)

View File

@ -59,7 +59,7 @@ class AsmGen6502(val prefixSymbols: Boolean, private val lastGeneratedLabelSeque
}
is PtFunctionCall -> {
val stNode = st.lookup(node.name)!!
if(stNode.astNode.definingBlock()?.options?.noSymbolPrefixing!=true) {
if(stNode.astNode!!.definingBlock()?.options?.noSymbolPrefixing!=true) {
val index = node.parent.children.indexOf(node)
functionCallsToPrefix += node.parent to index
}
@ -70,7 +70,7 @@ class AsmGen6502(val prefixSymbols: Boolean, private val lastGeneratedLabelSeque
lookupName = lookupName.dropLast(4)
}
val stNode = st.lookup(lookupName) ?: throw AssemblyError("unknown identifier $node")
if(stNode.astNode.definingBlock()?.options?.noSymbolPrefixing!=true) {
if(stNode.astNode!!.definingBlock()?.options?.noSymbolPrefixing!=true) {
val index = node.parent.children.indexOf(node)
nodesToPrefix += node.parent to index
}
@ -1268,7 +1268,7 @@ $repeatLabel""")
val node = stScope.astNode
if(node is PtSubroutineParameter)
return node
return node.definingSub()?.parameters?.singleOrNull { it.name===name }
return node!!.definingSub()?.parameters?.singleOrNull { it.name===name }
}
internal fun assignByteOperandsToAAndVar(left: PtExpression, right: PtExpression, rightVarName: String) {

View File

@ -60,7 +60,7 @@ internal class VariableAllocator(private val symboltable: SymbolTable,
variable.scopedName,
variable.dt,
variable.length,
variable.astNode.position,
variable.astNode?.position ?: Position.DUMMY,
errors
)
result.fold(
@ -68,7 +68,7 @@ internal class VariableAllocator(private val symboltable: SymbolTable,
numVariablesAllocatedInZP++
},
failure = {
errors.err(it.message!!, variable.astNode.position)
errors.err(it.message!!, variable.astNode?.position ?: Position.DUMMY)
}
)
}
@ -79,7 +79,7 @@ internal class VariableAllocator(private val symboltable: SymbolTable,
variable.scopedName,
variable.dt,
variable.length,
variable.astNode.position,
variable.astNode?.position ?: Position.DUMMY,
errors
)
result.onSuccess { numVariablesAllocatedInZP++ }
@ -99,7 +99,7 @@ internal class VariableAllocator(private val symboltable: SymbolTable,
variable.scopedName,
variable.dt,
variable.length,
variable.astNode.position,
variable.astNode?.position ?: Position.DUMMY,
errors
)
result.onSuccess { numVariablesAllocatedInZP++ }

View File

@ -25,7 +25,7 @@ class IRCodeGen(
verifyNameScoping(program, symbolTable)
changeGlobalVarInits(symbolTable)
val irSymbolTable = IRSymbolTable.fromStDuringCodegen(symbolTable)
val irSymbolTable = IRSymbolTable.fromAstSymboltable(symbolTable)
val irProg = IRProgram(program.name, irSymbolTable, options, program.encoding)
// collect global variables initializers
@ -486,7 +486,7 @@ class IRCodeGen(
it += IRInstruction(Opcode.STOREM, irType(DataType.forDt(elementDt)), reg1=tmpReg, labelSymbol = loopvarSymbol)
}
result += translateNode(forLoop.statements)
result += addConstReg(IRDataType.BYTE, indexReg, elementSize)
result += addConstIntToReg(IRDataType.BYTE, indexReg, elementSize)
result += IRCodeChunk(null, null).also {
if(lengthBytes!=256) {
// for length 256, the compare is actually against 0, which doesn't require a separate CMP instruction
@ -639,7 +639,7 @@ class IRCodeGen(
return result
}
private fun addConstReg(dt: IRDataType, reg: Int, value: Int): IRCodeChunk {
private fun addConstIntToReg(dt: IRDataType, reg: Int, value: Int): IRCodeChunk {
val code = IRCodeChunk(null, null)
when(value) {
0 -> { /* do nothing */ }

View File

@ -94,7 +94,7 @@ private fun integrateDefers(subdefers: Map<PtSub, List<PtDefer>>, program: PtPro
val identifier = node.target as? PtIdentifier
if (identifier != null) {
val stNode = st.lookup(identifier.name)!!
val targetSub = stNode.astNode.definingSub()
val targetSub = stNode.astNode!!.definingSub()
if (targetSub != node.definingSub())
jumpsAndCallsToAugment.add(node)
}

View File

@ -23,6 +23,8 @@ class TestLaunchEmu: FunSpec({
</VARIABLESNOINIT>
<VARIABLESWITHINIT>
</VARIABLESWITHINIT>
<CONSTANTS>
</CONSTANTS>
<MEMORYMAPPEDVARIABLES>
</MEMORYMAPPEDVARIABLES>

View File

@ -21,7 +21,7 @@ class TestSymbolTable: FunSpec({
st.type shouldBe StNodeType.GLOBAL
st.children shouldBe mutableMapOf()
st.astNode shouldBeSameInstanceAs astNode
st.astNode.position shouldBe Position.DUMMY
st.astNode!!.position shouldBe Position.DUMMY
}
test("symboltable flatten") {

View File

@ -46,8 +46,9 @@ Future Things and Ideas
IR/VM
-----
- cx16.r0-r15 should not be translated to their (fake) addresses but remain symbolical, so they can be translated to what the actual target system specifies for them.
- prefix immediate values with '#' for readability reasons (no technical reason)
- ExpressionCodeResult: get rid of the separation between single result register and multiple result registers?
- constants are not retained in the IR file, they should. (need to be able to make asm labels from them eventually)
- implement missing operators in AssignmentGen (array shifts etc)
- support %align on code chunks
- fix call() return value handling

View File

@ -1,40 +1,14 @@
%import sprites
%import palette
%import math
%zeropage basicsafe
%option no_sysinit
main {
sub start() {
word[128] xpos
word[128] ypos
const ubyte CVALUE = 123
const long CLONG = 555555
ubyte @shared vvalue = 99
for cx16.r2L in 0 to 127 {
sprites.init(cx16.r2L, 0, 0, sprites.SIZE_8, sprites.SIZE_8, sprites.COLORS_16, 0)
xpos[cx16.r2L] = math.rndw() & 511 as word + 64
ypos[cx16.r2L] = math.rnd()
}
repeat {
sys.waitvsync()
palette.set_color(6, $f00)
sprites.pos_batch(0, 128, &xpos, &ypos)
palette.set_color(6, $0f0)
for cx16.r2L in 0 to 127 {
if cx16.r2L & 1 == 0 {
xpos[cx16.r2L] ++
if xpos[cx16.r2L] > 640
xpos[cx16.r2L] = 0
} else {
ypos[cx16.r2L] ++
if ypos[cx16.r2L] > 480
ypos[cx16.r2L] = 0
}
}
palette.set_color(6, $00f)
}
cx16.r0L = CVALUE + 100
cx16.r1L = vvalue + 100
}
}

View File

@ -1,6 +1,7 @@
package prog8.intermediate
import prog8.code.*
import prog8.code.ast.PtConstant
import prog8.code.ast.PtVariable
import prog8.code.core.*
import prog8.code.target.VMTarget
@ -52,6 +53,7 @@ class IRFileReader {
val asmsymbols = parseAsmSymbols(reader)
val varsWithoutInit = parseVarsWithoutInit(reader)
val variables = parseVariables(reader)
val constants = parseConstants(reader)
val memorymapped = parseMemMapped(reader)
val slabs = parseSlabs(reader)
val initGlobals = parseInitGlobals(reader)
@ -61,6 +63,7 @@ class IRFileReader {
asmsymbols.forEach { (name, value) -> st.addAsmSymbol(name, value)}
varsWithoutInit.forEach { st.add(it) }
variables.forEach { st.add(it) }
constants.forEach { st.add(it) }
memorymapped.forEach { st.add(it) }
slabs.forEach { st.add(it) }
@ -165,19 +168,45 @@ class IRFileReader {
val match = varPattern.matchEntire(line) ?: throw IRParseException("invalid VARIABLESNOINIT $line")
val (type, arrayspec, name, zpwish, alignment) = match.destructured
if('.' !in name)
throw IRParseException("unscoped varname: $name")
throw IRParseException("unscoped name: $name")
val arraysize = if(arrayspec.isNotBlank()) arrayspec.substring(1, arrayspec.length-1).toInt() else null
val dt = parseDatatype(type, arraysize!=null)
val zp = if(zpwish.isBlank()) ZeropageWish.DONTCARE else ZeropageWish.valueOf(zpwish)
val align = if(alignment.isBlank()) 0u else alignment.toUInt()
val dummyNode = PtVariable(name, dt, zp, align, null, null, Position.DUMMY)
val newVar = StStaticVariable(name, dt, null, null, arraysize, zp, align.toInt(), dummyNode)
val newVar = StStaticVariable(name, dt, null, null, arraysize, zp, align.toInt(), null)
variables.add(newVar)
}
return variables
}
}
private fun parseConstants(reader: XMLEventReader): List<StConstant> {
skipText(reader)
val start = reader.nextEvent().asStartElement()
require(start.name.localPart=="CONSTANTS") { "missing CONSTANTS" }
val text = readText(reader).trim()
require(reader.nextEvent().isEndElement)
return if(text.isBlank())
emptyList()
else {
val constantPattern = Regex("(.+?) (.+)=(.*?)")
val constants = mutableListOf<StConstant>()
text.lineSequence().forEach { line ->
// examples:
// uword main.start.qq2=0
val match = constantPattern.matchEntire(line) ?: throw IRParseException("invalid CONSTANT $line")
val (type, name, valueStr) = match.destructured
if('.' !in name)
throw IRParseException("unscoped name: $name")
val dt = parseDatatype(type, false)
val value = parseIRValue(valueStr)
constants.add(StConstant(name, dt.base, value, null))
}
return constants
}
}
private fun parseVariables(reader: XMLEventReader): List<StStaticVariable> {
skipText(reader)
val start = reader.nextEvent().asStartElement()
@ -223,11 +252,10 @@ class IRFileReader {
dt.isString -> throw IRParseException("STR should have been converted to byte array")
else -> throw IRParseException("weird dt")
}
val dummyNode = PtVariable(name, dt, zp, align, null, null, Position.DUMMY)
if(arraysize!=null && initArray!=null && initArray.all { it.number==0.0 }) {
initArray=null // arrays with just zeros can be left uninitialized
}
val stVar = StStaticVariable(name, dt, null, initArray, arraysize, zp, align.toInt(), dummyNode)
val stVar = StStaticVariable(name, dt, null, initArray, arraysize, zp, align.toInt(), null)
if(initNumeric!=null)
stVar.setOnetimeInitNumeric(initNumeric)
variables.add(stVar)
@ -256,16 +284,7 @@ class IRFileReader {
val (type, arrayspec, name, address) = match.destructured
val arraysize = if(arrayspec.isNotBlank()) arrayspec.substring(1, arrayspec.length-1).toInt() else null
val dt = parseDatatype(type, arraysize!=null)
val dummyNode = PtVariable(
name,
dt,
ZeropageWish.NOT_IN_ZEROPAGE,
0u,
null,
null,
Position.DUMMY
)
memvars.add(StMemVar(name, dt, parseIRValue(address).toUInt(), arraysize, dummyNode))
memvars.add(StMemVar(name, dt, parseIRValue(address).toUInt(), arraysize, null))
}
memvars
}
@ -287,16 +306,7 @@ class IRFileReader {
// example: "slabname 4096 0"
val match = slabPattern.matchEntire(line) ?: throw IRParseException("invalid slab $line")
val (name, size, align) = match.destructured
val dummyNode = PtVariable(
name,
DataType.arrayFor(BaseDataType.UBYTE, false),
ZeropageWish.NOT_IN_ZEROPAGE,
0u,
null,
null,
Position.DUMMY
)
slabs.add(StMemorySlab(name, size.toUInt(), align.toUInt(), dummyNode))
slabs.add(StMemorySlab(name, size.toUInt(), align.toUInt(), null))
}
slabs
}
@ -520,6 +530,7 @@ class IRFileReader {
"word" -> DataType.arrayFor(BaseDataType.WORD, false)
"uword" -> DataType.arrayFor(BaseDataType.UWORD, false)
"float" -> DataType.arrayFor(BaseDataType.FLOAT, false)
"long" -> DataType.arrayFor(BaseDataType.LONG, false)
else -> throw IRParseException("invalid dt $type")
}
} else {
@ -530,6 +541,7 @@ class IRFileReader {
"word" -> DataType.forDt(BaseDataType.WORD)
"uword" -> DataType.forDt(BaseDataType.UWORD)
"float" -> DataType.forDt(BaseDataType.FLOAT)
"long" -> DataType.forDt(BaseDataType.LONG)
// note: 'str' should not occur anymore in IR. Should be 'uword'
else -> throw IRParseException("invalid dt $type")
}

View File

@ -148,10 +148,13 @@ class IRFileWriter(private val irProgram: IRProgram, outfileOverride: Path?) {
if(code.sourceLinesPositions.any {it !== Position.DUMMY}) {
xml.writeStartElement("P8SRC")
val sourceTxt = StringBuilder("\n")
code.sourceLinesPositions.filter{ pos -> pos.line>0 }.forEach { pos ->
val line = ImportFileSystem.retrieveSourceLine(pos)
sourceTxt.append("$pos $line\n")
}
code.sourceLinesPositions
.filter{ pos -> pos.line > 0 }
.sortedBy { it.line }
.forEach { pos ->
val line = ImportFileSystem.retrieveSourceLine(pos)
sourceTxt.append("$pos $line\n")
}
xml.writeCData(sourceTxt.toString())
xml.writeEndElement()
}
@ -212,6 +215,17 @@ class IRFileWriter(private val irProgram: IRProgram, outfileOverride: Path?) {
}
}
fun writeConstant(constant: IRStConstant) {
val dt = constant.dt
val value: String = when {
dt.isBool -> constant.value.toInt().toString()
dt.isFloat -> constant.value.toString()
dt.isInteger -> constant.value.toInt().toHex()
else -> throw InternalCompilerException("weird dt")
}
xml.writeCharacters("${constant.typeString} ${constant.name}=$value\n")
}
fun writeVarWithInit(variable: IRStStaticVariable) {
if(variable.dt.isSplitWordArray) {
val lsbValue: String
@ -240,7 +254,7 @@ class IRFileWriter(private val irProgram: IRProgram, outfileOverride: Path?) {
val value: String = when {
dt.isBool -> variable.onetimeInitializationNumericValue?.toInt()?.toString() ?: ""
dt.isFloat -> (variable.onetimeInitializationNumericValue ?: "").toString()
dt.isNumeric -> variable.onetimeInitializationNumericValue?.toInt()?.toHex() ?: ""
dt.isInteger -> variable.onetimeInitializationNumericValue?.toInt()?.toHex() ?: ""
dt.isString -> {
val encoded = irProgram.encoding.encodeString(variable.onetimeInitializationStringValue!!.first, variable.onetimeInitializationStringValue.second) + listOf(0u)
encoded.joinToString(",") { it.toInt().toString() }
@ -285,12 +299,11 @@ class IRFileWriter(private val irProgram: IRProgram, outfileOverride: Path?) {
for (variable in noinitAligned.sortedBy { it.align }) {
writeNoInitVar(variable)
}
xml.writeEndElement()
xml.writeCharacters("\n")
xml.writeStartElement("VARIABLESWITHINIT")
xml.writeCharacters("\n")
val (initNotAligned, initAligned) = variablesWithInit.partition { it.align==0 || it.align==1 }
for (variable in initNotAligned) {
writeVarWithInit(variable)
@ -301,6 +314,14 @@ class IRFileWriter(private val irProgram: IRProgram, outfileOverride: Path?) {
xml.writeEndElement()
xml.writeCharacters("\n")
xml.writeStartElement("CONSTANTS")
xml.writeCharacters("\n")
for (constant in irProgram.st.allConstants()) {
writeConstant(constant)
}
xml.writeEndElement()
xml.writeCharacters("\n")
xml.writeStartElement("MEMORYMAPPEDVARIABLES")
xml.writeCharacters("\n")
for (variable in irProgram.st.allMemMappedVariables()) {

View File

@ -11,6 +11,7 @@ PROGRAM:
OPTIONS (from CompilationOptions)
ASMSYMBOLS (from command line defined symbols)
VARIABLES (from Symboltable)
CONSTANTS (form Symboltable)
MEMORYMAPPEDVARIABLES (from Symboltable)
MEMORYSLABS (from Symboltable)
INITGLOBALS

View File

@ -13,17 +13,17 @@ class IRSymbolTable {
private val asmSymbols = mutableMapOf<String, String>()
companion object {
fun fromStDuringCodegen(sourceSt: SymbolTable?): IRSymbolTable {
fun fromAstSymboltable(sourceSt: SymbolTable?): IRSymbolTable {
val st = IRSymbolTable()
if (sourceSt != null) {
sourceSt.allVariables.forEach {
st.add(it)
}
sourceSt.allMemMappedVariables.forEach {
st.add(it)
}
sourceSt.allMemorySlabs.forEach {
st.add(it)
sourceSt.flat.forEach {
when(it.value.type) {
StNodeType.STATICVAR -> st.add(it.value as StStaticVariable)
StNodeType.MEMVAR -> st.add(it.value as StMemVar)
StNodeType.CONSTANT -> st.add(it.value as StConstant)
StNodeType.MEMORYSLAB -> st.add(it.value as StMemorySlab)
else -> { }
}
}
require(st.table.all { it.key == it.value.name })
@ -44,6 +44,9 @@ class IRSymbolTable {
}
}
fun allConstants(): Sequence<IRStConstant> =
table.asSequence().map { it.value }.filterIsInstance<IRStConstant>()
fun allVariables(): Sequence<IRStStaticVariable> =
table.asSequence().map { it.value }.filterIsInstance<IRStStaticVariable>()
@ -60,7 +63,14 @@ class IRSymbolTable {
val varToadd: IRStStaticVariable
if('.' in variable.name) {
scopedName = variable.name
varToadd = IRStStaticVariable.from(variable)
varToadd = IRStStaticVariable(variable.name,
variable.dt,
variable.initializationNumericValue,
variable.initializationStringValue,
variable.initializationArrayValue?.map { convertArrayElt(it) },
variable.length,
variable.zpwish,
variable.align)
} else {
fun fixupAddressOfInArray(array: List<StArrayElement>?): List<IRStArrayElement>? {
if(array==null)
@ -71,7 +81,7 @@ class IRSymbolTable {
val target = variable.lookup(it.addressOfSymbol!!) ?: throw NoSuchElementException("can't find variable ${it.addressOfSymbol}")
newArray.add(IRStArrayElement(null, null, target.scopedName))
} else {
newArray.add(IRStArrayElement.from(it))
newArray.add(convertArrayElt(it))
}
}
return newArray
@ -90,13 +100,17 @@ class IRSymbolTable {
table[scopedName] = varToadd
}
fun add(variable: StMemVar) {
val scopedName: String
val varToadd: IRStMemVar
if('.' in variable.name) {
scopedName = variable.name
varToadd = IRStMemVar.from(variable)
varToadd = IRStMemVar(
variable.name,
variable.dt,
variable.address,
variable.length
)
} else {
scopedName = try {
variable.scopedName
@ -110,13 +124,28 @@ class IRSymbolTable {
fun add(variable: StMemorySlab) {
val varToadd = if('.' in variable.name)
IRStMemorySlab.from(variable)
IRStMemorySlab(variable.name, variable.size, variable.align)
else {
IRStMemorySlab("prog8_slabs.${variable.name}", variable.size, variable.align)
}
table[varToadd.name] = varToadd
}
fun add(constant: StConstant) {
val scopedName: String
val dt = DataType.forDt(constant.dt)
if('.' in constant.name) {
scopedName = constant.name
} else {
scopedName = try {
constant.scopedName
} catch (_: UninitializedPropertyAccessException) {
constant.name
}
}
table[scopedName] = IRStConstant(scopedName, dt, constant.value)
}
fun addAsmSymbol(name: String, value: String) {
asmSymbols[name] = value
}
@ -133,15 +162,20 @@ class IRSymbolTable {
}
}
}
private fun convertArrayElt(elt: StArrayElement): IRStArrayElement = if(elt.boolean!=null)
IRStArrayElement(elt.boolean, null, elt.addressOfSymbol)
else
IRStArrayElement(null, elt.number, elt.addressOfSymbol)
}
enum class IRStNodeType {
STATICVAR,
MEMVAR,
MEMORYSLAB
// the other StNodeType types aren't used here anymore.
// this symbol table only contains variables.
MEMORYSLAB,
CONST
}
open class IRStNode(val name: String,
@ -154,17 +188,6 @@ class IRStMemVar(name: String,
val address: UInt,
val length: Int? // for arrays: the number of elements, for strings: number of characters *including* the terminating 0-byte
) : IRStNode(name, IRStNodeType.MEMVAR) {
companion object {
fun from(variable: StMemVar): IRStMemVar {
return IRStMemVar(
variable.name,
variable.dt,
variable.address,
variable.length
)
}
}
init {
require(!dt.isString)
}
@ -176,18 +199,14 @@ class IRStMemorySlab(
name: String,
val size: UInt,
val align: UInt
): IRStNode(name, IRStNodeType.MEMORYSLAB) {
companion object {
fun from(variable: StMemorySlab): IRStMemorySlab {
return IRStMemorySlab(
variable.name,
variable.size,
variable.align
)
}
}
): IRStNode(name, IRStNodeType.MEMORYSLAB)
class IRStConstant(name: String, val dt: DataType, val value: Double) : IRStNode(name, IRStNodeType.CONST) {
val typeString: String = dt.irTypeString(null)
}
class IRStStaticVariable(name: String,
val dt: DataType,
val onetimeInitializationNumericValue: Double?, // regular (every-run-time) initialization is done via regular assignments
@ -197,19 +216,6 @@ class IRStStaticVariable(name: String,
val zpwish: ZeropageWish, // used in the variable allocator
val align: Int
) : IRStNode(name, IRStNodeType.STATICVAR) {
companion object {
fun from(variable: StStaticVariable): IRStStaticVariable {
return IRStStaticVariable(variable.name,
variable.dt,
variable.initializationNumericValue,
variable.initializationStringValue,
variable.initializationArrayValue?.map { IRStArrayElement.from(it) },
variable.length,
variable.zpwish,
variable.align)
}
}
init {
if(align > 0) {
require(dt.isString || dt.isArray)
@ -223,15 +229,6 @@ class IRStStaticVariable(name: String,
}
class IRStArrayElement(val bool: Boolean?, val number: Double?, val addressOfSymbol: String?) {
companion object {
fun from(elt: StArrayElement): IRStArrayElement {
return if(elt.boolean!=null)
IRStArrayElement(elt.boolean, null, elt.addressOfSymbol)
else
IRStArrayElement(null, elt.number, elt.addressOfSymbol)
}
}
init {
if(bool!=null) require(number==null && addressOfSymbol==null)
if(number!=null) require(bool==null && addressOfSymbol==null)

View File

@ -58,6 +58,9 @@ uword sys.bssvar zp=DONTCARE align=0
uword sys.wait.jiffies=10 zp=DONTCARE align=0
ubyte[3] sys.emptystring=0,0,0 zp=DONTCARE align=0
</VARIABLESWITHINIT>
<CONSTANTS>
ubyte main.thing=42
</CONSTANTS>
<MEMORYMAPPEDVARIABLES>
@uword cx16.r0=65282
@ -104,6 +107,7 @@ return
program.name shouldBe "test-ir-reader"
program.blocks.size shouldBe 2
program.st.allVariables().count() shouldBe 3
program.st.allConstants().count() shouldBe 1
val var1 = program.st.lookup("sys.wait.jiffies") as IRStStaticVariable
val var2 = program.st.lookup("sys.bssvar") as IRStStaticVariable
val var3 = program.st.lookup("sys.emptystring") as IRStStaticVariable

View File

@ -105,6 +105,8 @@ class TestVm: FunSpec( {
</VARIABLESNOINIT>
<VARIABLESWITHINIT>
</VARIABLESWITHINIT>
<CONSTANTS>
</CONSTANTS>
<MEMORYMAPPEDVARIABLES>
</MEMORYMAPPEDVARIABLES>