From 5071da678438efec6f8ed592d024b6fba39ed19e Mon Sep 17 00:00:00 2001 From: Irmen de Jong Date: Mon, 23 Dec 2024 23:29:33 +0100 Subject: [PATCH] retain constants in IR some IR related cleanups --- codeCore/src/prog8/code/SymbolTable.kt | 13 +- .../src/prog8/codegen/cpu6502/AsmGen.kt | 6 +- .../codegen/cpu6502/VariableAllocator.kt | 8 +- .../prog8/codegen/intermediate/IRCodeGen.kt | 6 +- .../IntermediateAstPostprocess.kt | 2 +- compiler/test/TestLaunchEmu.kt | 2 + compiler/test/TestSymbolTable.kt | 2 +- docs/source/todo.rst | 3 +- examples/test.p8 | 36 +----- .../src/prog8/intermediate/IRFileReader.kt | 62 ++++++---- .../src/prog8/intermediate/IRFileWriter.kt | 35 ++++-- .../src/prog8/intermediate/IRProgram.kt | 1 + .../src/prog8/intermediate/IRSymbolTable.kt | 117 +++++++++--------- intermediate/test/TestIRFileInOut.kt | 4 + virtualmachine/test/TestVm.kt | 2 + 15 files changed, 158 insertions(+), 141 deletions(-) diff --git a/codeCore/src/prog8/code/SymbolTable.kt b/codeCore/src/prog8/code/SymbolTable.kt index 272d2f57e..b2ec2d2cc 100644 --- a/codeCore/src/prog8/code/SymbolTable.kt +++ b/codeCore/src/prog8/code/SymbolTable.kt @@ -42,6 +42,7 @@ class SymbolTable(astProgram: PtProgram) : StNode(astProgram.name, StNodeType.GL } val allVariables: Collection by lazy { + // can't be done with a generic function because those don't support local recursive functions yet val vars = mutableListOf() 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 by lazy { + // can't be done with a generic function because those don't support local recursive functions yet val vars = mutableListOf() 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 by lazy { + // can't be done with a generic function because those don't support local recursive functions yet val vars = mutableListOf() 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 = 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) diff --git a/codeGenCpu6502/src/prog8/codegen/cpu6502/AsmGen.kt b/codeGenCpu6502/src/prog8/codegen/cpu6502/AsmGen.kt index 2046d46e8..14589b5e0 100644 --- a/codeGenCpu6502/src/prog8/codegen/cpu6502/AsmGen.kt +++ b/codeGenCpu6502/src/prog8/codegen/cpu6502/AsmGen.kt @@ -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) { diff --git a/codeGenCpu6502/src/prog8/codegen/cpu6502/VariableAllocator.kt b/codeGenCpu6502/src/prog8/codegen/cpu6502/VariableAllocator.kt index 889feeb04..57a22f9d6 100644 --- a/codeGenCpu6502/src/prog8/codegen/cpu6502/VariableAllocator.kt +++ b/codeGenCpu6502/src/prog8/codegen/cpu6502/VariableAllocator.kt @@ -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++ } diff --git a/codeGenIntermediate/src/prog8/codegen/intermediate/IRCodeGen.kt b/codeGenIntermediate/src/prog8/codegen/intermediate/IRCodeGen.kt index 92123260a..4f1d859ab 100644 --- a/codeGenIntermediate/src/prog8/codegen/intermediate/IRCodeGen.kt +++ b/codeGenIntermediate/src/prog8/codegen/intermediate/IRCodeGen.kt @@ -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 */ } diff --git a/compiler/src/prog8/compiler/astprocessing/IntermediateAstPostprocess.kt b/compiler/src/prog8/compiler/astprocessing/IntermediateAstPostprocess.kt index 69114dbd6..cd1e47ab6 100644 --- a/compiler/src/prog8/compiler/astprocessing/IntermediateAstPostprocess.kt +++ b/compiler/src/prog8/compiler/astprocessing/IntermediateAstPostprocess.kt @@ -94,7 +94,7 @@ private fun integrateDefers(subdefers: Map>, 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) } diff --git a/compiler/test/TestLaunchEmu.kt b/compiler/test/TestLaunchEmu.kt index ddd2df089..33e0dae5e 100644 --- a/compiler/test/TestLaunchEmu.kt +++ b/compiler/test/TestLaunchEmu.kt @@ -23,6 +23,8 @@ class TestLaunchEmu: FunSpec({ + + diff --git a/compiler/test/TestSymbolTable.kt b/compiler/test/TestSymbolTable.kt index 8dc6d30ac..6cd29b18e 100644 --- a/compiler/test/TestSymbolTable.kt +++ b/compiler/test/TestSymbolTable.kt @@ -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") { diff --git a/docs/source/todo.rst b/docs/source/todo.rst index ec41cbcdc..f2b294ffc 100644 --- a/docs/source/todo.rst +++ b/docs/source/todo.rst @@ -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 diff --git a/examples/test.p8 b/examples/test.p8 index ce2f21bff..b914de90c 100644 --- a/examples/test.p8 +++ b/examples/test.p8 @@ -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 } } diff --git a/intermediate/src/prog8/intermediate/IRFileReader.kt b/intermediate/src/prog8/intermediate/IRFileReader.kt index 8925fe7c2..939d4e83b 100644 --- a/intermediate/src/prog8/intermediate/IRFileReader.kt +++ b/intermediate/src/prog8/intermediate/IRFileReader.kt @@ -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 { + 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() + 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 { 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") } diff --git a/intermediate/src/prog8/intermediate/IRFileWriter.kt b/intermediate/src/prog8/intermediate/IRFileWriter.kt index b0a92c5d3..d0199da9a 100644 --- a/intermediate/src/prog8/intermediate/IRFileWriter.kt +++ b/intermediate/src/prog8/intermediate/IRFileWriter.kt @@ -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()) { diff --git a/intermediate/src/prog8/intermediate/IRProgram.kt b/intermediate/src/prog8/intermediate/IRProgram.kt index 866958a1a..99d4c6628 100644 --- a/intermediate/src/prog8/intermediate/IRProgram.kt +++ b/intermediate/src/prog8/intermediate/IRProgram.kt @@ -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 diff --git a/intermediate/src/prog8/intermediate/IRSymbolTable.kt b/intermediate/src/prog8/intermediate/IRSymbolTable.kt index 7e063b69b..24d0373b1 100644 --- a/intermediate/src/prog8/intermediate/IRSymbolTable.kt +++ b/intermediate/src/prog8/intermediate/IRSymbolTable.kt @@ -13,17 +13,17 @@ class IRSymbolTable { private val asmSymbols = mutableMapOf() 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 = + table.asSequence().map { it.value }.filterIsInstance() + fun allVariables(): Sequence = table.asSequence().map { it.value }.filterIsInstance() @@ -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?): List? { 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) diff --git a/intermediate/test/TestIRFileInOut.kt b/intermediate/test/TestIRFileInOut.kt index 7d3ddd4ff..69205abcb 100644 --- a/intermediate/test/TestIRFileInOut.kt +++ b/intermediate/test/TestIRFileInOut.kt @@ -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 + +ubyte main.thing=42 + @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 diff --git a/virtualmachine/test/TestVm.kt b/virtualmachine/test/TestVm.kt index 0cf201db6..c596d0089 100644 --- a/virtualmachine/test/TestVm.kt +++ b/virtualmachine/test/TestVm.kt @@ -105,6 +105,8 @@ class TestVm: FunSpec( { + +