mirror of
https://github.com/irmen/prog8.git
synced 2025-05-12 19:47:48 +00:00
optimizing scoped names more and fix scoping of identifier names in arrays (pointers) in SymbolTable
This commit is contained in:
parent
e0913a39ab
commit
8e730ef93d
@ -18,7 +18,7 @@ class SymbolTable : StNode("", StNodeType.GLOBAL, Position.DUMMY) {
|
||||
val flat: Map<List<String>, StNode> by lazy {
|
||||
val result = mutableMapOf<List<String>, StNode>()
|
||||
fun flatten(node: StNode) {
|
||||
result[node.scopedName] = node
|
||||
result[node.scopedName.split('.')] = node
|
||||
node.children.values.forEach { flatten(it) }
|
||||
}
|
||||
children.values.forEach { flatten(it) }
|
||||
@ -57,7 +57,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: List<String>) = flat[scopedName]
|
||||
override fun lookup(scopedName: String) = flat[scopedName.split('.')] // TODO dotted string as keys
|
||||
}
|
||||
|
||||
|
||||
@ -84,23 +84,27 @@ open class StNode(val name: String,
|
||||
|
||||
lateinit var parent: StNode
|
||||
|
||||
val scopedName: List<String> by lazy {
|
||||
if(type== StNodeType.GLOBAL)
|
||||
emptyList()
|
||||
else
|
||||
parent.scopedName + name
|
||||
val scopedName: String by lazy {
|
||||
scopedNameList.joinToString(".")
|
||||
}
|
||||
|
||||
open fun lookup(scopedName: List<String>) =
|
||||
if(scopedName.size>1) lookupQualified(scopedName) else lookupUnqualified(scopedName[0])
|
||||
open fun lookup(scopedName: String) =
|
||||
lookup(scopedName.split('.'))
|
||||
|
||||
fun lookupUnqualifiedOrElse(name: String, default: () -> StNode) =
|
||||
lookupUnqualified(name) ?: default()
|
||||
|
||||
fun lookupUnqualifiedOrElse(scopedName: List<String>, default: () -> StNode) =
|
||||
fun lookupQualifiedOrElse(scopedName: List<String>, default: () -> StNode) =
|
||||
lookup(scopedName) ?: default()
|
||||
|
||||
private fun lookupQualified(scopedName: List<String>): StNode? {
|
||||
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)
|
||||
@ -218,7 +222,11 @@ 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?)
|
||||
class StArrayElement(val number: Double?, val addressOfSymbol: String?) {
|
||||
init {
|
||||
require(addressOfSymbol==null || addressOfSymbol.contains('.'))
|
||||
}
|
||||
}
|
||||
|
||||
typealias StString = Pair<String, Encoding>
|
||||
typealias StArray = List<StArrayElement>
|
||||
|
@ -286,7 +286,7 @@ internal class ProgramAndVarsGen(
|
||||
// regular subroutine
|
||||
asmgen.out("${sub.name}\t$asmStartScope")
|
||||
|
||||
val scope = symboltable.lookupUnqualifiedOrElse(sub.scopedName) { throw AssemblyError("lookup") }
|
||||
val scope = symboltable.lookupQualifiedOrElse(sub.scopedName) { throw AssemblyError("lookup") }
|
||||
require(scope.type==StNodeType.SUBROUTINE)
|
||||
val varsInSubroutine = getVars(scope)
|
||||
|
||||
@ -461,8 +461,9 @@ internal class ProgramAndVarsGen(
|
||||
return result
|
||||
}
|
||||
|
||||
private fun zeropagevars2asm(varNames: Set<List<String>>) {
|
||||
val zpVariables = allocator.zeropageVars.filter { it.key in varNames }
|
||||
private fun zeropagevars2asm(varNames2: Set<String>) {
|
||||
val varNamesAsList = varNames2.map { it.split('.') } // TODO use dotted string
|
||||
val zpVariables = allocator.zeropageVars.filter { it.key in varNamesAsList }
|
||||
for ((scopedName, zpvar) in zpVariables) {
|
||||
if (scopedName.size == 2 && scopedName[0] == "cx16" && scopedName[1][0] == 'r' && scopedName[1][1].isDigit())
|
||||
continue // The 16 virtual registers of the cx16 are not actual variables in zp, they're memory mapped
|
||||
|
@ -22,7 +22,8 @@ internal class VariableAllocator(private val symboltable: SymbolTable,
|
||||
allocateZeropageVariables()
|
||||
}
|
||||
|
||||
internal fun isZpVar(scopedName: List<String>) = scopedName in zeropage.allocatedVariables
|
||||
internal fun isZpVar(scopedName: List<String>) = scopedName in zeropage.allocatedVariables // TODO remove, use dotted string
|
||||
internal fun isZpVar(scopedName: String) = scopedName.split('.') in zeropage.allocatedVariables
|
||||
|
||||
internal fun getFloatAsmConst(number: Double): String {
|
||||
val asmName = globalFloatConsts[number]
|
||||
@ -56,7 +57,7 @@ internal class VariableAllocator(private val symboltable: SymbolTable,
|
||||
|
||||
varsRequiringZp.forEach { variable ->
|
||||
val result = zeropage.allocate(
|
||||
variable.scopedName,
|
||||
variable.scopedName.split('.'), // TODO use dotted name
|
||||
variable.dt,
|
||||
variable.length,
|
||||
variable.position,
|
||||
@ -75,7 +76,7 @@ internal class VariableAllocator(private val symboltable: SymbolTable,
|
||||
if(errors.noErrors()) {
|
||||
varsPreferringZp.forEach { variable ->
|
||||
val result = zeropage.allocate(
|
||||
variable.scopedName,
|
||||
variable.scopedName.split('.'), // TODO use dotted name
|
||||
variable.dt,
|
||||
variable.length,
|
||||
variable.position,
|
||||
@ -88,13 +89,13 @@ 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.size }) {
|
||||
for (variable in varsDontCare.sortedBy { it.scopedName.length }) {
|
||||
if(variable.dt in IntegerDatatypes) {
|
||||
if(zeropage.free.isEmpty()) {
|
||||
break
|
||||
} else {
|
||||
val result = zeropage.allocate(
|
||||
variable.scopedName,
|
||||
variable.scopedName.split('.'), // TODO use dotted name,
|
||||
variable.dt,
|
||||
variable.length,
|
||||
variable.position,
|
||||
|
@ -454,7 +454,7 @@ class IRCodeGen(
|
||||
}
|
||||
|
||||
private fun translate(forLoop: PtForLoop): IRCodeChunks {
|
||||
val loopvar = symbolTable.lookup(forLoop.variable.name.split('.'))!!
|
||||
val loopvar = symbolTable.lookup(forLoop.variable.name)!!
|
||||
val iterable = forLoop.iterable
|
||||
val result = mutableListOf<IRCodeChunkBase>()
|
||||
when(iterable) {
|
||||
@ -465,8 +465,8 @@ class IRCodeGen(
|
||||
result += translateForInNonConstantRange(forLoop, loopvar)
|
||||
}
|
||||
is PtIdentifier -> {
|
||||
val iterableVar = symbolTable.lookup(iterable.name.split('.')) as StStaticVariable
|
||||
val loopvarSymbol = loopvar.scopedName.joinToString(".")
|
||||
val iterableVar = symbolTable.lookup(iterable.name) as StStaticVariable
|
||||
val loopvarSymbol = loopvar.scopedName
|
||||
val indexReg = registers.nextFree()
|
||||
val tmpReg = registers.nextFree()
|
||||
val loopLabel = createLabelName()
|
||||
@ -529,7 +529,7 @@ class IRCodeGen(
|
||||
throw AssemblyError("step 0")
|
||||
val indexReg = registers.nextFree()
|
||||
val endvalueReg = registers.nextFree()
|
||||
val loopvarSymbol = loopvar.scopedName.joinToString(".")
|
||||
val loopvarSymbol = loopvar.scopedName
|
||||
val loopvarDt = when(loopvar) {
|
||||
is StMemVar -> loopvar.dt
|
||||
is StStaticVariable -> loopvar.dt
|
||||
@ -560,7 +560,7 @@ class IRCodeGen(
|
||||
|
||||
private fun translateForInConstantRange(forLoop: PtForLoop, loopvar: StNode): IRCodeChunks {
|
||||
val loopLabel = createLabelName()
|
||||
val loopvarSymbol = loopvar.scopedName.joinToString(".")
|
||||
val loopvarSymbol = loopvar.scopedName
|
||||
val indexReg = registers.nextFree()
|
||||
val loopvarDt = when(loopvar) {
|
||||
is StMemVar -> loopvar.dt
|
||||
|
@ -392,7 +392,7 @@ private fun createAssemblyAndAssemble(program: Program,
|
||||
compilerOptions.compTarget.machine.initializeMemoryAreas(compilerOptions)
|
||||
program.processAstBeforeAsmGeneration(compilerOptions, errors)
|
||||
errors.report()
|
||||
val symbolTable = SymbolTableMaker().makeFrom(program, compilerOptions)
|
||||
val symbolTable = SymbolTableMaker(program, compilerOptions).make()
|
||||
|
||||
// TODO make removing all VarDecls work, but this needs inferType to be able to get its information from somewhere else as the VarDecl nodes in the Ast,
|
||||
// or don't use inferType at all anymore and "bake the type information" into the Ast somehow.
|
||||
|
@ -111,18 +111,8 @@ class IntermediateAstMaker(private val program: Program, private val symbolTable
|
||||
return target
|
||||
}
|
||||
|
||||
private fun targetOf(identifier: IdentifierReference): Pair<String, DataType> {
|
||||
val target=identifier.targetStatement(program)!! as INamedStatement
|
||||
val targetname: String = if(target.name in program.builtinFunctions.names)
|
||||
"<builtin>.${target.name}"
|
||||
else
|
||||
target.scopedName.joinToString(".")
|
||||
val type = identifier.inferType(program).getOr(DataType.UNDEFINED)
|
||||
return Pair(targetname, type)
|
||||
}
|
||||
|
||||
private fun transform(identifier: IdentifierReference): PtIdentifier {
|
||||
val (target, type) = targetOf(identifier)
|
||||
val (target, type) = identifier.targetNameAndType(program)
|
||||
return PtIdentifier(target, type, identifier.position)
|
||||
}
|
||||
|
||||
@ -220,7 +210,7 @@ class IntermediateAstMaker(private val program: Program, private val symbolTable
|
||||
}
|
||||
|
||||
private fun transform(srcCall: FunctionCallStatement): PtFunctionCall {
|
||||
val (target, type) = targetOf(srcCall.target)
|
||||
val (target, type) = srcCall.target.targetNameAndType(program)
|
||||
val call = PtFunctionCall(target,true, type, srcCall.position)
|
||||
for (arg in srcCall.args)
|
||||
call.add(transformExpression(arg))
|
||||
@ -228,7 +218,7 @@ class IntermediateAstMaker(private val program: Program, private val symbolTable
|
||||
}
|
||||
|
||||
private fun transform(srcCall: FunctionCallExpression): PtFunctionCall {
|
||||
val (target, _) = targetOf(srcCall.target)
|
||||
val (target, _) = srcCall.target.targetNameAndType(program)
|
||||
val type = srcCall.inferType(program).getOrElse {
|
||||
throw FatalAstException("unknown dt $srcCall")
|
||||
}
|
||||
|
@ -12,13 +12,13 @@ import prog8.code.core.DataType
|
||||
import prog8.code.core.Position
|
||||
import java.util.*
|
||||
|
||||
internal class SymbolTableMaker: IAstVisitor {
|
||||
internal class SymbolTableMaker(private val program: Program, private val options: CompilationOptions): IAstVisitor {
|
||||
|
||||
private val st = SymbolTable()
|
||||
private val scopestack = Stack<StNode>()
|
||||
private var dontReinitGlobals = false
|
||||
|
||||
fun makeFrom(program: Program, options: CompilationOptions): SymbolTable {
|
||||
fun make(): SymbolTable {
|
||||
scopestack.clear()
|
||||
st.children.clear()
|
||||
dontReinitGlobals = options.dontReinitGlobals
|
||||
@ -104,8 +104,14 @@ internal class SymbolTableMaker: IAstVisitor {
|
||||
return null
|
||||
return arrayLit.value.map {
|
||||
when(it){
|
||||
is AddressOf -> StArrayElement(null, it.identifier.nameInSource.joinToString("."))
|
||||
is IdentifierReference -> StArrayElement(null, it.nameInSource.joinToString("."))
|
||||
is AddressOf -> {
|
||||
val scopedName = it.identifier.targetNameAndType(program).first
|
||||
StArrayElement(null, scopedName)
|
||||
}
|
||||
is IdentifierReference -> {
|
||||
val scopedName = it.targetNameAndType(program).first
|
||||
StArrayElement(null, scopedName)
|
||||
}
|
||||
is NumericLiteral -> StArrayElement(it.number, null)
|
||||
else -> throw FatalAstException("weird element dt in array literal")
|
||||
}
|
||||
|
@ -12,7 +12,7 @@ import prog8.code.core.ZeropageWish
|
||||
class TestSymbolTable: FunSpec({
|
||||
test("empty symboltable") {
|
||||
val st = SymbolTable()
|
||||
st.scopedName shouldBe emptyList()
|
||||
st.scopedName shouldBe ""
|
||||
st.name shouldBe ""
|
||||
st.type shouldBe StNodeType.GLOBAL
|
||||
st.children shouldBe mutableMapOf()
|
||||
@ -31,25 +31,25 @@ class TestSymbolTable: FunSpec({
|
||||
test("symboltable global lookups") {
|
||||
val st = makeSt()
|
||||
st.lookupUnqualified("undefined") shouldBe null
|
||||
st.lookup(listOf("undefined")) shouldBe null
|
||||
st.lookup("undefined") shouldBe null
|
||||
var default = st.lookupUnqualifiedOrElse("undefined") { StNode("default", StNodeType.LABEL, Position.DUMMY) }
|
||||
default.name shouldBe "default"
|
||||
default = st.lookupUnqualifiedOrElse(listOf("undefined")) { StNode("default", StNodeType.LABEL, Position.DUMMY) }
|
||||
default = st.lookupUnqualifiedOrElse("undefined") { StNode("default", StNodeType.LABEL, Position.DUMMY) }
|
||||
default.name shouldBe "default"
|
||||
|
||||
val msbFunc = st.lookupUnqualifiedOrElse("msb") { fail("msb must be found") }
|
||||
msbFunc.type shouldBe StNodeType.BUILTINFUNC
|
||||
|
||||
val variable = st.lookupUnqualifiedOrElse(listOf("block1", "sub2", "v2")) { fail("v2 must be found") }
|
||||
val variable = st.lookupQualifiedOrElse(listOf("block1", "sub2", "v2")) { fail("v2 must be found") }
|
||||
variable.type shouldBe StNodeType.STATICVAR
|
||||
}
|
||||
|
||||
test("symboltable nested lookups") {
|
||||
val st = makeSt()
|
||||
|
||||
val sub1 = st.lookupUnqualifiedOrElse(listOf("block1", "sub1")) { fail("should find sub1") }
|
||||
val sub1 = st.lookupQualifiedOrElse(listOf("block1", "sub1")) { fail("should find sub1") }
|
||||
sub1.name shouldBe "sub1"
|
||||
sub1.scopedName shouldBe listOf("block1", "sub1")
|
||||
sub1.scopedName shouldBe "block1.sub1"
|
||||
sub1.type shouldBe StNodeType.SUBROUTINE
|
||||
sub1.children.size shouldBe 2
|
||||
|
||||
@ -62,7 +62,7 @@ class TestSymbolTable: FunSpec({
|
||||
blockc.type shouldBe StNodeType.CONSTANT
|
||||
blockc.value shouldBe 999.0
|
||||
|
||||
val subsub = st.lookupUnqualifiedOrElse(listOf("block2", "sub2", "subsub")) { fail("should find subsub") }
|
||||
val subsub = st.lookupQualifiedOrElse(listOf("block2", "sub2", "subsub")) { fail("should find subsub") }
|
||||
subsub.lookupUnqualified("blockc") shouldBe null
|
||||
subsub.lookupUnqualified("label") shouldNotBe null
|
||||
}
|
||||
|
@ -38,7 +38,7 @@ class TestIntermediateAst: FunSpec({
|
||||
loadAddress = target.machine.PROGRAM_LOAD_ADDRESS
|
||||
)
|
||||
val result = compileText(target, false, text, writeAssembly = false)!!
|
||||
val st = SymbolTableMaker().makeFrom(result.program, options)
|
||||
val st = SymbolTableMaker(result.program, options).make()
|
||||
val ast = IntermediateAstMaker(result.program, st, options).transform()
|
||||
ast.name shouldBe result.program.name
|
||||
ast.allBlocks().any() shouldBe true
|
||||
|
@ -72,7 +72,7 @@ class TestAsmGenSymbols: StringSpec({
|
||||
val errors = ErrorReporterForTests()
|
||||
val options = CompilationOptions(OutputType.RAW, CbmPrgLauncherType.NONE, ZeropageType.FULL, emptyList(), false, true, C64Target(), 999u)
|
||||
options.compTarget.machine.zeropage = C64Zeropage(options)
|
||||
val st = SymbolTableMaker().makeFrom(program, options)
|
||||
val st = SymbolTableMaker(program, options).make()
|
||||
return AsmGen(program, st, options, errors)
|
||||
}
|
||||
|
||||
|
@ -914,6 +914,16 @@ data class IdentifierReference(val nameInSource: List<String>, override val posi
|
||||
fun targetVarDecl(program: Program): VarDecl? = targetStatement(program) as? VarDecl
|
||||
fun targetSubroutine(program: Program): Subroutine? = targetStatement(program) as? Subroutine
|
||||
|
||||
fun targetNameAndType(program: Program): Pair<String, DataType> {
|
||||
val target=targetStatement(program)!! as INamedStatement
|
||||
val targetname: String = if(target.name in program.builtinFunctions.names)
|
||||
"<builtin>.${target.name}"
|
||||
else
|
||||
target.scopedName.joinToString(".")
|
||||
val type = inferType(program).getOr(DataType.UNDEFINED)
|
||||
return Pair(targetname, type)
|
||||
}
|
||||
|
||||
override fun linkParents(parent: Node) {
|
||||
this.parent = parent
|
||||
}
|
||||
|
@ -3,7 +3,7 @@ TODO
|
||||
|
||||
For next release
|
||||
^^^^^^^^^^^^^^^^
|
||||
- optimize scoped symbols: .split('.') / .joinToString(".")
|
||||
- optimize scoped symbols: .split('.') / .joinToString(".") / 'dotted string' comments
|
||||
|
||||
...
|
||||
|
||||
|
@ -62,15 +62,15 @@ class IRSymbolTable(sourceSt: SymbolTable?) {
|
||||
val newArray = mutableListOf<StArrayElement>()
|
||||
array.forEach {
|
||||
if(it.addressOfSymbol!=null) {
|
||||
val target = variable.lookup(it.addressOfSymbol!!.split('.'))!!
|
||||
newArray.add(StArrayElement(null, target.scopedName.joinToString(".")))
|
||||
val target = variable.lookup(it.addressOfSymbol!!)!!
|
||||
newArray.add(StArrayElement(null, target.scopedName))
|
||||
} else {
|
||||
newArray.add(it)
|
||||
}
|
||||
}
|
||||
return newArray
|
||||
}
|
||||
scopedName = variable.scopedName.joinToString(".")
|
||||
scopedName = variable.scopedName
|
||||
varToadd = StStaticVariable(scopedName, variable.dt, variable.bss,
|
||||
variable.onetimeInitializationNumericValue,
|
||||
variable.onetimeInitializationStringValue,
|
||||
@ -91,7 +91,7 @@ class IRSymbolTable(sourceSt: SymbolTable?) {
|
||||
scopedName = variable.name
|
||||
varToadd = variable
|
||||
} else {
|
||||
scopedName = variable.scopedName.joinToString(".")
|
||||
scopedName = variable.scopedName
|
||||
varToadd = StMemVar(scopedName, variable.dt, variable.address, variable.length, variable.position)
|
||||
}
|
||||
table[scopedName] = varToadd
|
||||
|
Loading…
x
Reference in New Issue
Block a user