mirror of
https://github.com/irmen/prog8.git
synced 2025-02-09 07:31:34 +00:00
retain constants in IR
some IR related cleanups
This commit is contained in:
parent
4c1e2f3110
commit
5071da6784
@ -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)
|
||||
|
||||
|
@ -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) {
|
||||
|
@ -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++ }
|
||||
|
@ -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 */ }
|
||||
|
@ -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)
|
||||
}
|
||||
|
@ -23,6 +23,8 @@ class TestLaunchEmu: FunSpec({
|
||||
</VARIABLESNOINIT>
|
||||
<VARIABLESWITHINIT>
|
||||
</VARIABLESWITHINIT>
|
||||
<CONSTANTS>
|
||||
</CONSTANTS>
|
||||
|
||||
<MEMORYMAPPEDVARIABLES>
|
||||
</MEMORYMAPPEDVARIABLES>
|
||||
|
@ -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") {
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
}
|
||||
}
|
||||
|
@ -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")
|
||||
}
|
||||
|
@ -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()) {
|
||||
|
@ -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
|
||||
|
@ -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)
|
||||
|
@ -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
|
||||
|
@ -105,6 +105,8 @@ class TestVm: FunSpec( {
|
||||
</VARIABLESNOINIT>
|
||||
<VARIABLESWITHINIT>
|
||||
</VARIABLESWITHINIT>
|
||||
<CONSTANTS>
|
||||
</CONSTANTS>
|
||||
|
||||
<MEMORYMAPPEDVARIABLES>
|
||||
</MEMORYMAPPEDVARIABLES>
|
||||
|
Loading…
x
Reference in New Issue
Block a user