mirror of
https://github.com/irmen/prog8.git
synced 2024-11-26 11:49:22 +00:00
intermediate program written in blocks
This commit is contained in:
parent
987915a77a
commit
dff4518608
@ -31,3 +31,11 @@ sub start() {
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
~ block2 $c000 {
|
||||
|
||||
str derp="hello"
|
||||
byte v =44
|
||||
return
|
||||
}
|
||||
|
@ -99,7 +99,7 @@ fun main(args: Array<String>) {
|
||||
|
||||
val stackVmFilename = intermediate.name + "_stackvm.txt"
|
||||
val stackvmFile = PrintStream(File(stackVmFilename), "utf-8")
|
||||
intermediate.writeAsText(stackvmFile)
|
||||
intermediate.writeCode(stackvmFile)
|
||||
stackvmFile.close()
|
||||
println("StackVM program code written to '$stackVmFilename'")
|
||||
|
||||
|
File diff suppressed because it is too large
Load Diff
323
compiler/src/prog8/compiler/IntermediateProgram.kt
Normal file
323
compiler/src/prog8/compiler/IntermediateProgram.kt
Normal file
@ -0,0 +1,323 @@
|
||||
package prog8.compiler
|
||||
|
||||
import prog8.ast.DataType
|
||||
import prog8.ast.LiteralValue
|
||||
import prog8.ast.Position
|
||||
import prog8.ast.VarDecl
|
||||
import prog8.stackvm.*
|
||||
import java.io.PrintStream
|
||||
|
||||
|
||||
class IntermediateProgram(val name: String, val heap: HeapValues) {
|
||||
|
||||
private class ProgramBlock(val scopedname: String, val address: Int?) {
|
||||
val instructions = mutableListOf<Instruction>()
|
||||
val variables = mutableMapOf<String, Value>()
|
||||
val labels = mutableMapOf<String, Instruction>()
|
||||
|
||||
val numVariables: Int
|
||||
get() { return variables.size }
|
||||
val numInstructions: Int
|
||||
get() { return instructions.filter { it.opcode!= Opcode.LINE }.size }
|
||||
}
|
||||
|
||||
private val blocks = mutableListOf<ProgramBlock>()
|
||||
private val memory = mutableMapOf<Int, List<Value>>()
|
||||
private lateinit var currentBlock: ProgramBlock
|
||||
|
||||
val numVariables: Int
|
||||
get() = blocks.sumBy { it.numVariables }
|
||||
val numInstructions: Int
|
||||
get() = blocks.sumBy { it.numInstructions }
|
||||
|
||||
fun optimize() {
|
||||
println("Optimizing stackVM code...")
|
||||
optimizeDataConversionAndUselessDiscards()
|
||||
optimizeVariableCopying()
|
||||
optimizeMultipleSequentialLineInstrs()
|
||||
// todo optimize stackvm code more
|
||||
|
||||
// remove nops (that are not a label)
|
||||
for (blk in blocks) {
|
||||
blk.instructions.removeIf { it.opcode== Opcode.NOP && it !is LabelInstr }
|
||||
}
|
||||
}
|
||||
|
||||
private fun optimizeMultipleSequentialLineInstrs() {
|
||||
for(blk in blocks) {
|
||||
val instructionsToReplace = mutableMapOf<Int, Instruction>()
|
||||
|
||||
blk.instructions.asSequence().withIndex().windowed(2).toList().forEach {
|
||||
if (it[0].value.opcode == Opcode.LINE && it[1].value.opcode == Opcode.LINE)
|
||||
instructionsToReplace[it[0].index] = Instruction(Opcode.NOP)
|
||||
}
|
||||
|
||||
for (rins in instructionsToReplace) {
|
||||
blk.instructions[rins.key] = rins.value
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun optimizeVariableCopying() {
|
||||
for(blk in blocks) {
|
||||
|
||||
val instructionsToReplace = mutableMapOf<Int, Instruction>()
|
||||
|
||||
blk.instructions.asSequence().withIndex().windowed(2).toList().forEach {
|
||||
when (it[0].value.opcode) {
|
||||
Opcode.PUSH_VAR_BYTE ->
|
||||
if (it[1].value.opcode == Opcode.POP_VAR_BYTE) {
|
||||
if (it[0].value.callLabel != it[1].value.callLabel)
|
||||
instructionsToReplace[it[0].index] = Instruction(Opcode.COPY_VAR_BYTE, null, it[0].value.callLabel, it[1].value.callLabel)
|
||||
else
|
||||
instructionsToReplace[it[0].index] = Instruction(Opcode.NOP)
|
||||
instructionsToReplace[it[1].index] = Instruction(Opcode.NOP)
|
||||
}
|
||||
Opcode.PUSH_VAR_WORD ->
|
||||
if (it[1].value.opcode == Opcode.POP_VAR_WORD) {
|
||||
if (it[0].value.callLabel != it[1].value.callLabel)
|
||||
instructionsToReplace[it[0].index] = Instruction(Opcode.COPY_VAR_WORD, null, it[0].value.callLabel, it[1].value.callLabel)
|
||||
else
|
||||
instructionsToReplace[it[0].index] = Instruction(Opcode.NOP)
|
||||
instructionsToReplace[it[1].index] = Instruction(Opcode.NOP)
|
||||
}
|
||||
Opcode.PUSH_VAR_FLOAT ->
|
||||
if (it[1].value.opcode == Opcode.POP_VAR_FLOAT) {
|
||||
if (it[0].value.callLabel != it[1].value.callLabel)
|
||||
instructionsToReplace[it[0].index] = Instruction(Opcode.COPY_VAR_FLOAT, null, it[0].value.callLabel, it[1].value.callLabel)
|
||||
else
|
||||
instructionsToReplace[it[0].index] = Instruction(Opcode.NOP)
|
||||
instructionsToReplace[it[1].index] = Instruction(Opcode.NOP)
|
||||
}
|
||||
else -> {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (rins in instructionsToReplace) {
|
||||
blk.instructions[rins.key] = rins.value
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun optimizeDataConversionAndUselessDiscards() {
|
||||
// - push value followed by a data type conversion -> push the value in the correct type and remove the conversion
|
||||
// - push something followed by a discard -> remove both
|
||||
val instructionsToReplace = mutableMapOf<Int, Instruction>()
|
||||
|
||||
fun optimizeDiscardAfterPush(index0: Int, index1: Int, ins1: Instruction) {
|
||||
if (ins1.opcode == Opcode.DISCARD_FLOAT || ins1.opcode == Opcode.DISCARD_WORD || ins1.opcode == Opcode.DISCARD_BYTE) {
|
||||
instructionsToReplace[index0] = Instruction(Opcode.NOP)
|
||||
instructionsToReplace[index1] = Instruction(Opcode.NOP)
|
||||
}
|
||||
}
|
||||
|
||||
fun optimizeFloatConversion(index0: Int, index1: Int, ins1: Instruction) {
|
||||
when (ins1.opcode) {
|
||||
Opcode.LSB,
|
||||
Opcode.MSB,
|
||||
Opcode.B2WORD,
|
||||
Opcode.UB2UWORD,
|
||||
Opcode.MSB2WORD,
|
||||
Opcode.B2FLOAT,
|
||||
Opcode.UB2FLOAT,
|
||||
Opcode.UW2FLOAT,
|
||||
Opcode.W2FLOAT -> throw CompilerException("invalid conversion following a float")
|
||||
Opcode.DISCARD_FLOAT -> {
|
||||
instructionsToReplace[index0] = Instruction(Opcode.NOP)
|
||||
instructionsToReplace[index1] = Instruction(Opcode.NOP)
|
||||
}
|
||||
Opcode.DISCARD_BYTE, Opcode.DISCARD_WORD -> throw CompilerException("invalid discard type following a float")
|
||||
else -> throw CompilerException("invalid conversion opcode ${ins1.opcode}")
|
||||
}
|
||||
}
|
||||
|
||||
fun optimizeWordConversion(index0: Int, ins0: Instruction, index1: Int, ins1: Instruction) {
|
||||
when (ins1.opcode) {
|
||||
Opcode.LSB -> {
|
||||
val ins = Instruction(Opcode.PUSH_BYTE, Value(DataType.UBYTE, ins0.arg!!.integerValue() and 255))
|
||||
instructionsToReplace[index0] = ins
|
||||
instructionsToReplace[index1] = Instruction(Opcode.NOP)
|
||||
}
|
||||
Opcode.MSB -> {
|
||||
val ins = Instruction(Opcode.PUSH_BYTE, Value(DataType.UBYTE, ins0.arg!!.integerValue() ushr 8 and 255))
|
||||
instructionsToReplace[index0] = ins
|
||||
instructionsToReplace[index1] = Instruction(Opcode.NOP)
|
||||
}
|
||||
Opcode.B2WORD,
|
||||
Opcode.UB2UWORD,
|
||||
Opcode.MSB2WORD,
|
||||
Opcode.B2FLOAT,
|
||||
Opcode.UB2FLOAT -> throw CompilerException("invalid conversion following a word")
|
||||
Opcode.W2FLOAT, Opcode.UW2FLOAT -> {
|
||||
val ins = Instruction(Opcode.PUSH_FLOAT, Value(DataType.FLOAT, ins0.arg!!.integerValue().toDouble()))
|
||||
instructionsToReplace[index0] = ins
|
||||
instructionsToReplace[index1] = Instruction(Opcode.NOP)
|
||||
}
|
||||
Opcode.DISCARD_WORD -> {
|
||||
instructionsToReplace[index0] = Instruction(Opcode.NOP)
|
||||
instructionsToReplace[index1] = Instruction(Opcode.NOP)
|
||||
}
|
||||
Opcode.DISCARD_BYTE, Opcode.DISCARD_FLOAT -> throw CompilerException("invalid discard type following a byte")
|
||||
else -> throw CompilerException("invalid conversion opcode ${ins1.opcode}")
|
||||
}
|
||||
}
|
||||
|
||||
fun optimizeByteConversion(index0: Int, ins0: Instruction, index1: Int, ins1: Instruction) {
|
||||
when (ins1.opcode) {
|
||||
Opcode.LSB -> instructionsToReplace[index1] = Instruction(Opcode.NOP)
|
||||
Opcode.MSB -> throw CompilerException("msb of a byte")
|
||||
Opcode.UB2UWORD -> {
|
||||
val ins = Instruction(Opcode.PUSH_WORD, Value(DataType.UWORD, ins0.arg!!.integerValue()))
|
||||
instructionsToReplace[index0] = ins
|
||||
instructionsToReplace[index1] = Instruction(Opcode.NOP)
|
||||
}
|
||||
Opcode.B2WORD -> {
|
||||
val ins = Instruction(Opcode.PUSH_WORD, Value(DataType.WORD, ins0.arg!!.integerValue()))
|
||||
instructionsToReplace[index0] = ins
|
||||
instructionsToReplace[index1] = Instruction(Opcode.NOP)
|
||||
}
|
||||
Opcode.MSB2WORD -> {
|
||||
val ins = Instruction(Opcode.PUSH_WORD, Value(DataType.UWORD, 256 * ins0.arg!!.integerValue()))
|
||||
instructionsToReplace[index0] = ins
|
||||
instructionsToReplace[index1] = Instruction(Opcode.NOP)
|
||||
}
|
||||
Opcode.B2FLOAT, Opcode.UB2FLOAT -> {
|
||||
val ins = Instruction(Opcode.PUSH_FLOAT, Value(DataType.FLOAT, ins0.arg!!.integerValue().toDouble()))
|
||||
instructionsToReplace[index0] = ins
|
||||
instructionsToReplace[index1] = Instruction(Opcode.NOP)
|
||||
}
|
||||
Opcode.W2FLOAT, Opcode.UW2FLOAT -> throw CompilerException("invalid conversion following a byte")
|
||||
Opcode.DISCARD_BYTE -> {
|
||||
instructionsToReplace[index0] = Instruction(Opcode.NOP)
|
||||
instructionsToReplace[index1] = Instruction(Opcode.NOP)
|
||||
}
|
||||
Opcode.DISCARD_WORD, Opcode.DISCARD_FLOAT -> throw CompilerException("invalid discard type following a byte")
|
||||
else -> throw CompilerException("invalid conversion opcode ${ins1.opcode}")
|
||||
}
|
||||
}
|
||||
|
||||
for(blk in blocks) {
|
||||
instructionsToReplace.clear()
|
||||
|
||||
val typeConversionOpcodes = setOf(
|
||||
Opcode.LSB,
|
||||
Opcode.MSB,
|
||||
Opcode.B2WORD,
|
||||
Opcode.UB2UWORD,
|
||||
Opcode.MSB2WORD,
|
||||
Opcode.B2FLOAT,
|
||||
Opcode.UB2FLOAT,
|
||||
Opcode.W2FLOAT,
|
||||
Opcode.UW2FLOAT,
|
||||
Opcode.DISCARD_BYTE,
|
||||
Opcode.DISCARD_WORD,
|
||||
Opcode.DISCARD_FLOAT
|
||||
)
|
||||
blk.instructions.asSequence().withIndex().windowed(2).toList().forEach {
|
||||
if (it[1].value.opcode in typeConversionOpcodes) {
|
||||
when (it[0].value.opcode) {
|
||||
Opcode.PUSH_BYTE -> optimizeByteConversion(it[0].index, it[0].value, it[1].index, it[1].value)
|
||||
Opcode.PUSH_WORD -> optimizeWordConversion(it[0].index, it[0].value, it[1].index, it[1].value)
|
||||
Opcode.PUSH_FLOAT -> optimizeFloatConversion(it[0].index, it[1].index, it[1].value)
|
||||
Opcode.PUSH_VAR_FLOAT,
|
||||
Opcode.PUSH_VAR_WORD,
|
||||
Opcode.PUSH_VAR_BYTE,
|
||||
Opcode.PUSH_MEM_B, Opcode.PUSH_MEM_UB,
|
||||
Opcode.PUSH_MEM_W, Opcode.PUSH_MEM_UW,
|
||||
Opcode.PUSH_MEM_FLOAT -> optimizeDiscardAfterPush(it[0].index, it[1].index, it[1].value)
|
||||
else -> {
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (rins in instructionsToReplace) {
|
||||
blk.instructions[rins.key] = rins.value
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun variable(scopedname: String, decl: VarDecl) {
|
||||
val value = when(decl.datatype) {
|
||||
DataType.UBYTE, DataType.BYTE, DataType.UWORD, DataType.WORD, DataType.FLOAT -> Value(decl.datatype, (decl.value as LiteralValue).asNumericValue!!)
|
||||
DataType.STR, DataType.STR_P, DataType.STR_S, DataType.STR_PS -> {
|
||||
val litval = (decl.value as LiteralValue)
|
||||
if(litval.heapId==null)
|
||||
throw CompilerException("string should already be in the heap")
|
||||
Value(decl.datatype, litval.heapId)
|
||||
}
|
||||
DataType.ARRAY_B, DataType.ARRAY_W, DataType.MATRIX_B, DataType.MATRIX_UB,
|
||||
DataType.ARRAY_UB, DataType.ARRAY_UW, DataType.ARRAY_F -> {
|
||||
val litval = (decl.value as LiteralValue)
|
||||
if(litval.heapId==null)
|
||||
throw CompilerException("array/matrix should already be in the heap")
|
||||
Value(decl.datatype, litval.heapId)
|
||||
}
|
||||
}
|
||||
currentBlock.variables[scopedname] = value
|
||||
}
|
||||
|
||||
fun instr(opcode: Opcode, arg: Value? = null, callLabel: String? = null) {
|
||||
currentBlock.instructions.add(Instruction(opcode, arg, callLabel))
|
||||
}
|
||||
|
||||
fun label(labelname: String) {
|
||||
val instr = LabelInstr(labelname)
|
||||
currentBlock.instructions.add(instr)
|
||||
currentBlock.labels[labelname] = instr
|
||||
}
|
||||
|
||||
fun line(position: Position) {
|
||||
currentBlock.instructions.add(Instruction(Opcode.LINE, callLabel = "${position.line} ${position.file}"))
|
||||
}
|
||||
|
||||
fun newBlock(scopedname: String, address: Int?) {
|
||||
currentBlock = ProgramBlock(scopedname, address)
|
||||
blocks.add(currentBlock)
|
||||
}
|
||||
|
||||
fun writeCode(out: PrintStream, embeddedLabels: Boolean=true) {
|
||||
out.println("; stackVM program code for '$name'")
|
||||
out.println("%memory")
|
||||
if(memory.isNotEmpty()) {
|
||||
TODO("print out initial memory load")
|
||||
}
|
||||
out.println("%end_memory")
|
||||
out.println("%heap")
|
||||
heap.allStrings().forEach {
|
||||
out.println("${it.index} ${it.value.type.toString().toLowerCase()} \"${it.value.str}\"")
|
||||
}
|
||||
heap.allArrays().forEach {
|
||||
out.println("${it.index} ${it.value.type.toString().toLowerCase()} ${it.value.array!!.toList()}")
|
||||
}
|
||||
heap.allDoubleArrays().forEach {
|
||||
out.println("${it.index} ${it.value.type.toString().toLowerCase()} ${it.value.doubleArray!!.toList()}")
|
||||
}
|
||||
out.println("%end_heap")
|
||||
for(blk in blocks) {
|
||||
out.println("\n%block ${blk.scopedname} ${blk.address?.toString(16) ?: ""}")
|
||||
|
||||
out.println("%variables")
|
||||
for(variable in blk.variables) {
|
||||
val valuestr = variable.value.toString()
|
||||
out.println("${variable.key} ${variable.value.type.toString().toLowerCase()} $valuestr")
|
||||
}
|
||||
out.println("%end_variables")
|
||||
out.println("%instructions")
|
||||
val labels = blk.labels.entries.associateBy({it.value}) {it.key}
|
||||
for(instr in blk.instructions) {
|
||||
if(!embeddedLabels) {
|
||||
val label = labels[instr]
|
||||
if (label != null)
|
||||
out.println("$label:")
|
||||
} else {
|
||||
out.println(instr)
|
||||
}
|
||||
}
|
||||
out.println("%end_instructions")
|
||||
|
||||
out.println("%end_block")
|
||||
}
|
||||
}
|
||||
}
|
@ -4,25 +4,33 @@ import prog8.ast.DataType
|
||||
import prog8.compiler.HeapValues
|
||||
import prog8.compiler.unescape
|
||||
import java.io.File
|
||||
import java.io.PrintStream
|
||||
import java.util.*
|
||||
import java.util.regex.Pattern
|
||||
|
||||
class Program (val name: String,
|
||||
prog: MutableList<Instruction>,
|
||||
val program: MutableList<Instruction>,
|
||||
val variables: Map<String, Value>,
|
||||
val labels: Map<String, Instruction>,
|
||||
val variables: Map<String, Map<String, Value>>,
|
||||
val memory: Map<Int, List<Value>>,
|
||||
val heap: HeapValues)
|
||||
{
|
||||
init {
|
||||
// add end of program marker and some sentinel instructions, to correctly connect all others
|
||||
program.add(LabelInstr("____program_end"))
|
||||
program.add(Instruction(Opcode.TERMINATE))
|
||||
program.add(Instruction(Opcode.NOP))
|
||||
connect()
|
||||
}
|
||||
|
||||
companion object {
|
||||
fun load(filename: String): Program {
|
||||
val lines = File(filename).readLines().withIndex().iterator()
|
||||
val memory = mutableMapOf<Int, List<Value>>()
|
||||
val vars = mutableMapOf<String, MutableMap<String, Value>>()
|
||||
var instructions = mutableListOf<Instruction>()
|
||||
var labels = mapOf<String, Instruction>()
|
||||
val heap = HeapValues()
|
||||
val program = mutableListOf<Instruction>()
|
||||
val variables = mutableMapOf<String, Value>()
|
||||
val labels = mutableMapOf<String, Instruction>()
|
||||
|
||||
while(lines.hasNext()) {
|
||||
val (lineNr, line) = lines.next()
|
||||
if(line.startsWith(';') || line.isEmpty())
|
||||
@ -31,16 +39,33 @@ class Program (val name: String,
|
||||
loadMemory(lines, memory)
|
||||
else if(line=="%heap")
|
||||
loadHeap(lines, heap)
|
||||
else if(line=="%variables")
|
||||
loadVars(lines, vars)
|
||||
else if(line=="%instructions") {
|
||||
val (insResult, labelResult) = loadInstructions(lines, heap)
|
||||
instructions = insResult
|
||||
labels = labelResult
|
||||
}
|
||||
else if(line.startsWith("%block "))
|
||||
loadBlock(lines, heap, program, variables, labels)
|
||||
else throw VmExecutionException("syntax error at line ${lineNr + 1}")
|
||||
}
|
||||
return Program(filename, instructions, labels, vars, memory, heap)
|
||||
return Program(filename, program, variables, labels, memory, heap)
|
||||
}
|
||||
|
||||
private fun loadBlock(lines: Iterator<IndexedValue<String>>,
|
||||
heap: HeapValues,
|
||||
program: MutableList<Instruction>,
|
||||
variables: MutableMap<String, Value>,
|
||||
labels: MutableMap<String, Instruction>)
|
||||
{
|
||||
while(true) {
|
||||
val (lineNr, line) = lines.next()
|
||||
if(line.isEmpty())
|
||||
continue
|
||||
else if(line=="%end_block")
|
||||
return
|
||||
else if(line=="%variables")
|
||||
loadVars(lines, variables)
|
||||
else if(line=="%instructions") {
|
||||
val (blockInstructions, blockLabels) = loadInstructions(lines, heap)
|
||||
program.addAll(blockInstructions)
|
||||
labels.putAll(blockLabels)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun loadHeap(lines: Iterator<IndexedValue<String>>, heap: HeapValues) {
|
||||
@ -156,7 +181,7 @@ class Program (val name: String,
|
||||
}
|
||||
|
||||
private fun loadVars(lines: Iterator<IndexedValue<String>>,
|
||||
vars: MutableMap<String, MutableMap<String, Value>>): Map<String, Map<String, Value>> {
|
||||
vars: MutableMap<String, Value>): Map<String, Value> {
|
||||
val splitpattern = Pattern.compile("\\s+")
|
||||
while(true) {
|
||||
val (lineNr, line) = lines.next()
|
||||
@ -197,10 +222,7 @@ class Program (val name: String,
|
||||
}
|
||||
}
|
||||
}
|
||||
val blockname = name.substringBefore('.')
|
||||
val blockvars = vars[blockname] ?: mutableMapOf()
|
||||
vars[blockname] = blockvars
|
||||
blockvars[name] = value
|
||||
vars[name] = value
|
||||
}
|
||||
}
|
||||
|
||||
@ -229,15 +251,6 @@ class Program (val name: String,
|
||||
}
|
||||
}
|
||||
|
||||
val program: List<Instruction>
|
||||
|
||||
init {
|
||||
prog.add(LabelInstr("____program_end"))
|
||||
prog.add(Instruction(Opcode.TERMINATE))
|
||||
prog.add(Instruction(Opcode.NOP))
|
||||
program = prog
|
||||
connect()
|
||||
}
|
||||
|
||||
private fun connect() {
|
||||
val it1 = program.iterator()
|
||||
@ -283,43 +296,4 @@ class Program (val name: String,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun print(out: PrintStream, embeddedLabels: Boolean=true) {
|
||||
out.println("; stackVM program code for '$name'")
|
||||
out.println("%memory")
|
||||
if(memory.isNotEmpty()) {
|
||||
TODO("print out initial memory load")
|
||||
}
|
||||
out.println("%end_memory")
|
||||
out.println("%heap")
|
||||
heap.allStrings().forEach {
|
||||
out.println("${it.index} ${it.value.type.toString().toLowerCase()} \"${it.value.str}\"")
|
||||
}
|
||||
heap.allArrays().forEach {
|
||||
out.println("${it.index} ${it.value.type.toString().toLowerCase()} ${it.value.array!!.toList()}")
|
||||
}
|
||||
heap.allDoubleArrays().forEach {
|
||||
out.println("${it.index} ${it.value.type.toString().toLowerCase()} ${it.value.doubleArray!!.toList()}")
|
||||
}
|
||||
out.println("%end_heap")
|
||||
out.println("%variables")
|
||||
// just flatten all block vars into one global list for now...
|
||||
for(variable in variables.flatMap { e->e.value.entries}) {
|
||||
val valuestr = variable.value.toString()
|
||||
out.println("${variable.key} ${variable.value.type.toString().toLowerCase()} $valuestr")
|
||||
}
|
||||
out.println("%end_variables")
|
||||
out.println("%instructions")
|
||||
val labels = this.labels.entries.associateBy({it.value}) {it.key}
|
||||
for(instr in this.program) {
|
||||
if(!embeddedLabels) {
|
||||
val label = labels[instr]
|
||||
if (label != null)
|
||||
out.println("$label:")
|
||||
} else {
|
||||
out.println(instr)
|
||||
}
|
||||
}
|
||||
out.println("%end_instructions")
|
||||
}
|
||||
}
|
@ -384,9 +384,7 @@ class StackVm(private var traceOutputFile: String?) {
|
||||
this.heap = program.heap
|
||||
this.canvas = canvas
|
||||
canvas?.requestFocusInWindow()
|
||||
variables.clear()
|
||||
for(variable in program.variables.flatMap { e->e.value.entries })
|
||||
variables[variable.key] = variable.value
|
||||
variables = program.variables.toMutableMap()
|
||||
|
||||
if("A" in variables || "X" in variables || "Y" in variables ||
|
||||
"XY" in variables || "AX" in variables ||"AY" in variables)
|
||||
|
@ -50,18 +50,8 @@ class TestStackVmOpcodes {
|
||||
vars: Map<String, Value>?=null,
|
||||
labels: Map<String, Instruction>?=null,
|
||||
mem: Map<Int, List<Value>>?=null) : Program {
|
||||
|
||||
val blockvars = mutableMapOf<String, MutableMap<String, Value>>()
|
||||
if(vars!=null) {
|
||||
for (blockvar in vars) {
|
||||
val blockname = blockvar.key.substringBefore('.')
|
||||
val variables = blockvars[blockname] ?: mutableMapOf()
|
||||
blockvars[blockname] = variables
|
||||
variables[blockvar.key] = blockvar.value
|
||||
}
|
||||
}
|
||||
val heap = HeapValues()
|
||||
return Program("test", ins, labels ?: mapOf(), blockvars, mem ?: mapOf(), heap)
|
||||
return Program("test", ins, vars ?: mapOf(), labels ?: mapOf(), mem ?: mapOf(), heap)
|
||||
}
|
||||
|
||||
@Test
|
||||
@ -252,7 +242,6 @@ class TestStackVmOpcodes {
|
||||
assertEquals(42.25, vm.mem.getFloat(0x4000))
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
fun testPopVar() {
|
||||
val ins = mutableListOf(
|
||||
|
@ -25,15 +25,28 @@ class TestCompiler {
|
||||
assertEquals("10", 10.toHex())
|
||||
assertEquals("10", 10.99.toHex())
|
||||
assertEquals("15", 15.toHex())
|
||||
assertEquals("$10", 16.toHex())
|
||||
assertEquals("\$10", 16.toHex())
|
||||
assertEquals("\$ff", 255.toHex())
|
||||
assertEquals("$0100", 256.toHex())
|
||||
assertEquals("$4e5c", 20060.toHex())
|
||||
assertEquals("\$0100", 256.toHex())
|
||||
assertEquals("\$4e5c", 20060.toHex())
|
||||
assertEquals("\$c382", 50050.toHex())
|
||||
assertEquals("\$ffff", 65535.toHex())
|
||||
assertEquals("\$ffff", 65535L.toHex())
|
||||
assertEquals("0", 0.toHex())
|
||||
assertEquals("-1", (-1).toHex())
|
||||
assertEquals("-1", (-1.234).toHex())
|
||||
assertEquals("-10", (-10).toHex())
|
||||
assertEquals("-10", (-10.99).toHex())
|
||||
assertEquals("-15", (-15).toHex())
|
||||
assertEquals("-\$10", (-16).toHex())
|
||||
assertEquals("-\$ff", (-255).toHex())
|
||||
assertEquals("-\$0100", (-256).toHex())
|
||||
assertEquals("-\$4e5c", (-20060).toHex())
|
||||
assertEquals("-\$c382", (-50050).toHex())
|
||||
assertEquals("-\$ffff", (-65535).toHex())
|
||||
assertEquals("-\$ffff", (-65535L).toHex())
|
||||
assertFailsWith<CompilerException> { 65536.toHex() }
|
||||
assertFailsWith<CompilerException> { (-1).toHex() }
|
||||
assertFailsWith<CompilerException> { (-1.99).toHex() }
|
||||
assertFailsWith<CompilerException> { 65536L.toHex() }
|
||||
}
|
||||
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user