mirror of
https://github.com/irmen/prog8.git
synced 2024-11-29 17:50: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>()
|
val subscopes = mutableMapOf<String, INameScope>()
|
||||||
for(stmt in statements) {
|
for(stmt in statements) {
|
||||||
when(stmt) {
|
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 INameScope -> subscopes[stmt.name] = stmt
|
||||||
is ForLoop -> subscopes[stmt.body.name] = stmt.body
|
is ForLoop -> subscopes[stmt.body.name] = stmt.body
|
||||||
is RepeatLoop -> subscopes[stmt.body.name] = stmt.body
|
is RepeatLoop -> subscopes[stmt.body.name] = stmt.body
|
||||||
@ -94,6 +95,9 @@ interface INameScope {
|
|||||||
if(stmt.elsepart.containsCodeOrVars())
|
if(stmt.elsepart.containsCodeOrVars())
|
||||||
subscopes[stmt.elsepart.name] = stmt.elsepart
|
subscopes[stmt.elsepart.name] = stmt.elsepart
|
||||||
}
|
}
|
||||||
|
is WhenStatement -> {
|
||||||
|
stmt.choices.forEach { subscopes[it.statements.name] = it.statements }
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return subscopes
|
return subscopes
|
||||||
|
@ -54,6 +54,7 @@ internal fun Program.checkIdentifiers() {
|
|||||||
|
|
||||||
// add any anonymous variables for heap values that are used,
|
// add any anonymous variables for heap values that are used,
|
||||||
// and replace an iterable literalvalue by identifierref to new local variable
|
// and replace an iterable literalvalue by identifierref to new local variable
|
||||||
|
// TODO: this is't doing anything anymore?
|
||||||
for (variable in checker.anonymousVariablesFromHeap.values) {
|
for (variable in checker.anonymousVariablesFromHeap.values) {
|
||||||
val scope = variable.first.definingScope()
|
val scope = variable.first.definingScope()
|
||||||
scope.statements.add(variable.second)
|
scope.statements.add(variable.second)
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
package prog8.ast.expressions
|
package prog8.ast.expressions
|
||||||
|
|
||||||
import prog8.ast.*
|
import prog8.ast.*
|
||||||
|
import prog8.ast.antlr.escape
|
||||||
import prog8.ast.base.*
|
import prog8.ast.base.*
|
||||||
import prog8.ast.processing.IAstModifyingVisitor
|
import prog8.ast.processing.IAstModifyingVisitor
|
||||||
import prog8.ast.processing.IAstVisitor
|
import prog8.ast.processing.IAstVisitor
|
||||||
@ -424,7 +425,7 @@ open class LiteralValue(val type: DataType,
|
|||||||
DataType.UWORD -> "uword:$wordvalue"
|
DataType.UWORD -> "uword:$wordvalue"
|
||||||
DataType.WORD -> "word:$wordvalue"
|
DataType.WORD -> "word:$wordvalue"
|
||||||
DataType.FLOAT -> "float:$floatvalue"
|
DataType.FLOAT -> "float:$floatvalue"
|
||||||
in StringDatatypes -> "str:$strvalue"
|
in StringDatatypes -> "str:'${escape(strvalue?:"")}'"
|
||||||
in ArrayDatatypes -> "array:$arrayvalue"
|
in ArrayDatatypes -> "array:$arrayvalue"
|
||||||
else -> throw FatalAstException("weird datatype")
|
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) {
|
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.
|
// 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!
|
// 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,
|
val variable = VarDecl(VarDeclType.VAR, literalValue.type, false, null, "$autoHeapValuePrefix${literalValue.heapId}", literalValue,
|
||||||
isArray = false, autoGenerated = false, position = literalValue.position)
|
isArray = false, autoGenerated = false, position = literalValue.position)
|
||||||
anonymousVariablesFromHeap[variable.name] = Pair(literalValue, variable)
|
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,
|
val variable = VarDecl(VarDeclType.VAR, strvalue.type, false, null, autoVarName, strvalue,
|
||||||
isArray = false, autoGenerated = false, position = strvalue.position)
|
isArray = false, autoGenerated = false, position = strvalue.position)
|
||||||
addVarDecl(strvalue.definingScope(), variable)
|
addVarDecl(strvalue.definingScope(), variable)
|
||||||
// println("MADE ANONVAR $variable") // XXX
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -2106,13 +2106,11 @@ internal class Compiler(private val program: Program) {
|
|||||||
previousValue = choiceVal
|
previousValue = choiceVal
|
||||||
if (conditionDt in ByteDatatypes) {
|
if (conditionDt in ByteDatatypes) {
|
||||||
prog.instr(Opcode.DUP_B)
|
prog.instr(Opcode.DUP_B)
|
||||||
prog.instr(Opcode.PUSH_BYTE, RuntimeValue(conditionDt!!, subtract))
|
prog.instr(opcodeCompare(conditionDt!!), RuntimeValue(conditionDt, subtract))
|
||||||
prog.instr(opcodeCompare(conditionDt))
|
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
prog.instr(Opcode.DUP_W)
|
prog.instr(Opcode.DUP_W)
|
||||||
prog.instr(Opcode.PUSH_WORD, RuntimeValue(conditionDt!!, subtract))
|
prog.instr(opcodeCompare(conditionDt!!), RuntimeValue(conditionDt, subtract))
|
||||||
prog.instr(opcodeCompare(conditionDt))
|
|
||||||
}
|
}
|
||||||
val choiceLabel = makeLabel(whenstmt, "choice_$choiceVal")
|
val choiceLabel = makeLabel(whenstmt, "choice_$choiceVal")
|
||||||
choiceLabels.add(choiceLabel)
|
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) {
|
fun writeCode(out: PrintStream, embeddedLabels: Boolean=true) {
|
||||||
out.println("; stackVM program code for '$name'")
|
out.println("; stackVM program code for '$name'")
|
||||||
out.println("%memory")
|
writeMemory(out)
|
||||||
if(memory.isNotEmpty())
|
writeHeap(out)
|
||||||
TODO("add support for writing/reading initial memory values")
|
for(blk in blocks) {
|
||||||
out.println("%end_memory")
|
writeBlock(out, blk, embeddedLabels)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun writeHeap(out: PrintStream) {
|
||||||
out.println("%heap")
|
out.println("%heap")
|
||||||
heap.allEntries().forEach {
|
heap.allEntries().forEach {
|
||||||
out.print("${it.key} ${it.value.type.name.toLowerCase()} ")
|
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")
|
out.println("%end_heap")
|
||||||
for(blk in blocks) {
|
}
|
||||||
out.println("\n%block ${blk.name} ${blk.address?.toString(16) ?: ""}")
|
|
||||||
|
|
||||||
out.println("%variables")
|
private fun writeBlock(out: PrintStream, blk: ProgramBlock, embeddedLabels: Boolean) {
|
||||||
for(variable in blk.variables) {
|
out.println("\n%block ${blk.name} ${blk.address?.toString(16) ?: ""}")
|
||||||
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")
|
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.RRESTOREX -> " sta ${C64Zeropage.SCRATCH_REG} | pla | tax | lda ${C64Zeropage.SCRATCH_REG}"
|
||||||
Opcode.DISCARD_BYTE -> " inx"
|
Opcode.DISCARD_BYTE -> " inx"
|
||||||
Opcode.DISCARD_WORD -> " inx"
|
Opcode.DISCARD_WORD -> " inx"
|
||||||
|
Opcode.DISCARD_FLOAT -> " inx | inx | inx"
|
||||||
Opcode.DUP_B -> {
|
Opcode.DUP_B -> {
|
||||||
" dex | lda ${(ESTACK_LO+1).toHex()},x | sta ${ESTACK_LO.toHex()},x"
|
" dex | lda ${(ESTACK_LO+1).toHex()},x | sta ${ESTACK_LO.toHex()},x"
|
||||||
}
|
}
|
||||||
Opcode.DUP_W -> {
|
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 "
|
" 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.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 -> {
|
Opcode.INCLUDE_FILE -> {
|
||||||
val offset = if(ins.arg==null) "" else ", ${ins.arg.integerValue()}"
|
val offset = if(ins.arg==null) "" else ", ${ins.arg.integerValue()}"
|
||||||
|
@ -20,7 +20,7 @@ import java.util.*
|
|||||||
import kotlin.math.*
|
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_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_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
|
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),
|
SYSASM_c64flt_print_f(214),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
internal val syscallNames = enumValues<Syscall>().map { it.name }.toSet()
|
||||||
|
|
||||||
val syscallNames = enumValues<Syscall>().map { it.name }.toSet()
|
internal val syscallsForStackVm = setOf(
|
||||||
|
|
||||||
val syscallsForStackVm = setOf(
|
|
||||||
Syscall.VM_WRITE_MEMCHR,
|
Syscall.VM_WRITE_MEMCHR,
|
||||||
Syscall.VM_WRITE_MEMSTR,
|
Syscall.VM_WRITE_MEMSTR,
|
||||||
Syscall.VM_WRITE_NUM,
|
Syscall.VM_WRITE_NUM,
|
||||||
@ -123,13 +122,13 @@ val syscallsForStackVm = setOf(
|
|||||||
Syscall.VM_GFX_LINE
|
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> {
|
fun peek(amount: Int) : List<T> {
|
||||||
return this.toList().subList(max(0, size-amount), size)
|
return this.toList().subList(max(0, size-amount), size)
|
||||||
}
|
}
|
||||||
@ -141,7 +140,6 @@ class MyStack<T> : Stack<T>() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
class StackVm(private var traceOutputFile: String?) {
|
class StackVm(private var traceOutputFile: String?) {
|
||||||
val mem = Memory(::memread, ::memwrite)
|
val mem = Memory(::memread, ::memwrite)
|
||||||
var P_carry: Boolean = false
|
var P_carry: Boolean = false
|
||||||
@ -156,9 +154,9 @@ class StackVm(private var traceOutputFile: String?) {
|
|||||||
private set
|
private set
|
||||||
var memoryPointers = mutableMapOf<String, Pair<Int, DataType>>() // all named pointers
|
var memoryPointers = mutableMapOf<String, Pair<Int, DataType>>() // all named pointers
|
||||||
private set
|
private set
|
||||||
var evalstack = MyStack<RuntimeValue>()
|
internal var evalstack = MyStack<RuntimeValue>()
|
||||||
private set
|
private set
|
||||||
var callstack = MyStack<Int>()
|
internal var callstack = MyStack<Int>()
|
||||||
private set
|
private set
|
||||||
private var program = listOf<Instruction>()
|
private var program = listOf<Instruction>()
|
||||||
private var labels = emptyMap<String, Int>()
|
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")
|
throw VmExecutionException("program contains variable(s) for the reserved registers A/X/Y")
|
||||||
// define the 'registers'
|
// define the 'registers'
|
||||||
variables["A"] = RuntimeValue(DataType.UBYTE, 0)
|
variables["A"] = RuntimeValue(DataType.UBYTE, 0)
|
||||||
variables["X"] = RuntimeValue(DataType.UBYTE, 0)
|
variables["X"] = RuntimeValue(DataType.UBYTE, 255)
|
||||||
variables["Y"] = RuntimeValue(DataType.UBYTE, 0)
|
variables["Y"] = RuntimeValue(DataType.UBYTE, 0)
|
||||||
|
|
||||||
initMemory(program.memory)
|
initMemory(program.memory)
|
||||||
|
@ -1,33 +1,34 @@
|
|||||||
%import c64utils
|
%import c64utils
|
||||||
%zeropage basicsafe
|
%zeropage basicsafe
|
||||||
%option enable_floats
|
|
||||||
|
|
||||||
~ main {
|
~ main {
|
||||||
|
|
||||||
sub start() {
|
sub start() {
|
||||||
A=10
|
A=100
|
||||||
Y=22
|
Y=22
|
||||||
uword uw = A*Y
|
uword uw = (A as uword)*Y
|
||||||
|
|
||||||
str teststring = "hello"
|
c64scr.print("stack (255?): ")
|
||||||
c64scr.print(&teststring)
|
c64scr.print_ub(X)
|
||||||
|
c64.CHROUT('\n')
|
||||||
|
|
||||||
|
c64scr.print_uw(uw)
|
||||||
|
c64scr.print("?: ")
|
||||||
when uw {
|
when uw {
|
||||||
12345 -> {
|
12345 -> c64scr.print("12345")
|
||||||
A=44
|
12346 -> c64scr.print("12346")
|
||||||
}
|
2200 -> c64scr.print("2200")
|
||||||
12346 -> {
|
12347 -> c64scr.print("12347")
|
||||||
A=44
|
else -> c64scr.print("else")
|
||||||
}
|
|
||||||
12347 -> {
|
|
||||||
A=44
|
|
||||||
}
|
|
||||||
else -> {
|
|
||||||
A=0
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
c64.CHROUT('\n')
|
||||||
|
|
||||||
when 4+A+Y {
|
A=30
|
||||||
|
Y=2
|
||||||
|
|
||||||
|
c64scr.print_ub(A+Y)
|
||||||
|
c64scr.print("?: ")
|
||||||
|
when A+Y {
|
||||||
10 -> {
|
10 -> {
|
||||||
c64scr.print("ten")
|
c64scr.print("ten")
|
||||||
}
|
}
|
||||||
@ -48,9 +49,11 @@
|
|||||||
}
|
}
|
||||||
else -> {
|
else -> {
|
||||||
c64scr.print("!??!\n")
|
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