redo 8e730ef93d to avoid larger code generated

This commit is contained in:
Irmen de Jong 2022-12-31 14:27:14 +01:00
parent 3feb3e52f8
commit c25eb088ec
8 changed files with 68 additions and 75 deletions

View File

@ -13,12 +13,10 @@ class SymbolTable : StNode("", StNodeType.GLOBAL, Position.DUMMY) {
* This gives the fastest lookup possible (no need to traverse tree nodes)
*/
// TODO key as dotted string instead of list
val flat: Map<List<String>, StNode> by lazy {
val result = mutableMapOf<List<String>, StNode>()
val flat: Map<String, StNode> by lazy {
val result = mutableMapOf<String, StNode>()
fun flatten(node: StNode) {
result[node.scopedName.split('.')] = node
result[node.scopedName] = node
node.children.values.forEach { flatten(it) }
}
children.values.forEach { flatten(it) }
@ -57,7 +55,7 @@ class SymbolTable : StNode("", StNodeType.GLOBAL, Position.DUMMY) {
children.mapNotNull { if (it.value.type == StNodeType.MEMORYSLAB) it.value as StMemorySlab else null }
}
override fun lookup(scopedName: String) = flat[scopedName.split('.')] // TODO dotted string as keys
override fun lookup(scopedName: String) = flat[scopedName]
}
@ -84,42 +82,18 @@ open class StNode(val name: String,
lateinit var parent: StNode
val scopedName: String by lazy {
scopedNameList.joinToString(".")
}
val scopedName: String by lazy { scopedNameList.joinToString(".") }
open fun lookup(scopedName: String) =
lookup(scopedName.split('.'))
fun lookupUnqualifiedOrElse(name: String, default: () -> StNode) =
lookupUnqualified(name) ?: default()
fun lookupUnscopedOrElse(name: String, default: () -> StNode) =
lookupUnscoped(name) ?: default()
fun lookupQualifiedOrElse(scopedName: List<String>, default: () -> StNode) =
lookup(scopedName) ?: default()
fun lookupOrElse(scopedName: String, default: () -> StNode): StNode =
lookup(scopedName.split('.')) ?: default()
private val scopedNameList: List<String> by lazy {
if(type== StNodeType.GLOBAL)
emptyList()
else
parent.scopedNameList + name
}
private fun lookup(scopedName: List<String>): StNode? {
// a scoped name refers to a name in another namespace, and always stars from the root.
var node = this
while(node.type!= StNodeType.GLOBAL)
node = node.parent
for(name in scopedName) {
if(name in node.children)
node = node.children.getValue(name)
else
return null
}
return node
}
fun lookupUnqualified(name: String): StNode? {
fun lookupUnscoped(name: String): StNode? {
// first consider the builtin functions
var globalscope = this
while(globalscope.type!= StNodeType.GLOBAL)
@ -145,6 +119,28 @@ open class StNode(val name: String,
children[child.name] = child
child.parent = this
}
private val scopedNameList: List<String> by lazy {
if(type== StNodeType.GLOBAL)
emptyList()
else
parent.scopedNameList + name
}
private fun lookup(scopedName: List<String>): StNode? {
// a scoped name refers to a name in another namespace, and always stars from the root.
var node = this
while(node.type!= StNodeType.GLOBAL)
node = node.parent
for(name in scopedName) {
if(name in node.children)
node = node.children.getValue(name)
else
return null
}
return node
}
}
class StStaticVariable(name: String,
@ -222,11 +218,7 @@ class StRomSub(name: String,
class StSubroutineParameter(val name: String, val type: DataType)
class StRomSubParameter(val register: RegisterOrStatusflag, val type: DataType)
class StArrayElement(val number: Double?, val addressOfSymbol: String?) {
init {
require(addressOfSymbol==null || addressOfSymbol.contains('.'))
}
}
class StArrayElement(val number: Double?, val addressOfSymbol: String?)
typealias StString = Pair<String, Encoding>
typealias StArray = List<StArrayElement>

View File

@ -223,7 +223,7 @@ internal class ProgramAndVarsGen(
scope.children.filter { it.value.type in arrayOf(StNodeType.STATICVAR, StNodeType.CONSTANT, StNodeType.MEMVAR) }
private fun createBlockVariables(block: Block) {
val scope = symboltable.lookupUnqualifiedOrElse(block.name) { throw AssemblyError("lookup") }
val scope = symboltable.lookupUnscopedOrElse(block.name) { throw AssemblyError("lookup") }
require(scope.type==StNodeType.BLOCK)
val varsInBlock = getVars(scope)
@ -286,7 +286,7 @@ internal class ProgramAndVarsGen(
// regular subroutine
asmgen.out("${sub.name}\t$asmStartScope")
val scope = symboltable.lookupQualifiedOrElse(sub.scopedName) { throw AssemblyError("lookup") }
val scope = symboltable.lookupOrElse(sub.scopedName.joinToString(".")) { throw AssemblyError("lookup") }
require(scope.type==StNodeType.SUBROUTINE)
val varsInSubroutine = getVars(scope)
@ -428,13 +428,13 @@ internal class ProgramAndVarsGen(
}
private class ZpStringWithInitial(
val name: List<String>,
val name: String,
val alloc: MemoryAllocator.VarAllocation,
val value: Pair<String, Encoding>
)
private class ZpArrayWithInitial(
val name: List<String>,
val name: String,
val alloc: MemoryAllocator.VarAllocation,
val value: StArray
)
@ -443,9 +443,9 @@ internal class ProgramAndVarsGen(
val result = mutableListOf<ZpStringWithInitial>()
val vars = allocator.zeropageVars.filter { it.value.dt==DataType.STR }
for (variable in vars) {
val svar = symboltable.flat.getValue(variable.key.split('.')) as StStaticVariable
val svar = symboltable.flat.getValue(variable.key) as StStaticVariable
if(svar.onetimeInitializationStringValue!=null)
result.add(ZpStringWithInitial(variable.key.split('.'), variable.value, svar.onetimeInitializationStringValue!!))
result.add(ZpStringWithInitial(variable.key, variable.value, svar.onetimeInitializationStringValue!!))
}
return result
}
@ -454,9 +454,9 @@ internal class ProgramAndVarsGen(
val result = mutableListOf<ZpArrayWithInitial>()
val vars = allocator.zeropageVars.filter { it.value.dt in ArrayDatatypes }
for (variable in vars) {
val svar = symboltable.flat.getValue(variable.key.split('.')) as StStaticVariable
val svar = symboltable.flat.getValue(variable.key) as StStaticVariable
if(svar.onetimeInitializationArrayValue!=null)
result.add(ZpArrayWithInitial(variable.key.split('.'), variable.value, svar.onetimeInitializationArrayValue!!))
result.add(ZpArrayWithInitial(variable.key, variable.value, svar.onetimeInitializationArrayValue!!))
}
return result
}

View File

@ -88,7 +88,7 @@ internal class VariableAllocator(private val symboltable: SymbolTable,
// try to allocate any other interger variables into the zeropage until it is full.
// TODO some form of intelligent priorization? most often used variables first? loopcounter vars first? ...?
if(errors.noErrors()) {
for (variable in varsDontCare.sortedBy { it.scopedName.length }) {
for (variable in varsDontCare.sortedBy { it.scopedName.count { chr -> chr=='.'}}) {
if(variable.dt in IntegerDatatypes) {
if(zeropage.free.isEmpty()) {
break

View File

@ -60,7 +60,7 @@ internal class BuiltinFuncGen(private val codeGen: IRCodeGen, private val exprGe
private fun funcAny(call: PtBuiltinFunctionCall, resultRegister: Int): IRCodeChunks {
val arrayName = call.args[0] as PtIdentifier
val array = codeGen.symbolTable.flat.getValue(arrayName.name.split('.')) as StStaticVariable
val array = codeGen.symbolTable.flat.getValue(arrayName.name) as StStaticVariable
val syscall =
when (array.dt) {
DataType.ARRAY_UB,
@ -83,7 +83,7 @@ internal class BuiltinFuncGen(private val codeGen: IRCodeGen, private val exprGe
private fun funcAll(call: PtBuiltinFunctionCall, resultRegister: Int): IRCodeChunks {
val arrayName = call.args[0] as PtIdentifier
val array = codeGen.symbolTable.flat.getValue(arrayName.name.split('.')) as StStaticVariable
val array = codeGen.symbolTable.flat.getValue(arrayName.name) as StStaticVariable
val syscall =
when(array.dt) {
DataType.ARRAY_UB,
@ -204,7 +204,7 @@ internal class BuiltinFuncGen(private val codeGen: IRCodeGen, private val exprGe
private fun funcReverse(call: PtBuiltinFunctionCall): IRCodeChunks {
val arrayName = call.args[0] as PtIdentifier
val array = codeGen.symbolTable.flat.getValue(arrayName.name.split('.')) as StStaticVariable
val array = codeGen.symbolTable.flat.getValue(arrayName.name) as StStaticVariable
val syscall =
when(array.dt) {
DataType.ARRAY_UB, DataType.ARRAY_B, DataType.STR -> IMSyscall.REVERSE_BYTES
@ -223,7 +223,7 @@ internal class BuiltinFuncGen(private val codeGen: IRCodeGen, private val exprGe
private fun funcSort(call: PtBuiltinFunctionCall): IRCodeChunks {
val arrayName = call.args[0] as PtIdentifier
val array = codeGen.symbolTable.flat.getValue(arrayName.name.split('.')) as StStaticVariable
val array = codeGen.symbolTable.flat.getValue(arrayName.name) as StStaticVariable
val syscall =
when(array.dt) {
DataType.ARRAY_UB -> IMSyscall.SORT_UBYTE

View File

@ -88,7 +88,7 @@ internal class ExpressionGen(private val codeGen: IRCodeGen) {
private fun translate(check: PtContainmentCheck, resultRegister: Int, resultFpRegister: Int): IRCodeChunks {
val result = mutableListOf<IRCodeChunkBase>()
result += translateExpression(check.element, resultRegister, -1) // load the element to check in resultRegister
val iterable = codeGen.symbolTable.flat.getValue(check.iterable.name.split('.')) as StStaticVariable
val iterable = codeGen.symbolTable.flat.getValue(check.iterable.name) as StStaticVariable
when(iterable.dt) {
DataType.STR -> {
result += translateExpression(check.element, SyscallRegisterBase, -1)
@ -931,7 +931,7 @@ internal class ExpressionGen(private val codeGen: IRCodeGen) {
}
fun translate(fcall: PtFunctionCall, resultRegister: Int, resultFpRegister: Int): IRCodeChunks {
when (val callTarget = codeGen.symbolTable.flat.getValue(fcall.name.split('.'))) {
when (val callTarget = codeGen.symbolTable.flat.getValue(fcall.name)) {
is StSub -> {
val result = mutableListOf<IRCodeChunkBase>()
for ((arg, parameter) in fcall.args.zip(callTarget.parameters)) {

View File

@ -131,7 +131,7 @@ class IRCodeGen(
symbol = symbolExpr
index = 0u
}
val target = symbolTable.flat[symbol.split('.')]
val target = symbolTable.flat[symbol]
if (target is StMemVar) {
replacements.add(Triple(chunk, idx, target.address+index))
}
@ -1248,7 +1248,7 @@ class IRCodeGen(
private fun translate(parameters: List<PtSubroutineParameter>) =
parameters.map {
val flattenedName = it.definingSub()!!.scopedName + "." + it.name
val orig = symbolTable.flat.getValue(flattenedName.split('.')) as StStaticVariable
val orig = symbolTable.flat.getValue(flattenedName) as StStaticVariable
IRSubroutine.IRParam(flattenedName, orig.dt)
}

View File

@ -21,50 +21,51 @@ class TestSymbolTable: FunSpec({
test("symboltable flatten") {
val st = makeSt()
st.flat[listOf("zzzzz")] shouldBe null
st.flat.getValue(listOf("msb")).type shouldBe StNodeType.BUILTINFUNC
st.flat.getValue(listOf("block2")).type shouldBe StNodeType.BLOCK
st.flat.getValue(listOf("block2", "sub2", "subsub", "label")).type shouldBe StNodeType.LABEL
st.flat[listOf("block2", "sub2", "subsub", "label", "zzzz")] shouldBe null
st.flat["zzzzz"] shouldBe null
st.flat.getValue("msb").type shouldBe StNodeType.BUILTINFUNC
st.flat.getValue("block2").type shouldBe StNodeType.BLOCK
st.flat.getValue("block2.sub2.subsub.label").type shouldBe StNodeType.LABEL
st.flat["block2.sub2.subsub.label.zzzz"] shouldBe null
}
test("symboltable global lookups") {
val st = makeSt()
st.lookupUnqualified("undefined") shouldBe null
st.lookupUnscoped("undefined") shouldBe null
st.lookup("undefined") shouldBe null
var default = st.lookupUnqualifiedOrElse("undefined") { StNode("default", StNodeType.LABEL, Position.DUMMY) }
st.lookup("undefined.undefined") shouldBe null
var default = st.lookupUnscopedOrElse("undefined") { StNode("default", StNodeType.LABEL, Position.DUMMY) }
default.name shouldBe "default"
default = st.lookupUnqualifiedOrElse("undefined") { StNode("default", StNodeType.LABEL, Position.DUMMY) }
default = st.lookupUnscopedOrElse("undefined") { StNode("default", StNodeType.LABEL, Position.DUMMY) }
default.name shouldBe "default"
val msbFunc = st.lookupUnqualifiedOrElse("msb") { fail("msb must be found") }
val msbFunc = st.lookupUnscopedOrElse("msb") { fail("msb must be found") }
msbFunc.type shouldBe StNodeType.BUILTINFUNC
val variable = st.lookupQualifiedOrElse(listOf("block1", "sub2", "v2")) { fail("v2 must be found") }
val variable = st.lookupOrElse("block1.sub2.v2") { fail("v2 must be found") }
variable.type shouldBe StNodeType.STATICVAR
}
test("symboltable nested lookups") {
val st = makeSt()
val sub1 = st.lookupQualifiedOrElse(listOf("block1", "sub1")) { fail("should find sub1") }
val sub1 = st.lookupOrElse("block1.sub1") { fail("should find sub1") }
sub1.name shouldBe "sub1"
sub1.scopedName shouldBe "block1.sub1"
sub1.type shouldBe StNodeType.SUBROUTINE
sub1.children.size shouldBe 2
val v1 = sub1.lookupUnqualifiedOrElse("v1") { fail("v1 must be found") } as StStaticVariable
val v1 = sub1.lookupUnscopedOrElse("v1") { fail("v1 must be found") } as StStaticVariable
v1.type shouldBe StNodeType.STATICVAR
v1.name shouldBe "v1"
v1.dt shouldBe DataType.BYTE
val blockc = sub1.lookupUnqualifiedOrElse("blockc") { fail("blockc") } as StConstant
val blockc = sub1.lookupUnscopedOrElse("blockc") { fail("blockc") } as StConstant
blockc.type shouldBe StNodeType.CONSTANT
blockc.value shouldBe 999.0
val subsub = st.lookupQualifiedOrElse(listOf("block2", "sub2", "subsub")) { fail("should find subsub") }
subsub.lookupUnqualified("blockc") shouldBe null
subsub.lookupUnqualified("label") shouldNotBe null
val subsub = st.lookupOrElse("block2.sub2.subsub") { fail("should find subsub") }
subsub.lookupUnscoped("blockc") shouldBe null
subsub.lookupUnscoped("label") shouldNotBe null
}
})

View File

@ -3,7 +3,7 @@ TODO
For next release
^^^^^^^^^^^^^^^^
- optimize scoped symbols: .split('.') / .joinToString(".") / 'dotted string' comments
- optimize scoped symbols: .split('.') / .joinToString(".")
...