mirror of
https://github.com/irmen/prog8.git
synced 2025-08-07 05:27:10 +00:00
comments
This commit is contained in:
@@ -47,6 +47,9 @@ class CodeGen(internal val program: PtProgram,
|
|||||||
internal val vmRegisters = VmRegisterPool()
|
internal val vmRegisters = VmRegisterPool()
|
||||||
|
|
||||||
override fun compileToAssembly(): IAssemblyProgram? {
|
override fun compileToAssembly(): IAssemblyProgram? {
|
||||||
|
|
||||||
|
flattenNestedSubroutines()
|
||||||
|
|
||||||
val irProg = IRProgram(program.name, symbolTable, options, program.encoding)
|
val irProg = IRProgram(program.name, symbolTable, options, program.encoding)
|
||||||
|
|
||||||
if(!options.dontReinitGlobals) {
|
if(!options.dontReinitGlobals) {
|
||||||
@@ -80,6 +83,56 @@ class CodeGen(internal val program: PtProgram,
|
|||||||
return DummyAssemblyProgram(irProg.name)
|
return DummyAssemblyProgram(irProg.name)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun flattenNestedSubroutines() {
|
||||||
|
// this moves all nested subroutines up to the block scope.
|
||||||
|
val flattenedSubs = mutableListOf<Pair<PtBlock, PtSub>>()
|
||||||
|
val flattenedAsmSubs = mutableListOf<Pair<PtBlock, PtAsmSub>>()
|
||||||
|
val removalsSubs = mutableListOf<Pair<PtSub, PtSub>>()
|
||||||
|
val removalsAsmSubs = mutableListOf<Pair<PtSub, PtAsmSub>>()
|
||||||
|
|
||||||
|
fun flattenNestedAsm(block: PtBlock, parentSub: PtSub, asmsub: PtAsmSub) {
|
||||||
|
val flattened = PtAsmSub(asmsub.scopedName.joinToString("."),
|
||||||
|
asmsub.address,
|
||||||
|
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 flattenNested(block: PtBlock, parentSub: PtSub, sub: PtSub) {
|
||||||
|
sub.children.filterIsInstance<PtSub>().forEach { subsub->flattenNested(block, sub, subsub) }
|
||||||
|
sub.children.filterIsInstance<PtAsmSub>().forEach { asmsubsub->flattenNestedAsm(block, sub, asmsubsub) }
|
||||||
|
val flattened = PtSub(sub.scopedName.joinToString("."),
|
||||||
|
sub.parameters,
|
||||||
|
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 ->
|
||||||
|
block.children.forEach {
|
||||||
|
if(it is PtSub) {
|
||||||
|
// Only regular subroutines can have nested subroutines.
|
||||||
|
it.children.filterIsInstance<PtSub>().forEach { subsub->flattenNested(block, it, subsub)}
|
||||||
|
it.children.filterIsInstance<PtAsmSub>().forEach { asmsubsub->flattenNestedAsm(block, it, asmsubsub)}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
removalsSubs.forEach { (parent, sub) -> parent.children.remove(sub) }
|
||||||
|
removalsAsmSubs.forEach { (parent, asmsub) -> parent.children.remove(asmsub) }
|
||||||
|
flattenedSubs.forEach { (block, sub) -> block.add(sub) }
|
||||||
|
flattenedAsmSubs.forEach { (block, asmsub) -> block.add(asmsub) }
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
internal fun translateNode(node: PtNode): IRCodeChunk {
|
internal fun translateNode(node: PtNode): IRCodeChunk {
|
||||||
val code = when(node) {
|
val code = when(node) {
|
||||||
@@ -651,7 +704,6 @@ class CodeGen(internal val program: PtProgram,
|
|||||||
translateNonZeroComparison()
|
translateNonZeroComparison()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
private fun translate(postIncrDecr: PtPostIncrDecr): IRCodeChunk {
|
private fun translate(postIncrDecr: PtPostIncrDecr): IRCodeChunk {
|
||||||
val code = IRCodeChunk(postIncrDecr.position)
|
val code = IRCodeChunk(postIncrDecr.position)
|
||||||
val operationMem: Opcode
|
val operationMem: Opcode
|
||||||
@@ -771,7 +823,7 @@ class CodeGen(internal val program: PtProgram,
|
|||||||
is PtAssignment -> { /* global variable initialization is done elsewhere */ }
|
is PtAssignment -> { /* global variable initialization is done elsewhere */ }
|
||||||
is PtScopeVarsDecls -> { /* vars should be looked up via symbol table */ }
|
is PtScopeVarsDecls -> { /* vars should be looked up via symbol table */ }
|
||||||
is PtSub -> {
|
is PtSub -> {
|
||||||
val vmsub = IRSubroutine(child.scopedName, child.returntype, child.position)
|
val vmsub = IRSubroutine(child.name, child.returntype, child.position)
|
||||||
for (line in child.children) {
|
for (line in child.children) {
|
||||||
vmsub += translateNode(line)
|
vmsub += translateNode(line)
|
||||||
}
|
}
|
||||||
@@ -823,4 +875,3 @@ class CodeGen(internal val program: PtProgram,
|
|||||||
return scopedName
|
return scopedName
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -20,11 +20,19 @@ main {
|
|||||||
|
|
||||||
qq=global1
|
qq=global1
|
||||||
qq=other.global2
|
qq=other.global2
|
||||||
; nested()
|
nested()
|
||||||
|
main.start.nested.nested2()
|
||||||
|
|
||||||
; TODO flatten nested subroutines in codegen
|
; TODO flatten nested subroutines in codegen
|
||||||
sub nested() {
|
sub nested() {
|
||||||
qq++
|
qq++
|
||||||
|
txt.print("zzz")
|
||||||
|
nested2()
|
||||||
|
|
||||||
|
sub nested2() {
|
||||||
|
txt.print("zzz2")
|
||||||
|
qq++
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -5,6 +5,7 @@
|
|||||||
<content url="file://$MODULE_DIR$">
|
<content url="file://$MODULE_DIR$">
|
||||||
<sourceFolder url="file://$MODULE_DIR$/src" isTestSource="false" />
|
<sourceFolder url="file://$MODULE_DIR$/src" isTestSource="false" />
|
||||||
<sourceFolder url="file://$MODULE_DIR$/test" isTestSource="true" />
|
<sourceFolder url="file://$MODULE_DIR$/test" isTestSource="true" />
|
||||||
|
<excludeFolder url="file://$MODULE_DIR$/build" />
|
||||||
</content>
|
</content>
|
||||||
<orderEntry type="inheritedJdk" />
|
<orderEntry type="inheritedJdk" />
|
||||||
<orderEntry type="sourceFolder" forTests="false" />
|
<orderEntry type="sourceFolder" forTests="false" />
|
||||||
|
@@ -37,7 +37,7 @@ class IRFileWriter(private val irProgram: IRProgram) {
|
|||||||
out.write("</INLINEASM>\n")
|
out.write("</INLINEASM>\n")
|
||||||
}
|
}
|
||||||
block.subroutines.forEach {
|
block.subroutines.forEach {
|
||||||
out.write("<SUB SCOPEDNAME=${it.scopedName.joinToString(".")} RETURNTYPE=${it.returnType} POS=${it.position}>\n")
|
out.write("<SUB NAME=${it.name} RETURNTYPE=${it.returnType} POS=${it.position}>\n")
|
||||||
it.lines.forEach { line -> out.writeLine(line) }
|
it.lines.forEach { line -> out.writeLine(line) }
|
||||||
out.write("</SUB>\n")
|
out.write("</SUB>\n")
|
||||||
}
|
}
|
||||||
|
@@ -8,7 +8,33 @@ import prog8.code.core.IStringEncoding
|
|||||||
import prog8.code.core.Position
|
import prog8.code.core.Position
|
||||||
import java.nio.file.Path
|
import java.nio.file.Path
|
||||||
|
|
||||||
// TODO: move this Intermedate Representation into the actual compiler core, code gen modules can receive it as input rather than an Ast.
|
/*
|
||||||
|
PROGRAM:
|
||||||
|
OPTIONS (from CompilationOptions)
|
||||||
|
VARIABLES (from Symboltable)
|
||||||
|
MEMORYMAPPEDVARIABLES (from Symboltable)
|
||||||
|
MEMORYSLABS (from Symboltable)
|
||||||
|
GLOBALINITS
|
||||||
|
CODE-LINE (assignment to initialize a variable)
|
||||||
|
CODE-LINE (assignment to initialize a variable)
|
||||||
|
...
|
||||||
|
BLOCK
|
||||||
|
INLINEASM
|
||||||
|
INLINEASM
|
||||||
|
SUB
|
||||||
|
CODE-LINE (label, instruction, comment, inlinebinary)
|
||||||
|
CODE-LINE
|
||||||
|
CODE-LINE
|
||||||
|
...
|
||||||
|
SUB
|
||||||
|
SUB
|
||||||
|
ASMSUB
|
||||||
|
ASMSUB
|
||||||
|
...
|
||||||
|
BLOCK
|
||||||
|
BLOCK
|
||||||
|
...
|
||||||
|
*/
|
||||||
|
|
||||||
class IRProgram(val name: String,
|
class IRProgram(val name: String,
|
||||||
val st: SymbolTable,
|
val st: SymbolTable,
|
||||||
@@ -35,22 +61,16 @@ class IRBlock(
|
|||||||
operator fun plusAssign(sub: IRSubroutine) {
|
operator fun plusAssign(sub: IRSubroutine) {
|
||||||
subroutines += sub
|
subroutines += sub
|
||||||
}
|
}
|
||||||
operator fun plusAssign(sub: IRAsmSubroutine) {
|
operator fun plusAssign(sub: IRAsmSubroutine) { asmSubroutines += sub }
|
||||||
asmSubroutines += sub
|
operator fun plusAssign(asm: IRInlineAsmChunk) { inlineAssembly += asm }
|
||||||
}
|
|
||||||
operator fun plusAssign(asm: IRInlineAsmChunk) {
|
|
||||||
inlineAssembly += asm
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
class IRSubroutine(val scopedName: List<String>,
|
class IRSubroutine(val name: String,
|
||||||
val returnType: DataType?,
|
val returnType: DataType?,
|
||||||
val position: Position) {
|
val position: Position) {
|
||||||
val lines = mutableListOf<IRCodeLine>()
|
val lines = mutableListOf<IRCodeLine>()
|
||||||
|
|
||||||
operator fun plusAssign(chunk: IRCodeChunk) {
|
operator fun plusAssign(chunk: IRCodeChunk) { lines += chunk.lines }
|
||||||
lines += chunk.lines
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
class IRAsmSubroutine(val scopedName: List<String>,
|
class IRAsmSubroutine(val scopedName: List<String>,
|
||||||
|
@@ -2,15 +2,18 @@ package prog8.intermediate
|
|||||||
|
|
||||||
/*
|
/*
|
||||||
|
|
||||||
Virtual machine:
|
Intermediate Representation instructions for the IR Virtual machine.
|
||||||
|
--------------------------------------------------------------------
|
||||||
|
|
||||||
|
Specs of the virtual machine this will run on:
|
||||||
|
Program to execute is not stored in the system memory, it's just a separate list of instructions.
|
||||||
65536 virtual registers, 16 bits wide, can also be used as 8 bits. r0-r65535
|
65536 virtual registers, 16 bits wide, can also be used as 8 bits. r0-r65535
|
||||||
65536 virtual floating point registers (32 bits single precision floats) fr0-fr65535
|
65536 virtual floating point registers (32 bits single precision floats) fr0-fr65535
|
||||||
65536 bytes of memory. Thus memory pointers (addresses) are limited to 16 bits.
|
65536 bytes of memory. Thus memory pointers (addresses) are limited to 16 bits.
|
||||||
Value stack, max 128 entries of 1 byte each.
|
Value stack, max 128 entries of 1 byte each.
|
||||||
Status flags: Carry, Zero, Negative. NOTE: status flags are only affected by the CMP instruction or explicit CLC/SEC!!!
|
Status flags: Carry, Zero, Negative. NOTE: status flags are only affected by the CMP instruction or explicit CLC/SEC!!!
|
||||||
logical or arithmetic operations DO NOT AFFECT THE STATUS FLAGS UNLESS EXPLICITLY NOTED!
|
logical or arithmetic operations DO NOT AFFECT THE STATUS FLAGS UNLESS EXPLICITLY NOTED!
|
||||||
Program to execute is not stored in this memory, it's just a separate list of instructions.
|
|
||||||
Most instructions have an associated data type 'b','w','f'. (omitting it means 'b'/byte).
|
Most instructions have an associated data type 'b','w','f'. (omitting it means 'b'/byte).
|
||||||
Currently NO support for 24 or 32 bits integers.
|
Currently NO support for 24 or 32 bits integers.
|
||||||
Floating point operations are just 'f' typed regular instructions, and additionally there are a few fp conversion instructions
|
Floating point operations are just 'f' typed regular instructions, and additionally there are a few fp conversion instructions
|
||||||
|
@@ -10,6 +10,19 @@ import java.util.*
|
|||||||
import kotlin.math.*
|
import kotlin.math.*
|
||||||
import kotlin.random.Random
|
import kotlin.random.Random
|
||||||
|
|
||||||
|
/*
|
||||||
|
|
||||||
|
Virtual machine specs:
|
||||||
|
|
||||||
|
Program to execute is not stored in the system memory, it's just a separate list of instructions.
|
||||||
|
65536 virtual registers, 16 bits wide, can also be used as 8 bits. r0-r65535
|
||||||
|
65536 virtual floating point registers (32 bits single precision floats) fr0-fr65535
|
||||||
|
65536 bytes of memory. Thus memory pointers (addresses) are limited to 16 bits.
|
||||||
|
Value stack, max 128 entries of 1 byte each.
|
||||||
|
Status flags: Carry, Zero, Negative. NOTE: status flags are only affected by the CMP instruction or explicit CLC/SEC!!!
|
||||||
|
logical or arithmetic operations DO NOT AFFECT THE STATUS FLAGS UNLESS EXPLICITLY NOTED!
|
||||||
|
|
||||||
|
*/
|
||||||
|
|
||||||
class ProgramExitException(val status: Int): Exception()
|
class ProgramExitException(val status: Int): Exception()
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user