mirror of
https://github.com/irmen/prog8.git
synced 2025-02-19 11:31:07 +00:00
ir: making sure all names are scoped properly. textelite now runs in vm
This commit is contained in:
parent
dda19c29fe
commit
1d65d63bd9
@ -221,12 +221,11 @@ class StMemorySlab(
|
|||||||
name: String,
|
name: String,
|
||||||
val size: UInt,
|
val size: UInt,
|
||||||
val align: UInt,
|
val align: UInt,
|
||||||
val allocatedAddress: UInt? = null, // this is used (for now) in the VM code generator. TODO remove this once no longer used
|
|
||||||
position: Position
|
position: Position
|
||||||
):
|
):
|
||||||
StNode(name, StNodeType.MEMORYSLAB, position) {
|
StNode(name, StNodeType.MEMORYSLAB, position) {
|
||||||
override fun printProperties() {
|
override fun printProperties() {
|
||||||
print("$name size=$size align=$align address=$allocatedAddress")
|
print("$name size=$size align=$align")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2900,7 +2900,7 @@ $repeatLabel lda $counterVar
|
|||||||
|
|
||||||
fun addMemorySlab(name: String, size: UInt, align: UInt, position: Position): String {
|
fun addMemorySlab(name: String, size: UInt, align: UInt, position: Position): String {
|
||||||
val prefixedName = "prog8_memoryslab_$name"
|
val prefixedName = "prog8_memoryslab_$name"
|
||||||
symbolTable.add(StMemorySlab(prefixedName, size, align, null, position))
|
symbolTable.add(StMemorySlab(prefixedName, size, align, position))
|
||||||
return prefixedName
|
return prefixedName
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -27,7 +27,7 @@ class IRCodeGen(
|
|||||||
flattenLabelNames()
|
flattenLabelNames()
|
||||||
flattenNestedSubroutines()
|
flattenNestedSubroutines()
|
||||||
|
|
||||||
val irProg = IRProgram(program.name, symbolTable, options, program.encoding)
|
val irProg = IRProgram(program.name, IRSymbolTable(symbolTable), options, program.encoding)
|
||||||
|
|
||||||
if(!options.dontReinitGlobals) {
|
if(!options.dontReinitGlobals) {
|
||||||
// collect global variables initializers
|
// collect global variables initializers
|
||||||
@ -996,7 +996,8 @@ class IRCodeGen(
|
|||||||
private fun translate(parameters: List<PtSubroutineParameter>) =
|
private fun translate(parameters: List<PtSubroutineParameter>) =
|
||||||
parameters.map {
|
parameters.map {
|
||||||
val flattenedName = (it.definingSub()!!.scopedName + it.name)
|
val flattenedName = (it.definingSub()!!.scopedName + it.name)
|
||||||
symbolTable.flat.getValue(flattenedName) as StStaticVariable
|
val orig = symbolTable.flat.getValue(flattenedName) as StStaticVariable
|
||||||
|
IRSubroutine.IRParam(flattenedName.joinToString("."), orig.dt, orig)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun translate(alignment: PtBlock.BlockAlignment): IRBlock.BlockAlignment {
|
private fun translate(alignment: PtBlock.BlockAlignment): IRBlock.BlockAlignment {
|
||||||
@ -1036,7 +1037,7 @@ class IRCodeGen(
|
|||||||
|
|
||||||
fun addMemorySlab(name: String, size: UInt, align: UInt, position: Position): String {
|
fun addMemorySlab(name: String, size: UInt, align: UInt, position: Position): String {
|
||||||
val scopedName = "prog8_memoryslab_$name"
|
val scopedName = "prog8_memoryslab_$name"
|
||||||
symbolTable.add(StMemorySlab(scopedName, size, align, null, position))
|
symbolTable.add(StMemorySlab(scopedName, size, align, position))
|
||||||
return scopedName
|
return scopedName
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,5 @@
|
|||||||
import io.kotest.core.spec.style.FunSpec
|
import io.kotest.core.spec.style.FunSpec
|
||||||
import io.kotest.matchers.shouldBe
|
import io.kotest.matchers.shouldBe
|
||||||
import prog8.code.SymbolTable
|
|
||||||
import prog8.code.core.*
|
import prog8.code.core.*
|
||||||
import prog8.code.target.VMTarget
|
import prog8.code.target.VMTarget
|
||||||
import prog8.codegen.intermediate.IRPeepholeOptimizer
|
import prog8.codegen.intermediate.IRPeepholeOptimizer
|
||||||
@ -15,7 +14,6 @@ class TestIRPeepholeOpt: FunSpec({
|
|||||||
chunk += line
|
chunk += line
|
||||||
sub += chunk
|
sub += chunk
|
||||||
block += sub
|
block += sub
|
||||||
val st = SymbolTable()
|
|
||||||
val target = VMTarget()
|
val target = VMTarget()
|
||||||
val options = CompilationOptions(
|
val options = CompilationOptions(
|
||||||
OutputType.RAW,
|
OutputType.RAW,
|
||||||
@ -27,7 +25,7 @@ class TestIRPeepholeOpt: FunSpec({
|
|||||||
compTarget = target,
|
compTarget = target,
|
||||||
loadAddress = target.machine.PROGRAM_LOAD_ADDRESS
|
loadAddress = target.machine.PROGRAM_LOAD_ADDRESS
|
||||||
)
|
)
|
||||||
val prog = IRProgram("test", st, options, target)
|
val prog = IRProgram("test", IRSymbolTable(null), options, target)
|
||||||
prog.addBlock(block)
|
prog.addBlock(block)
|
||||||
return prog
|
return prog
|
||||||
}
|
}
|
||||||
|
@ -20,7 +20,7 @@ internal class VmAssemblyProgram(override val name: String, private val irProgra
|
|||||||
|
|
||||||
outfile.bufferedWriter().use { out ->
|
outfile.bufferedWriter().use { out ->
|
||||||
allocations.asVmMemory().forEach { (name, alloc) ->
|
allocations.asVmMemory().forEach { (name, alloc) ->
|
||||||
out.write("var ${name.joinToString(".")} $alloc\n")
|
out.write("var ${name} $alloc\n")
|
||||||
}
|
}
|
||||||
|
|
||||||
out.write("------PROGRAM------\n")
|
out.write("------PROGRAM------\n")
|
||||||
|
@ -1,12 +1,12 @@
|
|||||||
package prog8.codegen.virtual
|
package prog8.codegen.virtual
|
||||||
|
|
||||||
import prog8.code.SymbolTable
|
|
||||||
import prog8.code.core.*
|
import prog8.code.core.*
|
||||||
|
import prog8.intermediate.IRSymbolTable
|
||||||
import prog8.intermediate.getTypeString
|
import prog8.intermediate.getTypeString
|
||||||
|
|
||||||
internal class VmVariableAllocator(val st: SymbolTable, val encoding: IStringEncoding, memsizer: IMemSizer) {
|
internal class VmVariableAllocator(val st: IRSymbolTable, val encoding: IStringEncoding, memsizer: IMemSizer) {
|
||||||
|
|
||||||
internal val allocations = mutableMapOf<List<String>, Int>()
|
internal val allocations = mutableMapOf<String, Int>()
|
||||||
private var freeMemoryStart: Int
|
private var freeMemoryStart: Int
|
||||||
|
|
||||||
val freeMem: Int
|
val freeMem: Int
|
||||||
@ -15,7 +15,7 @@ internal class VmVariableAllocator(val st: SymbolTable, val encoding: IStringEnc
|
|||||||
|
|
||||||
init {
|
init {
|
||||||
var nextLocation = 0
|
var nextLocation = 0
|
||||||
for (variable in st.allVariables) {
|
for (variable in st.allVariables()) {
|
||||||
val memsize =
|
val memsize =
|
||||||
when (variable.dt) {
|
when (variable.dt) {
|
||||||
DataType.STR -> variable.onetimeInitializationStringValue!!.first.length + 1 // include the zero byte
|
DataType.STR -> variable.onetimeInitializationStringValue!!.first.length + 1 // include the zero byte
|
||||||
@ -24,24 +24,24 @@ internal class VmVariableAllocator(val st: SymbolTable, val encoding: IStringEnc
|
|||||||
else -> throw InternalCompilerException("weird dt")
|
else -> throw InternalCompilerException("weird dt")
|
||||||
}
|
}
|
||||||
|
|
||||||
allocations[variable.scopedName] = nextLocation
|
allocations[variable.name] = nextLocation
|
||||||
nextLocation += memsize
|
nextLocation += memsize
|
||||||
}
|
}
|
||||||
for(slab in st.allMemorySlabs) {
|
for(slab in st.allMemorySlabs()) {
|
||||||
// we ignore the alignment for the VM.
|
// we ignore the alignment for the VM.
|
||||||
allocations[slab.scopedName] = nextLocation
|
allocations[slab.name] = nextLocation
|
||||||
nextLocation += slab.size.toInt()
|
nextLocation += slab.size.toInt()
|
||||||
}
|
}
|
||||||
|
|
||||||
freeMemoryStart = nextLocation
|
freeMemoryStart = nextLocation
|
||||||
}
|
}
|
||||||
|
|
||||||
fun asVmMemory(): List<Pair<List<String>, String>> {
|
fun asVmMemory(): List<Pair<String, String>> {
|
||||||
val mm = mutableListOf<Pair<List<String>, String>>()
|
val mm = mutableListOf<Pair<String, String>>()
|
||||||
|
|
||||||
// normal variables
|
// normal variables
|
||||||
for (variable in st.allVariables) {
|
for (variable in st.allVariables()) {
|
||||||
val location = allocations.getValue(variable.scopedName)
|
val location = allocations.getValue(variable.name)
|
||||||
val value = when(variable.dt) {
|
val value = when(variable.dt) {
|
||||||
DataType.FLOAT -> (variable.onetimeInitializationNumericValue ?: 0.0).toString()
|
DataType.FLOAT -> (variable.onetimeInitializationNumericValue ?: 0.0).toString()
|
||||||
in NumericDatatypes -> (variable.onetimeInitializationNumericValue ?: 0).toHex()
|
in NumericDatatypes -> (variable.onetimeInitializationNumericValue ?: 0).toHex()
|
||||||
@ -70,11 +70,11 @@ internal class VmVariableAllocator(val st: SymbolTable, val encoding: IStringEnc
|
|||||||
}
|
}
|
||||||
else -> throw InternalCompilerException("weird dt")
|
else -> throw InternalCompilerException("weird dt")
|
||||||
}
|
}
|
||||||
mm.add(Pair(variable.scopedName, "@$location ${getTypeString(variable)} $value"))
|
mm.add(Pair(variable.name, "@$location ${getTypeString(variable)} $value"))
|
||||||
}
|
}
|
||||||
|
|
||||||
// memory mapped variables
|
// memory mapped variables
|
||||||
for (variable in st.allMemMappedVariables) {
|
for (variable in st.allMemMappedVariables()) {
|
||||||
val value = when(variable.dt) {
|
val value = when(variable.dt) {
|
||||||
DataType.FLOAT -> "0.0"
|
DataType.FLOAT -> "0.0"
|
||||||
in NumericDatatypes -> "0"
|
in NumericDatatypes -> "0"
|
||||||
@ -82,13 +82,13 @@ internal class VmVariableAllocator(val st: SymbolTable, val encoding: IStringEnc
|
|||||||
in ArrayDatatypes -> (1..variable.length!!).joinToString(",") { "0" }
|
in ArrayDatatypes -> (1..variable.length!!).joinToString(",") { "0" }
|
||||||
else -> throw InternalCompilerException("weird dt for mem mapped var")
|
else -> throw InternalCompilerException("weird dt for mem mapped var")
|
||||||
}
|
}
|
||||||
mm.add(Pair(variable.scopedName, "@${variable.address} ${getTypeString(variable)} $value"))
|
mm.add(Pair(variable.name, "@${variable.address} ${getTypeString(variable)} $value"))
|
||||||
}
|
}
|
||||||
|
|
||||||
// memory slabs.
|
// memory slabs.
|
||||||
for(slab in st.allMemorySlabs) {
|
for(slab in st.allMemorySlabs()) {
|
||||||
val address = allocations.getValue(slab.scopedName)
|
val address = allocations.getValue(slab.name)
|
||||||
mm.add(Pair(slab.scopedName, "@$address ubyte[${slab.size}] 0"))
|
mm.add(Pair(slab.name, "@$address ubyte[${slab.size}] 0"))
|
||||||
}
|
}
|
||||||
|
|
||||||
return mm
|
return mm
|
||||||
|
@ -14,7 +14,6 @@ import prog8.ast.statements.VarDecl
|
|||||||
import prog8.code.core.DataType
|
import prog8.code.core.DataType
|
||||||
import prog8.code.core.Position
|
import prog8.code.core.Position
|
||||||
import prog8.code.target.C64Target
|
import prog8.code.target.C64Target
|
||||||
import prog8.code.target.VMTarget
|
|
||||||
import prog8tests.helpers.ErrorReporterForTests
|
import prog8tests.helpers.ErrorReporterForTests
|
||||||
import prog8tests.helpers.compileText
|
import prog8tests.helpers.compileText
|
||||||
|
|
||||||
@ -31,7 +30,7 @@ class TestTypecasts: FunSpec({
|
|||||||
}
|
}
|
||||||
}"""
|
}"""
|
||||||
val errors = ErrorReporterForTests()
|
val errors = ErrorReporterForTests()
|
||||||
val result = compileText(VMTarget(), false, text, writeAssembly = false, errors=errors)
|
val result = compileText(C64Target(), false, text, writeAssembly = false, errors=errors)
|
||||||
result shouldBe null
|
result shouldBe null
|
||||||
errors.errors.size shouldBe 1
|
errors.errors.size shouldBe 1
|
||||||
errors.errors[0] shouldContain "type mismatch, was: FLOAT expected one of: [UBYTE, BYTE, UWORD, WORD]"
|
errors.errors[0] shouldContain "type mismatch, was: FLOAT expected one of: [UBYTE, BYTE, UWORD, WORD]"
|
||||||
@ -627,9 +626,9 @@ main {
|
|||||||
ubyte @shared wordNr2 = (interlaced >= ${'$'}33) + (interlaced >= ${'$'}66) + (interlaced >= ${'$'}99) + (interlaced >= ${'$'}CC)
|
ubyte @shared wordNr2 = (interlaced >= ${'$'}33) + (interlaced >= ${'$'}66) + (interlaced >= ${'$'}99) + (interlaced >= ${'$'}CC)
|
||||||
}
|
}
|
||||||
}"""
|
}"""
|
||||||
val result = compileText(VMTarget(), false, text, writeAssembly = true)!!
|
val result = compileText(C64Target(), false, text, writeAssembly = true)!!
|
||||||
val stmts = result.program.entrypoint.statements
|
val stmts = result.program.entrypoint.statements
|
||||||
stmts.size shouldBe 14
|
stmts.size shouldBeGreaterThan 10
|
||||||
}
|
}
|
||||||
|
|
||||||
test("word to byte casts") {
|
test("word to byte casts") {
|
||||||
|
@ -3,7 +3,6 @@ TODO
|
|||||||
|
|
||||||
For next release
|
For next release
|
||||||
^^^^^^^^^^^^^^^^
|
^^^^^^^^^^^^^^^^
|
||||||
- fix vm assembler bug in TestCompilerVirtual when no IR code is written (IRWriter.writeVariableAllocations TODO)
|
|
||||||
- fix examples/vm/textelite.p8 having wrong randomization? (starts with wrong planet)
|
- fix examples/vm/textelite.p8 having wrong randomization? (starts with wrong planet)
|
||||||
|
|
||||||
...
|
...
|
||||||
|
@ -32,7 +32,7 @@ class IRFileReader(outputDir: Path, programName: String) {
|
|||||||
val initGlobals = parseInitGlobals(lines)
|
val initGlobals = parseInitGlobals(lines)
|
||||||
val blocks = parseBlocksUntilProgramEnd(lines, variables)
|
val blocks = parseBlocksUntilProgramEnd(lines, variables)
|
||||||
|
|
||||||
val st = SymbolTable()
|
val st = IRSymbolTable(null)
|
||||||
variables.forEach { st.add(it) }
|
variables.forEach { st.add(it) }
|
||||||
memorymapped.forEach { st.add(it) }
|
memorymapped.forEach { st.add(it) }
|
||||||
slabs.forEach { st.add(it) }
|
slabs.forEach { st.add(it) }
|
||||||
@ -213,7 +213,7 @@ class IRFileReader(outputDir: Path, programName: String) {
|
|||||||
// example: "SLAB slabname 4096 0"
|
// example: "SLAB slabname 4096 0"
|
||||||
val match = slabPattern.matchEntire(line) ?: throw IRParseException("invalid SLAB $line")
|
val match = slabPattern.matchEntire(line) ?: throw IRParseException("invalid SLAB $line")
|
||||||
val (name, size, align) = match.destructured
|
val (name, size, align) = match.destructured
|
||||||
slabs.add(StMemorySlab(name, size.toUInt(), align.toUInt(), null, Position.DUMMY))
|
slabs.add(StMemorySlab(name, size.toUInt(), align.toUInt(), Position.DUMMY))
|
||||||
}
|
}
|
||||||
return slabs
|
return slabs
|
||||||
}
|
}
|
||||||
@ -365,18 +365,19 @@ class IRFileReader(outputDir: Path, programName: String) {
|
|||||||
return sub
|
return sub
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun parseParameters(lines: Iterator<String>, variables: List<StStaticVariable>): List<StStaticVariable> {
|
private fun parseParameters(lines: Iterator<String>, variables: List<StStaticVariable>): List<IRSubroutine.IRParam> {
|
||||||
var line = lines.next()
|
var line = lines.next()
|
||||||
if(line!="<PARAMS>")
|
if(line!="<PARAMS>")
|
||||||
throw IRParseException("missing PARAMS")
|
throw IRParseException("missing PARAMS")
|
||||||
val params = mutableListOf<StStaticVariable>()
|
val params = mutableListOf<IRSubroutine.IRParam>()
|
||||||
while(true) {
|
while(true) {
|
||||||
line = lines.next()
|
line = lines.next()
|
||||||
if(line=="</PARAMS>")
|
if(line=="</PARAMS>")
|
||||||
return params
|
return params
|
||||||
val (datatype, name) = line.split(' ')
|
val (datatype, name) = line.split(' ')
|
||||||
val dt = parseDatatype(datatype, datatype.contains('['))
|
val dt = parseDatatype(datatype, datatype.contains('['))
|
||||||
params.add(variables.single { it.dt==dt && it.name==name})
|
val orig = variables.single { it.dt==dt && it.name==name}
|
||||||
|
params.add(IRSubroutine.IRParam(name, dt, orig))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -38,7 +38,7 @@ class IRFileWriter(private val irProgram: IRProgram) {
|
|||||||
block.subroutines.forEach {
|
block.subroutines.forEach {
|
||||||
out.write("<SUB NAME=${it.name} RETURNTYPE=${it.returnType.toString().lowercase()} POS=${it.position}>\n")
|
out.write("<SUB NAME=${it.name} RETURNTYPE=${it.returnType.toString().lowercase()} POS=${it.position}>\n")
|
||||||
out.write("<PARAMS>\n")
|
out.write("<PARAMS>\n")
|
||||||
it.parameters.forEach { param -> out.write("${getTypeString(param)} ${param.scopedName.joinToString(".")}\n") }
|
it.parameters.forEach { param -> out.write("${getTypeString(param.dt)} ${param.name}\n") }
|
||||||
out.write("</PARAMS>\n")
|
out.write("</PARAMS>\n")
|
||||||
it.chunks.forEach { chunk ->
|
it.chunks.forEach { chunk ->
|
||||||
if(chunk is IRInlineAsmChunk) {
|
if(chunk is IRInlineAsmChunk) {
|
||||||
@ -100,7 +100,7 @@ class IRFileWriter(private val irProgram: IRProgram) {
|
|||||||
|
|
||||||
private fun writeVariableAllocations() {
|
private fun writeVariableAllocations() {
|
||||||
out.write("\n<VARIABLES>\n")
|
out.write("\n<VARIABLES>\n")
|
||||||
for (variable in irProgram.st.allVariables) {
|
for (variable in irProgram.st.allVariables()) {
|
||||||
val typeStr = getTypeString(variable)
|
val typeStr = getTypeString(variable)
|
||||||
val value: String = when(variable.dt) {
|
val value: String = when(variable.dt) {
|
||||||
DataType.FLOAT -> (variable.onetimeInitializationNumericValue ?: 0.0).toString()
|
DataType.FLOAT -> (variable.onetimeInitializationNumericValue ?: 0.0).toString()
|
||||||
@ -121,12 +121,8 @@ class IRFileWriter(private val irProgram: IRProgram) {
|
|||||||
variable.onetimeInitializationArrayValue!!.joinToString(",") {
|
variable.onetimeInitializationArrayValue!!.joinToString(",") {
|
||||||
if(it.number!=null)
|
if(it.number!=null)
|
||||||
it.number!!.toInt().toString()
|
it.number!!.toInt().toString()
|
||||||
else {
|
else
|
||||||
// TODO : don't do a lookup; addressOf should be scoped properly already!
|
"&${it.addressOf!!.joinToString(".")}"
|
||||||
val target = variable.lookup(it.addressOf!!)
|
|
||||||
?: throw InternalCompilerException("symbol not found: ${it.addressOf} in ${variable.scopedName}")
|
|
||||||
"&${target.scopedName.joinToString(".")}"
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
(1..variable.length!!).joinToString(",") { "0" }
|
(1..variable.length!!).joinToString(",") { "0" }
|
||||||
@ -135,19 +131,19 @@ class IRFileWriter(private val irProgram: IRProgram) {
|
|||||||
else -> throw InternalCompilerException("weird dt")
|
else -> throw InternalCompilerException("weird dt")
|
||||||
}
|
}
|
||||||
// TODO have uninitialized variables and arrays? (BSS SECTION)
|
// TODO have uninitialized variables and arrays? (BSS SECTION)
|
||||||
out.write("$typeStr ${variable.scopedName.joinToString(".")}=$value zp=${variable.zpwish}\n")
|
out.write("$typeStr ${variable.name}=$value zp=${variable.zpwish}\n")
|
||||||
}
|
}
|
||||||
out.write("</VARIABLES>\n")
|
out.write("</VARIABLES>\n")
|
||||||
|
|
||||||
out.write("\n<MEMORYMAPPEDVARIABLES>\n")
|
out.write("\n<MEMORYMAPPEDVARIABLES>\n")
|
||||||
for (variable in irProgram.st.allMemMappedVariables) {
|
for (variable in irProgram.st.allMemMappedVariables()) {
|
||||||
val typeStr = getTypeString(variable)
|
val typeStr = getTypeString(variable)
|
||||||
out.write("&$typeStr ${variable.scopedName.joinToString(".")}=${variable.address}\n")
|
out.write("&$typeStr ${variable.name}=${variable.address}\n")
|
||||||
}
|
}
|
||||||
out.write("</MEMORYMAPPEDVARIABLES>\n")
|
out.write("</MEMORYMAPPEDVARIABLES>\n")
|
||||||
|
|
||||||
out.write("\n<MEMORYSLABS>\n")
|
out.write("\n<MEMORYSLABS>\n")
|
||||||
irProgram.st.allMemorySlabs.forEach{ slab -> out.write("SLAB ${slab.name} ${slab.size} ${slab.align}\n") }
|
irProgram.st.allMemorySlabs().forEach{ slab -> out.write("SLAB ${slab.name} ${slab.size} ${slab.align}\n") }
|
||||||
out.write("</MEMORYSLABS>\n")
|
out.write("</MEMORYSLABS>\n")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,7 +1,6 @@
|
|||||||
package prog8.intermediate
|
package prog8.intermediate
|
||||||
|
|
||||||
import prog8.code.StStaticVariable
|
import prog8.code.StStaticVariable
|
||||||
import prog8.code.SymbolTable
|
|
||||||
import prog8.code.core.*
|
import prog8.code.core.*
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -47,7 +46,7 @@ PROGRAM:
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
class IRProgram(val name: String,
|
class IRProgram(val name: String,
|
||||||
val st: SymbolTable,
|
val st: IRSymbolTable,
|
||||||
val options: CompilationOptions,
|
val options: CompilationOptions,
|
||||||
val encoding: IStringEncoding) {
|
val encoding: IStringEncoding) {
|
||||||
|
|
||||||
@ -86,10 +85,12 @@ class IRBlock(
|
|||||||
}
|
}
|
||||||
|
|
||||||
class IRSubroutine(val name: String,
|
class IRSubroutine(val name: String,
|
||||||
val parameters: List<StStaticVariable>, // NOTE: these are the same objects as their occurrences as variables in the symbol table
|
val parameters: List<IRParam>,
|
||||||
val returnType: DataType?,
|
val returnType: DataType?,
|
||||||
val position: Position) {
|
val position: Position) {
|
||||||
|
|
||||||
|
class IRParam(val name: String, val dt: DataType, val orig: StStaticVariable)
|
||||||
|
|
||||||
val chunks = mutableListOf<IRCodeChunkBase>()
|
val chunks = mutableListOf<IRCodeChunkBase>()
|
||||||
|
|
||||||
init {
|
init {
|
||||||
@ -115,8 +116,6 @@ class IRAsmSubroutine(val name: String,
|
|||||||
val parameters: List<Pair<DataType, RegisterOrStatusflag>>,
|
val parameters: List<Pair<DataType, RegisterOrStatusflag>>,
|
||||||
val returns: List<Pair<DataType, RegisterOrStatusflag>>,
|
val returns: List<Pair<DataType, RegisterOrStatusflag>>,
|
||||||
val assembly: String) {
|
val assembly: String) {
|
||||||
val lines = mutableListOf<IRCodeLine>()
|
|
||||||
|
|
||||||
init {
|
init {
|
||||||
if(!name.contains('.'))
|
if(!name.contains('.'))
|
||||||
throw IllegalArgumentException("subroutine name is not scoped: $name")
|
throw IllegalArgumentException("subroutine name is not scoped: $name")
|
||||||
|
111
intermediate/src/prog8/intermediate/IRSymbolTable.kt
Normal file
111
intermediate/src/prog8/intermediate/IRSymbolTable.kt
Normal file
@ -0,0 +1,111 @@
|
|||||||
|
package prog8.intermediate
|
||||||
|
|
||||||
|
import prog8.code.*
|
||||||
|
|
||||||
|
|
||||||
|
// In the Intermediate Representation, all nesting has been removed.
|
||||||
|
// So the symbol table is just a big flat mapping of (scoped)name to node.
|
||||||
|
|
||||||
|
class IRSymbolTable(sourceSt: SymbolTable?) {
|
||||||
|
private val table = mutableMapOf<String, StNode>()
|
||||||
|
|
||||||
|
init {
|
||||||
|
if(sourceSt!=null) {
|
||||||
|
sourceSt.allVariables.forEach {
|
||||||
|
add(it)
|
||||||
|
}
|
||||||
|
sourceSt.allMemMappedVariables.forEach {
|
||||||
|
add(it)
|
||||||
|
}
|
||||||
|
sourceSt.allMemorySlabs.forEach {
|
||||||
|
add(it)
|
||||||
|
}
|
||||||
|
|
||||||
|
require(table.all { it.key==it.value.name })
|
||||||
|
|
||||||
|
allVariables().forEach {variable ->
|
||||||
|
variable.onetimeInitializationArrayValue?.let {
|
||||||
|
it.forEach { arrayElt ->
|
||||||
|
if(arrayElt.addressOf!=null) {
|
||||||
|
require(arrayElt.addressOf!!.size > 1) {
|
||||||
|
"pointer var in array should be properly scoped: ${arrayElt.addressOf!!} in ${variable.name}"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun allVariables(): Sequence<StStaticVariable> =
|
||||||
|
table.asSequence().map { it.value }.filterIsInstance<StStaticVariable>()
|
||||||
|
|
||||||
|
fun allMemMappedVariables(): Sequence<StMemVar> =
|
||||||
|
table.asSequence().map { it.value }.filterIsInstance<StMemVar>()
|
||||||
|
|
||||||
|
fun allMemorySlabs(): Sequence<StMemorySlab> =
|
||||||
|
table.asSequence().map { it.value }.filterIsInstance<StMemorySlab>()
|
||||||
|
|
||||||
|
fun lookup(name: String) = table[name]
|
||||||
|
|
||||||
|
fun add(variable: StStaticVariable) {
|
||||||
|
val scopedName: String
|
||||||
|
val varToadd: StStaticVariable
|
||||||
|
if('.' in variable.name) {
|
||||||
|
scopedName = variable.name
|
||||||
|
varToadd = variable
|
||||||
|
} else {
|
||||||
|
fun fixupAddressOfInArray(array: List<StArrayElement>?): List<StArrayElement>? {
|
||||||
|
if(array==null)
|
||||||
|
return null
|
||||||
|
val newArray = mutableListOf<StArrayElement>()
|
||||||
|
array.forEach {
|
||||||
|
if(it.addressOf!=null) {
|
||||||
|
val target = variable.lookup(it.addressOf!!)!!
|
||||||
|
newArray.add(StArrayElement(null, target.scopedName))
|
||||||
|
} else {
|
||||||
|
newArray.add(it)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return newArray
|
||||||
|
}
|
||||||
|
scopedName = variable.scopedName.joinToString(".")
|
||||||
|
varToadd = StStaticVariable(scopedName, variable.dt,
|
||||||
|
variable.onetimeInitializationNumericValue,
|
||||||
|
variable.onetimeInitializationStringValue,
|
||||||
|
fixupAddressOfInArray(variable.onetimeInitializationArrayValue),
|
||||||
|
variable.length,
|
||||||
|
variable.zpwish,
|
||||||
|
variable.position
|
||||||
|
)
|
||||||
|
}
|
||||||
|
table[scopedName] = varToadd
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
fun add(variable: StMemVar) {
|
||||||
|
val scopedName: String
|
||||||
|
val varToadd: StMemVar
|
||||||
|
if('.' in variable.name) {
|
||||||
|
scopedName = variable.name
|
||||||
|
varToadd = variable
|
||||||
|
} else {
|
||||||
|
scopedName = variable.scopedName.joinToString(".")
|
||||||
|
varToadd = StMemVar(scopedName, variable.dt, variable.address, variable.length, variable.position)
|
||||||
|
}
|
||||||
|
table[scopedName] = varToadd
|
||||||
|
}
|
||||||
|
|
||||||
|
fun add(variable: StMemorySlab) {
|
||||||
|
val scopedName: String
|
||||||
|
val varToadd: StMemorySlab
|
||||||
|
if('.' in variable.name) {
|
||||||
|
scopedName = variable.name
|
||||||
|
varToadd = variable
|
||||||
|
} else {
|
||||||
|
scopedName = variable.scopedName.joinToString(".")
|
||||||
|
varToadd = StMemorySlab(scopedName, variable.size, variable.align, variable.position)
|
||||||
|
}
|
||||||
|
table[scopedName] = varToadd
|
||||||
|
}
|
||||||
|
}
|
@ -6,7 +6,7 @@ import prog8.code.core.DataType
|
|||||||
import prog8.code.core.InternalCompilerException
|
import prog8.code.core.InternalCompilerException
|
||||||
|
|
||||||
|
|
||||||
public fun getTypeString(dt : DataType): String {
|
fun getTypeString(dt : DataType): String {
|
||||||
return when(dt) {
|
return when(dt) {
|
||||||
DataType.UBYTE -> "ubyte"
|
DataType.UBYTE -> "ubyte"
|
||||||
DataType.BYTE -> "byte"
|
DataType.BYTE -> "byte"
|
||||||
@ -22,7 +22,7 @@ public fun getTypeString(dt : DataType): String {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public fun getTypeString(memvar: StMemVar): String {
|
fun getTypeString(memvar: StMemVar): String {
|
||||||
return when(memvar.dt) {
|
return when(memvar.dt) {
|
||||||
DataType.UBYTE -> "ubyte"
|
DataType.UBYTE -> "ubyte"
|
||||||
DataType.BYTE -> "byte"
|
DataType.BYTE -> "byte"
|
||||||
@ -38,7 +38,7 @@ public fun getTypeString(memvar: StMemVar): String {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public fun getTypeString(variable : StStaticVariable): String {
|
fun getTypeString(variable : StStaticVariable): String {
|
||||||
return when(variable.dt) {
|
return when(variable.dt) {
|
||||||
DataType.UBYTE -> "ubyte"
|
DataType.UBYTE -> "ubyte"
|
||||||
DataType.BYTE -> "byte"
|
DataType.BYTE -> "byte"
|
||||||
|
@ -3,7 +3,6 @@ import io.kotest.matchers.ints.shouldBeGreaterThan
|
|||||||
import io.kotest.matchers.shouldBe
|
import io.kotest.matchers.shouldBe
|
||||||
import io.kotest.matchers.types.instanceOf
|
import io.kotest.matchers.types.instanceOf
|
||||||
import prog8.code.StStaticVariable
|
import prog8.code.StStaticVariable
|
||||||
import prog8.code.SymbolTable
|
|
||||||
import prog8.code.core.CbmPrgLauncherType
|
import prog8.code.core.CbmPrgLauncherType
|
||||||
import prog8.code.core.CompilationOptions
|
import prog8.code.core.CompilationOptions
|
||||||
import prog8.code.core.OutputType
|
import prog8.code.core.OutputType
|
||||||
@ -12,11 +11,11 @@ import prog8.code.target.Cx16Target
|
|||||||
import prog8.intermediate.IRFileReader
|
import prog8.intermediate.IRFileReader
|
||||||
import prog8.intermediate.IRFileWriter
|
import prog8.intermediate.IRFileWriter
|
||||||
import prog8.intermediate.IRProgram
|
import prog8.intermediate.IRProgram
|
||||||
|
import prog8.intermediate.IRSymbolTable
|
||||||
import kotlin.io.path.*
|
import kotlin.io.path.*
|
||||||
|
|
||||||
class TestIRFileInOut: FunSpec({
|
class TestIRFileInOut: FunSpec({
|
||||||
test("test IR writer") {
|
test("test IR writer") {
|
||||||
val st = SymbolTable()
|
|
||||||
val target = Cx16Target()
|
val target = Cx16Target()
|
||||||
val tempdir = Path(System.getProperty("java.io.tmpdir"))
|
val tempdir = Path(System.getProperty("java.io.tmpdir"))
|
||||||
val options = CompilationOptions(
|
val options = CompilationOptions(
|
||||||
@ -30,7 +29,7 @@ class TestIRFileInOut: FunSpec({
|
|||||||
loadAddress = target.machine.PROGRAM_LOAD_ADDRESS,
|
loadAddress = target.machine.PROGRAM_LOAD_ADDRESS,
|
||||||
outputDir = tempdir
|
outputDir = tempdir
|
||||||
)
|
)
|
||||||
val program = IRProgram("unittest-irwriter", st, options, target)
|
val program = IRProgram("unittest-irwriter", IRSymbolTable(null), options, target)
|
||||||
val writer = IRFileWriter(program)
|
val writer = IRFileWriter(program)
|
||||||
writer.writeFile()
|
writer.writeFile()
|
||||||
val generatedFile = tempdir.resolve("unittest-irwriter.p8ir")
|
val generatedFile = tempdir.resolve("unittest-irwriter.p8ir")
|
||||||
@ -96,7 +95,7 @@ return
|
|||||||
</BLOCK>
|
</BLOCK>
|
||||||
</PROGRAM>
|
</PROGRAM>
|
||||||
"""
|
"""
|
||||||
val tempfile = kotlin.io.path.createTempFile(suffix = ".p8ir")
|
val tempfile = createTempFile(suffix = ".p8ir")
|
||||||
tempfile.writeText(source)
|
tempfile.writeText(source)
|
||||||
val filepart = tempfile.name.dropLast(5)
|
val filepart = tempfile.name.dropLast(5)
|
||||||
val reader = IRFileReader(tempfile.parent, filepart)
|
val reader = IRFileReader(tempfile.parent, filepart)
|
||||||
@ -104,6 +103,7 @@ return
|
|||||||
tempfile.deleteExisting()
|
tempfile.deleteExisting()
|
||||||
program.name shouldBe "test-ir-reader"
|
program.name shouldBe "test-ir-reader"
|
||||||
program.blocks.size shouldBe 2
|
program.blocks.size shouldBe 2
|
||||||
|
program.st.allVariables().count() shouldBe 1
|
||||||
program.st.lookup("sys.wait.jiffies") shouldBe instanceOf<StStaticVariable>()
|
program.st.lookup("sys.wait.jiffies") shouldBe instanceOf<StStaticVariable>()
|
||||||
}
|
}
|
||||||
})
|
})
|
Loading…
x
Reference in New Issue
Block a user