fix some initial value datatypes and type casting in assignments

This commit is contained in:
Irmen de Jong 2019-06-24 04:09:30 +02:00
parent a079e44b02
commit eb25b4c800
5 changed files with 152 additions and 76 deletions

View File

@ -107,6 +107,7 @@ private class StatementReorderer(private val program: Program): IAstProcessor {
sortConstantAssignments(block.statements)
// create subroutine that initializes the block's variables (if any)
val varInits = block.statements.withIndex().filter { it.value is VariableInitializationAssignment }
if(varInits.isNotEmpty()) {
val statements = varInits.map{it.value}.toMutableList()

View File

@ -65,10 +65,30 @@ class AstVm(val program: Program) {
fun run() {
try {
val init = VariablesInitializer(runtimeVariables, program.heap)
val init = VariablesCreator(runtimeVariables, program.heap)
init.process(program)
// initialize all global variables
for(m in program.modules) {
for (b in m.statements.filterIsInstance<Block>()) {
for (s in b.statements.filterIsInstance<Subroutine>()) {
if (s.name == initvarsSubName) {
try {
executeSubroutine(s, emptyList())
} catch (x: LoopControlReturn) {
// regular return
}
}
}
}
}
val entrypoint = program.entrypoint() ?: throw VmTerminationException("no valid entrypoint found")
executeSubroutine(entrypoint, emptyList())
try {
executeSubroutine(entrypoint, emptyList())
} catch (x: LoopControlReturn) {
// regular return
}
println("PROGRAM EXITED!")
dialog.title = "PROGRAM EXITED"
} catch(bp: VmBreakpointException) {
@ -84,18 +104,24 @@ class AstVm(val program: Program) {
private val runtimeVariables = RuntimeVariables()
class LoopControlBreak: Exception()
class LoopControlContinue: Exception()
class LoopControlReturn(val returnvalues: List<RuntimeValue>): Exception()
internal fun executeSubroutine(sub: INameScope, arguments: List<RuntimeValue>): List<RuntimeValue> {
if (sub.statements.isEmpty())
throw VmTerminationException("scope contains no statements: $sub")
if(sub !is AnonymousScope)
throw VmTerminationException("scope contains no statements: $sub")
if(sub is Subroutine) {
assert(!sub.isAsmSubroutine)
// TODO process arguments if it's a subroutine
}
for (s in sub.statements) {
if(s is Return) {
return s.values.map { evaluate(it, program, runtimeVariables, ::executeSubroutine) }
try {
for (s in sub.statements) {
executeStatement(sub, s)
}
executeStatement(sub, s)
} catch (r: LoopControlReturn) {
return r.returnvalues
}
if(sub !is AnonymousScope)
throw VmTerminationException("instruction pointer overflow, is a return missing? $sub")
@ -103,6 +129,7 @@ class AstVm(val program: Program) {
}
private fun executeStatement(sub: INameScope, stmt: IStatement) {
Thread.sleep(10)
when (stmt) {
is NopStatement, is Label, is Subroutine -> {
// do nothing, skip this instruction
@ -140,62 +167,56 @@ class AstVm(val program: Program) {
is BuiltinFunctionStatementPlaceholder -> {
TODO("$stmt")
}
is Return -> {
throw VmExecutionException("return statement should have been handled by the subroutine loop")
}
is Continue -> {
TODO("$stmt")
}
is Break -> {
TODO("$stmt")
}
is Return -> throw LoopControlReturn(stmt.values.map { evaluate(it, program, runtimeVariables, ::executeSubroutine) })
is Continue -> throw LoopControlContinue()
is Break -> throw LoopControlBreak()
is Assignment -> {
if(stmt.aug_op==null) {
val target = stmt.singleTarget
if(target!=null) {
when {
target.identifier!=null -> {
val ident = stmt.definingScope().lookup(target.identifier.nameInSource, stmt) as VarDecl
val value = evaluate(stmt.value, program, runtimeVariables, ::executeSubroutine)
val identScope = ident.definingScope()
runtimeVariables.set(identScope, ident.name, value)
}
target.memoryAddress!=null -> {
TODO("$stmt")
}
target.arrayindexed!=null -> {
val array = evaluate(target.arrayindexed.identifier, program, runtimeVariables, ::executeSubroutine)
val index = evaluate(target.arrayindexed.arrayspec.index, program, runtimeVariables, ::executeSubroutine)
val value = evaluate(stmt.value, program, runtimeVariables, ::executeSubroutine)
when(array.type) {
DataType.ARRAY_UB -> {
if(value.type!=DataType.UBYTE)
throw VmExecutionException("new value is of different datatype ${value.type} for $array")
}
DataType.ARRAY_B -> {
if(value.type!=DataType.BYTE)
throw VmExecutionException("new value is of different datatype ${value.type} for $array")
}
DataType.ARRAY_UW -> {
if(value.type!=DataType.UWORD)
throw VmExecutionException("new value is of different datatype ${value.type} for $array")
}
DataType.ARRAY_W -> {
if(value.type!=DataType.WORD)
throw VmExecutionException("new value is of different datatype ${value.type} for $array")
}
DataType.ARRAY_F -> {
if(value.type!=DataType.FLOAT)
throw VmExecutionException("new value is of different datatype ${value.type} for $array")
}
else -> throw VmExecutionException("strange array type ${array.type}")
if(stmt.aug_op!=null)
throw VmExecutionException("augmented assignment should have been converted into regular one $stmt")
val target = stmt.singleTarget
if(target!=null) {
when {
target.identifier!=null -> {
val ident = stmt.definingScope().lookup(target.identifier.nameInSource, stmt) as VarDecl
val value = evaluate(stmt.value, program, runtimeVariables, ::executeSubroutine)
val identScope = ident.definingScope()
runtimeVariables.set(identScope, ident.name, value)
}
target.memoryAddress!=null -> {
TODO("$stmt")
}
target.arrayindexed!=null -> {
val array = evaluate(target.arrayindexed.identifier, program, runtimeVariables, ::executeSubroutine)
val index = evaluate(target.arrayindexed.arrayspec.index, program, runtimeVariables, ::executeSubroutine)
val value = evaluate(stmt.value, program, runtimeVariables, ::executeSubroutine)
when(array.type) {
DataType.ARRAY_UB -> {
if(value.type!=DataType.UBYTE)
throw VmExecutionException("new value is of different datatype ${value.type} for $array")
}
array.array!![index.integerValue()] = value.numericValue()
DataType.ARRAY_B -> {
if(value.type!=DataType.BYTE)
throw VmExecutionException("new value is of different datatype ${value.type} for $array")
}
DataType.ARRAY_UW -> {
if(value.type!=DataType.UWORD)
throw VmExecutionException("new value is of different datatype ${value.type} for $array")
}
DataType.ARRAY_W -> {
if(value.type!=DataType.WORD)
throw VmExecutionException("new value is of different datatype ${value.type} for $array")
}
DataType.ARRAY_F -> {
if(value.type!=DataType.FLOAT)
throw VmExecutionException("new value is of different datatype ${value.type} for $array")
}
else -> throw VmExecutionException("strange array type ${array.type}")
}
array.array!![index.integerValue()] = value.numericValue()
}
}
else TODO("$stmt")
} else TODO("$stmt")
}
else TODO("$stmt")
}
is PostIncrDecr -> {
when {
@ -228,27 +249,50 @@ class AstVm(val program: Program) {
throw VmExecutionException("anonymous scopes should have been flattened")
}
is IfStatement -> {
TODO("$stmt")
val condition = evaluate(stmt.condition, program, runtimeVariables, ::executeSubroutine)
if(condition.asBooleanRuntimeValue)
executeSubroutine(stmt.truepart, emptyList())
else
executeSubroutine(stmt.elsepart, emptyList())
}
is BranchStatement -> {
TODO("$stmt")
}
is ForLoop -> {
TODO("$stmt")
// try {
//
// } catch(b: LoopControlBreak) {
// break
// } catch(c: LoopControlContinue){
// continue
// }
}
is WhileLoop -> {
var condition = evaluate(stmt.condition, program, runtimeVariables, ::executeSubroutine)
while(condition.asBooleanRuntimeValue) {
println("STILL IN WHILE LOOP ${stmt.position}")
executeSubroutine(stmt.body, emptyList())
condition = evaluate(stmt.condition, program, runtimeVariables, ::executeSubroutine)
while (condition.asBooleanRuntimeValue) {
try {
println("STILL IN WHILE LOOP ${stmt.position}")
executeSubroutine(stmt.body, emptyList())
condition = evaluate(stmt.condition, program, runtimeVariables, ::executeSubroutine)
} catch(b: LoopControlBreak) {
break
} catch(c: LoopControlContinue){
continue
}
}
println(">>>>WHILE LOOP EXITED")
}
is RepeatLoop -> {
do {
val condition = evaluate(stmt.untilCondition, program, runtimeVariables, ::executeSubroutine)
executeSubroutine(stmt.body, emptyList())
try {
executeSubroutine(stmt.body, emptyList())
} catch(b: LoopControlBreak) {
break
} catch(c: LoopControlContinue){
continue
}
} while(!condition.asBooleanRuntimeValue)
}
else -> {

View File

@ -3,7 +3,7 @@ package prog8.astvm
import prog8.ast.*
import prog8.compiler.HeapValues
class VariablesInitializer(private val runtimeVariables: RuntimeVariables, private val heap: HeapValues) : IAstProcessor {
class VariablesCreator(private val runtimeVariables: RuntimeVariables, private val heap: HeapValues) : IAstProcessor {
override fun process(decl: VarDecl): IStatement {
if(decl.type==VarDeclType.VAR) {

View File

@ -43,8 +43,8 @@
while multiple < len(sieve) {
sieve[lsb(multiple)] = true
multiple += candidate_prime
c64scr.print_uw(multiple) ; TODO
c64.CHROUT('\n') ; TODO
; c64scr.print_uw(multiple) ; TODO
; c4.CHROUT('\n') ; TODO
}
return candidate_prime
}

View File

@ -1,20 +1,51 @@
%import c64utils
%zeropage basicsafe
~ main {
ubyte[256] sieve
ubyte candidate_prime = 2 ; is increased in the loop
sub start() {
memset(sieve, 256, false) ; clear the sieve, to reset starting situation on subsequent runs
uword multiple
while multiple < 5 {
multiple += 2
c64scr.print_uw(multiple) ; TODO
c64.CHROUT('\n') ; TODO
; calculate primes
c64scr.print("prime numbers up to 255:\n\n")
ubyte amount=0
while true {
ubyte prime = find_next_prime()
if prime==0
break
c64scr.print_ub(prime)
c64scr.print(", ")
amount++
}
c64scr.print("done!\n")
c64.CHROUT('\n')
c64scr.print("number of primes (expected 54): ")
c64scr.print_ub(amount)
c64.CHROUT('\n')
}
sub find_next_prime() -> ubyte {
while sieve[candidate_prime] {
candidate_prime++
if candidate_prime==0
return 0 ; we wrapped; no more primes available in the sieve
}
; found next one, mark the multiples and return it.
sieve[candidate_prime] = true
uword multiple = candidate_prime
while multiple < len(sieve) {
sieve[lsb(multiple)] = true
multiple += candidate_prime
; c64scr.print_uw(multiple) ; TODO
; c4.CHROUT('\n') ; TODO
}
return candidate_prime
}
}