mirror of
https://github.com/irmen/prog8.git
synced 2024-12-26 14:29:35 +00:00
fix scoping of variables in when statement
This commit is contained in:
parent
3581017489
commit
9e6408244f
@ -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
|
||||
|
@ -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)
|
||||
|
@ -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")
|
||||
}
|
||||
|
@ -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)
|
||||
|
@ -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
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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)
|
||||
|
@ -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,34 +495,42 @@ class IntermediateProgram(val name: String, var loadAddress: Int, val heap: Heap
|
||||
}
|
||||
}
|
||||
out.println("%end_heap")
|
||||
for(blk in blocks) {
|
||||
out.println("\n%block ${blk.name} ${blk.address?.toString(16) ?: ""}")
|
||||
}
|
||||
|
||||
out.println("%variables")
|
||||
for(variable in blk.variables) {
|
||||
val valuestr = variable.value.toString()
|
||||
out.println("${variable.key} ${variable.value.type.name.toLowerCase()} $valuestr")
|
||||
}
|
||||
out.println("%end_variables")
|
||||
out.println("%memorypointers")
|
||||
for(iconst in blk.memoryPointers) {
|
||||
out.println("${iconst.key} ${iconst.value.second.name.toLowerCase()} uw:${iconst.value.first.toString(16)}")
|
||||
}
|
||||
out.println("%end_memorypointers")
|
||||
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")
|
||||
private fun writeBlock(out: PrintStream, blk: ProgramBlock, embeddedLabels: Boolean) {
|
||||
out.println("\n%block ${blk.name} ${blk.address?.toString(16) ?: ""}")
|
||||
|
||||
out.println("%end_block")
|
||||
out.println("%variables")
|
||||
for (variable in blk.variables) {
|
||||
val valuestr = variable.value.toString()
|
||||
out.println("${variable.key} ${variable.value.type.name.toLowerCase()} $valuestr")
|
||||
}
|
||||
out.println("%end_variables")
|
||||
out.println("%memorypointers")
|
||||
for (iconst in blk.memoryPointers) {
|
||||
out.println("${iconst.key} ${iconst.value.second.name.toLowerCase()} uw:${iconst.value.first.toString(16)}")
|
||||
}
|
||||
out.println("%end_memorypointers")
|
||||
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")
|
||||
}
|
||||
|
||||
private fun writeMemory(out: PrintStream) {
|
||||
out.println("%memory")
|
||||
if (memory.isNotEmpty())
|
||||
TODO("add support for writing/reading initial memory values")
|
||||
out.println("%end_memory")
|
||||
}
|
||||
}
|
||||
|
@ -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()}"
|
||||
|
@ -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)
|
||||
|
@ -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)
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user