mirror of
https://github.com/irmen/prog8.git
synced 2024-09-07 19:54:26 +00:00
Merge branch 'master' into codegen-on-new-ast
# Conflicts: # codeGenIntermediate/src/prog8/codegen/intermediate/IRCodeGen.kt # examples/test.p8
This commit is contained in:
commit
a3c0c7c96f
@ -24,10 +24,9 @@ class IRCodeGen(
|
|||||||
internal val registers = RegisterPool()
|
internal val registers = RegisterPool()
|
||||||
|
|
||||||
fun generate(): IRProgram {
|
fun generate(): IRProgram {
|
||||||
flattenLabelNames()
|
makeAllNodenamesScoped()
|
||||||
flattenNestedSubroutines()
|
moveAllNestedSubroutinesToBlockScope()
|
||||||
|
verifyNameScoping(program, symbolTable)
|
||||||
// TODO: validateNames(program)
|
|
||||||
|
|
||||||
val irProg = IRProgram(program.name, IRSymbolTable(symbolTable), options, program.encoding)
|
val irProg = IRProgram(program.name, IRSymbolTable(symbolTable), options, program.encoding)
|
||||||
|
|
||||||
@ -73,23 +72,37 @@ class IRCodeGen(
|
|||||||
return irProg
|
return irProg
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun validateNames(node: PtNode) {
|
private fun verifyNameScoping(program: PtProgram, symbolTable: SymbolTable) {
|
||||||
when(node) {
|
fun verifyPtNode(node: PtNode) {
|
||||||
is PtBuiltinFunctionCall -> require('.' in node.name) { "node $node name is not scoped: ${node.name}"}
|
when (node) {
|
||||||
is PtFunctionCall -> require('.' in node.name) { "node $node name is not scoped: ${node.name}"}
|
is PtBuiltinFunctionCall -> require('.' !in node.name) { "builtin function call name should not be scoped: ${node.name}" }
|
||||||
is PtIdentifier -> require('.' in node.name) { "node $node name is not scoped: ${node.name}"}
|
is PtFunctionCall -> require('.' in node.name) { "node $node name is not scoped: ${node.name}" }
|
||||||
is PtAsmSub -> require('.' in node.name) { "node $node name is not scoped: ${node.name}"}
|
is PtIdentifier -> require('.' in node.name) { "node $node name is not scoped: ${node.name}" }
|
||||||
is PtBlock -> require('.' !in node.name) { "block name should not be scoped: ${node.name}"}
|
is PtAsmSub -> require('.' in node.name) { "node $node name is not scoped: ${node.name}" }
|
||||||
is PtConstant -> require('.' in node.name) { "node $node name is not scoped: ${node.name}"}
|
is PtBlock -> require('.' !in node.name) { "block name should not be scoped: ${node.name}" }
|
||||||
is PtLabel -> require('.' in node.name) { "node $node name is not scoped: ${node.name}"}
|
is PtConstant -> require('.' in node.name) { "node $node name is not scoped: ${node.name}" }
|
||||||
is PtMemMapped -> require('.' in node.name) { "node $node name is not scoped: ${node.name}"}
|
is PtLabel -> require('.' in node.name) { "node $node name is not scoped: ${node.name}" }
|
||||||
is PtSub -> require('.' in node.name) { "node $node name is not scoped: ${node.name}"}
|
is PtMemMapped -> require('.' in node.name) { "node $node name is not scoped: ${node.name}" }
|
||||||
is PtVariable -> require('.' in node.name) { "node $node name is not scoped: ${node.name}"}
|
is PtSub -> require('.' in node.name) { "node $node name is not scoped: ${node.name}" }
|
||||||
is PtProgram -> require('.' !in node.name) { "program name should not be scoped: ${node.name}"}
|
is PtVariable -> require('.' in node.name) { "node $node name is not scoped: ${node.name}" }
|
||||||
is PtSubroutineParameter -> require('.' in node.name) { "node $node name is not scoped: ${node.name}"}
|
is PtProgram -> require('.' !in node.name) { "program name should not be scoped: ${node.name}" }
|
||||||
else -> { /* node has no name */ }
|
is PtSubroutineParameter -> require('.' in node.name) { "node $node name is not scoped: ${node.name}" }
|
||||||
|
else -> { /* node has no name */
|
||||||
|
}
|
||||||
|
}
|
||||||
|
node.children.forEach { verifyPtNode(it) }
|
||||||
}
|
}
|
||||||
node.children.forEach{ validateNames(it) }
|
|
||||||
|
fun verifyStNode(node: StNode) {
|
||||||
|
require('.' !in node.name) { "st node name should not be scoped: ${node.name}"}
|
||||||
|
node.children.forEach {
|
||||||
|
require(it.key==it.value.name)
|
||||||
|
verifyStNode(it.value)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
verifyPtNode(program)
|
||||||
|
verifyStNode(symbolTable)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun ensureFirstChunkLabels(irProg: IRProgram) {
|
private fun ensureFirstChunkLabels(irProg: IRProgram) {
|
||||||
@ -176,79 +189,47 @@ class IRCodeGen(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun flattenLabelNames() {
|
private fun makeAllNodenamesScoped() {
|
||||||
val renameLabels = mutableListOf<Pair<PtNode, PtLabel>>()
|
val renames = mutableListOf<Pair<PtNamedNode, String>>()
|
||||||
|
fun recurse(node: PtNode) {
|
||||||
fun flattenRecurse(node: PtNode) {
|
|
||||||
node.children.forEach {
|
node.children.forEach {
|
||||||
if (it is PtLabel)
|
if(it is PtNamedNode)
|
||||||
renameLabels += Pair(it.parent, it)
|
renames.add(it to it.scopedName)
|
||||||
else
|
recurse(it)
|
||||||
flattenRecurse(it)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
recurse(program)
|
||||||
flattenRecurse(program)
|
renames.forEach { it.first.name = it.second }
|
||||||
|
|
||||||
renameLabels.forEach { (_, label) -> label.name = label.scopedName }
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun flattenNestedSubroutines() {
|
private fun moveAllNestedSubroutinesToBlockScope() {
|
||||||
// this moves all nested subroutines up to the block scope.
|
val movedSubs = mutableListOf<Pair<PtBlock, PtSub>>()
|
||||||
// also changes the name to be the fully scoped one, so it becomes unique at the top level.
|
val removedSubs = mutableListOf<Pair<PtSub, PtSub>>()
|
||||||
val flattenedSubs = mutableListOf<Pair<PtBlock, PtSub>>()
|
|
||||||
val flattenedAsmSubs = mutableListOf<Pair<PtBlock, PtAsmSub>>()
|
|
||||||
val removalsSubs = mutableListOf<Pair<PtSub, PtSub>>()
|
|
||||||
val removalsAsmSubs = mutableListOf<Pair<PtSub, PtAsmSub>>()
|
|
||||||
val renameSubs = mutableListOf<Pair<PtBlock, PtSub>>()
|
|
||||||
val renameAsmSubs = mutableListOf<Pair<PtBlock, PtAsmSub>>()
|
|
||||||
|
|
||||||
fun flattenNestedAsmSub(block: PtBlock, parentSub: PtSub, asmsub: PtAsmSub) {
|
fun moveToBlock(block: PtBlock, parent: PtSub, asmsub: PtAsmSub) {
|
||||||
val flattened = PtAsmSub(asmsub.scopedName,
|
block.add(asmsub)
|
||||||
asmsub.address,
|
parent.children.remove(asmsub)
|
||||||
asmsub.clobbers,
|
|
||||||
asmsub.parameters,
|
|
||||||
asmsub.returnTypes,
|
|
||||||
asmsub.retvalRegisters,
|
|
||||||
asmsub.inline,
|
|
||||||
asmsub.position)
|
|
||||||
asmsub.children.forEach { flattened.add(it) }
|
|
||||||
flattenedAsmSubs += Pair(block, flattened)
|
|
||||||
removalsAsmSubs += Pair(parentSub, asmsub)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fun flattenNestedSub(block: PtBlock, parentSub: PtSub, sub: PtSub) {
|
fun moveToBlock(block: PtBlock, parent: PtSub, sub: PtSub) {
|
||||||
sub.children.filterIsInstance<PtSub>().forEach { subsub->flattenNestedSub(block, sub, subsub) }
|
sub.children.filterIsInstance<PtSub>().forEach { subsub -> moveToBlock(block, sub, subsub) }
|
||||||
sub.children.filterIsInstance<PtAsmSub>().forEach { asmsubsub->flattenNestedAsmSub(block, sub, asmsubsub) }
|
sub.children.filterIsInstance<PtAsmSub>().forEach { asmsubsub -> moveToBlock(block, sub, asmsubsub) }
|
||||||
val flattened = PtSub(sub.scopedName,
|
movedSubs += Pair(block, sub)
|
||||||
sub.parameters,
|
removedSubs += Pair(parent, sub)
|
||||||
sub.returntype,
|
|
||||||
sub.inline,
|
|
||||||
sub.position)
|
|
||||||
sub.children.forEach { if(it !is PtSub) flattened.add(it) }
|
|
||||||
flattenedSubs += Pair(block, flattened)
|
|
||||||
removalsSubs += Pair(parentSub, sub)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
program.allBlocks().forEach { block ->
|
program.allBlocks().forEach { block ->
|
||||||
block.children.forEach {
|
block.children.forEach {
|
||||||
if(it is PtSub) {
|
if (it is PtSub) {
|
||||||
// Only regular subroutines can have nested subroutines.
|
// Only regular subroutines can have nested subroutines.
|
||||||
it.children.filterIsInstance<PtSub>().forEach { subsub->flattenNestedSub(block, it, subsub)}
|
it.children.filterIsInstance<PtSub>().forEach { subsub -> moveToBlock(block, it, subsub) }
|
||||||
it.children.filterIsInstance<PtAsmSub>().forEach { asmsubsub->flattenNestedAsmSub(block, it, asmsubsub)}
|
it.children.filterIsInstance<PtAsmSub>().forEach { asmsubsub -> moveToBlock(block, it, asmsubsub) }
|
||||||
renameSubs += Pair(block, it)
|
|
||||||
}
|
}
|
||||||
if(it is PtAsmSub)
|
|
||||||
renameAsmSubs += Pair(block, it)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
removalsSubs.forEach { (parent, sub) -> parent.children.remove(sub) }
|
removedSubs.forEach { (parent, sub) -> parent.children.remove(sub) }
|
||||||
removalsAsmSubs.forEach { (parent, asmsub) -> parent.children.remove(asmsub) }
|
movedSubs.forEach { (block, sub) -> block.add(sub) }
|
||||||
flattenedSubs.forEach { (block, sub) -> block.add(sub) }
|
|
||||||
flattenedAsmSubs.forEach { (block, asmsub) -> block.add(asmsub) }
|
|
||||||
renameSubs.forEach { (_, sub) -> sub.name = sub.scopedName }
|
|
||||||
renameAsmSubs.forEach { (_, sub) -> sub.name = sub.scopedName }
|
|
||||||
}
|
}
|
||||||
|
|
||||||
internal fun translateNode(node: PtNode): IRCodeChunks {
|
internal fun translateNode(node: PtNode): IRCodeChunks {
|
||||||
@ -463,7 +444,8 @@ class IRCodeGen(
|
|||||||
}
|
}
|
||||||
is PtIdentifier -> {
|
is PtIdentifier -> {
|
||||||
val iterableVar = symbolTable.lookup(iterable.name) as StStaticVariable
|
val iterableVar = symbolTable.lookup(iterable.name) as StStaticVariable
|
||||||
val loopvarSymbol = loopvar.scopedName
|
require(forLoop.variable.name == loopvar.scopedName)
|
||||||
|
val loopvarSymbol = forLoop.variable.name
|
||||||
val indexReg = registers.nextFree()
|
val indexReg = registers.nextFree()
|
||||||
val tmpReg = registers.nextFree()
|
val tmpReg = registers.nextFree()
|
||||||
val loopLabel = createLabelName()
|
val loopLabel = createLabelName()
|
||||||
@ -526,7 +508,8 @@ class IRCodeGen(
|
|||||||
throw AssemblyError("step 0")
|
throw AssemblyError("step 0")
|
||||||
val indexReg = registers.nextFree()
|
val indexReg = registers.nextFree()
|
||||||
val endvalueReg = registers.nextFree()
|
val endvalueReg = registers.nextFree()
|
||||||
val loopvarSymbol = loopvar.scopedName
|
require(forLoop.variable.name == loopvar.scopedName)
|
||||||
|
val loopvarSymbol = forLoop.variable.name
|
||||||
val loopvarDt = when(loopvar) {
|
val loopvarDt = when(loopvar) {
|
||||||
is StMemVar -> loopvar.dt
|
is StMemVar -> loopvar.dt
|
||||||
is StStaticVariable -> loopvar.dt
|
is StStaticVariable -> loopvar.dt
|
||||||
@ -557,7 +540,8 @@ class IRCodeGen(
|
|||||||
|
|
||||||
private fun translateForInConstantRange(forLoop: PtForLoop, loopvar: StNode): IRCodeChunks {
|
private fun translateForInConstantRange(forLoop: PtForLoop, loopvar: StNode): IRCodeChunks {
|
||||||
val loopLabel = createLabelName()
|
val loopLabel = createLabelName()
|
||||||
val loopvarSymbol = loopvar.scopedName
|
require(forLoop.variable.name == loopvar.scopedName)
|
||||||
|
val loopvarSymbol = forLoop.variable.name
|
||||||
val indexReg = registers.nextFree()
|
val indexReg = registers.nextFree()
|
||||||
val loopvarDt = when(loopvar) {
|
val loopvarDt = when(loopvar) {
|
||||||
is StMemVar -> loopvar.dt
|
is StMemVar -> loopvar.dt
|
||||||
@ -1244,7 +1228,7 @@ class IRCodeGen(
|
|||||||
|
|
||||||
private fun translate(parameters: List<PtSubroutineParameter>) =
|
private fun translate(parameters: List<PtSubroutineParameter>) =
|
||||||
parameters.map {
|
parameters.map {
|
||||||
val flattenedName = it.definingISub()!!.name + "." + it.name
|
val flattenedName = it.definingSub()!!.name + "." + it.name
|
||||||
val orig = symbolTable.flat.getValue(flattenedName) as StStaticVariable
|
val orig = symbolTable.flat.getValue(flattenedName) as StStaticVariable
|
||||||
IRSubroutine.IRParam(flattenedName, orig.dt)
|
IRSubroutine.IRParam(flattenedName, orig.dt)
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user