fix scoping of variables in when statement

This commit is contained in:
Irmen de Jong 2019-07-09 19:44:59 +02:00
parent 3581017489
commit 9e6408244f
10 changed files with 106 additions and 69 deletions

View File

@ -80,6 +80,7 @@ interface INameScope {
val subscopes = mutableMapOf<String, INameScope>()
for(stmt in statements) {
when(stmt) {
// NOTE: if other nodes are introduced that are a scope of contain subscopes, they must be added here!
is INameScope -> subscopes[stmt.name] = stmt
is ForLoop -> subscopes[stmt.body.name] = stmt.body
is RepeatLoop -> subscopes[stmt.body.name] = stmt.body
@ -94,6 +95,9 @@ interface INameScope {
if(stmt.elsepart.containsCodeOrVars())
subscopes[stmt.elsepart.name] = stmt.elsepart
}
is WhenStatement -> {
stmt.choices.forEach { subscopes[it.statements.name] = it.statements }
}
}
}
return subscopes

View File

@ -54,6 +54,7 @@ internal fun Program.checkIdentifiers() {
// add any anonymous variables for heap values that are used,
// and replace an iterable literalvalue by identifierref to new local variable
// TODO: this is't doing anything anymore?
for (variable in checker.anonymousVariablesFromHeap.values) {
val scope = variable.first.definingScope()
scope.statements.add(variable.second)

View File

@ -1,6 +1,7 @@
package prog8.ast.expressions
import prog8.ast.*
import prog8.ast.antlr.escape
import prog8.ast.base.*
import prog8.ast.processing.IAstModifyingVisitor
import prog8.ast.processing.IAstVisitor
@ -424,7 +425,7 @@ open class LiteralValue(val type: DataType,
DataType.UWORD -> "uword:$wordvalue"
DataType.WORD -> "word:$wordvalue"
DataType.FLOAT -> "float:$floatvalue"
in StringDatatypes -> "str:$strvalue"
in StringDatatypes -> "str:'${escape(strvalue?:"")}'"
in ArrayDatatypes -> "array:$arrayvalue"
else -> throw FatalAstException("weird datatype")
}

View File

@ -199,6 +199,7 @@ internal class AstIdentifiersChecker(private val namespace: INameScope) : IAstMo
if(literalValue.heapId!=null && literalValue.parent !is VarDecl) {
// a literal value that's not declared as a variable, which refers to something on the heap.
// we need to introduce an auto-generated variable for this to be able to refer to the value!
// (note: ususally, this has been taken care of already when the var was created)
val variable = VarDecl(VarDeclType.VAR, literalValue.type, false, null, "$autoHeapValuePrefix${literalValue.heapId}", literalValue,
isArray = false, autoGenerated = false, position = literalValue.position)
anonymousVariablesFromHeap[variable.name] = Pair(literalValue, variable)

View File

@ -110,7 +110,6 @@ internal class VarInitValueAndAddressOfCreator(private val namespace: INameScope
val variable = VarDecl(VarDeclType.VAR, strvalue.type, false, null, autoVarName, strvalue,
isArray = false, autoGenerated = false, position = strvalue.position)
addVarDecl(strvalue.definingScope(), variable)
// println("MADE ANONVAR $variable") // XXX
}
}
}

View File

@ -2106,13 +2106,11 @@ internal class Compiler(private val program: Program) {
previousValue = choiceVal
if (conditionDt in ByteDatatypes) {
prog.instr(Opcode.DUP_B)
prog.instr(Opcode.PUSH_BYTE, RuntimeValue(conditionDt!!, subtract))
prog.instr(opcodeCompare(conditionDt))
prog.instr(opcodeCompare(conditionDt!!), RuntimeValue(conditionDt, subtract))
}
else {
prog.instr(Opcode.DUP_W)
prog.instr(Opcode.PUSH_WORD, RuntimeValue(conditionDt!!, subtract))
prog.instr(opcodeCompare(conditionDt))
prog.instr(opcodeCompare(conditionDt!!), RuntimeValue(conditionDt, subtract))
}
val choiceLabel = makeLabel(whenstmt, "choice_$choiceVal")
choiceLabels.add(choiceLabel)

View File

@ -459,10 +459,14 @@ class IntermediateProgram(val name: String, var loadAddress: Int, val heap: Heap
fun writeCode(out: PrintStream, embeddedLabels: Boolean=true) {
out.println("; stackVM program code for '$name'")
out.println("%memory")
if(memory.isNotEmpty())
TODO("add support for writing/reading initial memory values")
out.println("%end_memory")
writeMemory(out)
writeHeap(out)
for(blk in blocks) {
writeBlock(out, blk, embeddedLabels)
}
}
private fun writeHeap(out: PrintStream) {
out.println("%heap")
heap.allEntries().forEach {
out.print("${it.key} ${it.value.type.name.toLowerCase()} ")
@ -491,7 +495,9 @@ class IntermediateProgram(val name: String, var loadAddress: Int, val heap: Heap
}
}
out.println("%end_heap")
for(blk in blocks) {
}
private fun writeBlock(out: PrintStream, blk: ProgramBlock, embeddedLabels: Boolean) {
out.println("\n%block ${blk.name} ${blk.address?.toString(16) ?: ""}")
out.println("%variables")
@ -520,5 +526,11 @@ class IntermediateProgram(val name: String, var loadAddress: Int, val heap: Heap
out.println("%end_block")
}
private fun writeMemory(out: PrintStream) {
out.println("%memory")
if (memory.isNotEmpty())
TODO("add support for writing/reading initial memory values")
out.println("%end_memory")
}
}

View File

@ -61,13 +61,33 @@ internal fun simpleInstr2Asm(ins: Instruction, block: IntermediateProgram.Progra
Opcode.RRESTOREX -> " sta ${C64Zeropage.SCRATCH_REG} | pla | tax | lda ${C64Zeropage.SCRATCH_REG}"
Opcode.DISCARD_BYTE -> " inx"
Opcode.DISCARD_WORD -> " inx"
Opcode.DISCARD_FLOAT -> " inx | inx | inx"
Opcode.DUP_B -> {
" dex | lda ${(ESTACK_LO+1).toHex()},x | sta ${ESTACK_LO.toHex()},x"
}
Opcode.DUP_W -> {
" dex | lda ${(ESTACK_LO+1).toHex()},x | sta ${ESTACK_LO.toHex()},x | lda ${(ESTACK_HI+1).toHex()},x | sta ${ESTACK_HI.toHex()},x "
}
Opcode.DISCARD_FLOAT -> " inx | inx | inx"
Opcode.CMP_B, Opcode.CMP_UB -> {
" inx | lda ${ESTACK_LO.toHex()},x | inx | cmp ${ESTACK_LO.toHex()},x "
}
Opcode.CMP_W, Opcode.CMP_UW -> {
"""
inx
inx
lda ${(ESTACK_HI-1).toHex()},x
cmp ${(ESTACK_HI).toHex()},x
bne +
lda ${(ESTACK_LO-1).toHex()},x
cmp ${(ESTACK_LO).toHex()},x
bne +
lda #0
+
"""
}
Opcode.INLINE_ASSEMBLY -> "@inline@" + (ins.callLabel2 ?: "") // All of the inline assembly is stored in the calllabel2 property. the '@inline@' is a special marker to accept it.
Opcode.INCLUDE_FILE -> {
val offset = if(ins.arg==null) "" else ", ${ins.arg.integerValue()}"

View File

@ -20,7 +20,7 @@ import java.util.*
import kotlin.math.*
enum class Syscall(val callNr: Short) {
internal enum class Syscall(val callNr: Short) {
VM_WRITE_MEMCHR(10), // print a single char from the memory address popped from stack
VM_WRITE_MEMSTR(11), // print a 0-terminated petscii string from the memory address popped from stack
VM_WRITE_NUM(12), // pop from the evaluation stack and print it as a number
@ -107,10 +107,9 @@ enum class Syscall(val callNr: Short) {
SYSASM_c64flt_print_f(214),
}
internal val syscallNames = enumValues<Syscall>().map { it.name }.toSet()
val syscallNames = enumValues<Syscall>().map { it.name }.toSet()
val syscallsForStackVm = setOf(
internal val syscallsForStackVm = setOf(
Syscall.VM_WRITE_MEMCHR,
Syscall.VM_WRITE_MEMSTR,
Syscall.VM_WRITE_NUM,
@ -123,13 +122,13 @@ val syscallsForStackVm = setOf(
Syscall.VM_GFX_LINE
)
class VmExecutionException(msg: String?) : Exception(msg)
internal class VmExecutionException(msg: String?) : Exception(msg)
class VmTerminationException(msg: String?) : Exception(msg)
internal class VmTerminationException(msg: String?) : Exception(msg)
class VmBreakpointException : Exception("breakpoint")
internal class VmBreakpointException : Exception("breakpoint")
class MyStack<T> : Stack<T>() {
internal class MyStack<T> : Stack<T>() {
fun peek(amount: Int) : List<T> {
return this.toList().subList(max(0, size-amount), size)
}
@ -141,7 +140,6 @@ class MyStack<T> : Stack<T>() {
}
}
class StackVm(private var traceOutputFile: String?) {
val mem = Memory(::memread, ::memwrite)
var P_carry: Boolean = false
@ -156,9 +154,9 @@ class StackVm(private var traceOutputFile: String?) {
private set
var memoryPointers = mutableMapOf<String, Pair<Int, DataType>>() // all named pointers
private set
var evalstack = MyStack<RuntimeValue>()
internal var evalstack = MyStack<RuntimeValue>()
private set
var callstack = MyStack<Int>()
internal var callstack = MyStack<Int>()
private set
private var program = listOf<Instruction>()
private var labels = emptyMap<String, Int>()
@ -204,7 +202,7 @@ class StackVm(private var traceOutputFile: String?) {
throw VmExecutionException("program contains variable(s) for the reserved registers A/X/Y")
// define the 'registers'
variables["A"] = RuntimeValue(DataType.UBYTE, 0)
variables["X"] = RuntimeValue(DataType.UBYTE, 0)
variables["X"] = RuntimeValue(DataType.UBYTE, 255)
variables["Y"] = RuntimeValue(DataType.UBYTE, 0)
initMemory(program.memory)

View File

@ -1,33 +1,34 @@
%import c64utils
%zeropage basicsafe
%option enable_floats
~ main {
sub start() {
A=10
A=100
Y=22
uword uw = A*Y
uword uw = (A as uword)*Y
str teststring = "hello"
c64scr.print(&teststring)
c64scr.print("stack (255?): ")
c64scr.print_ub(X)
c64.CHROUT('\n')
c64scr.print_uw(uw)
c64scr.print("?: ")
when uw {
12345 -> {
A=44
}
12346 -> {
A=44
}
12347 -> {
A=44
}
else -> {
A=0
}
12345 -> c64scr.print("12345")
12346 -> c64scr.print("12346")
2200 -> c64scr.print("2200")
12347 -> c64scr.print("12347")
else -> c64scr.print("else")
}
c64.CHROUT('\n')
when 4+A+Y {
A=30
Y=2
c64scr.print_ub(A+Y)
c64scr.print("?: ")
when A+Y {
10 -> {
c64scr.print("ten")
}
@ -48,9 +49,11 @@
}
else -> {
c64scr.print("!??!\n")
c64scr.print("!??!!??!\n")
c64scr.print("!??!!??!!?!\n")
}
}
c64.CHROUT('\n')
c64scr.print("stack (255?): ")
c64scr.print_ub(X)
}
}