1
0
mirror of https://github.com/irmen/prog8.git synced 2025-02-13 03:30:28 +00:00

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

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

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

@ -3,7 +3,7 @@ package prog8.astvm
import prog8.ast.* import prog8.ast.*
import prog8.compiler.HeapValues 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 { override fun process(decl: VarDecl): IStatement {
if(decl.type==VarDeclType.VAR) { if(decl.type==VarDeclType.VAR) {

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

@ -1,20 +1,51 @@
%import c64utils
%zeropage basicsafe %zeropage basicsafe
~ main { ~ main {
ubyte[256] sieve
ubyte candidate_prime = 2 ; is increased in the loop
sub start() { sub start() {
memset(sieve, 256, false) ; clear the sieve, to reset starting situation on subsequent runs
uword multiple ; calculate primes
c64scr.print("prime numbers up to 255:\n\n")
while multiple < 5 { ubyte amount=0
multiple += 2 while true {
c64scr.print_uw(multiple) ; TODO ubyte prime = find_next_prime()
c64.CHROUT('\n') ; TODO if prime==0
break
c64scr.print_ub(prime)
c64scr.print(", ")
amount++
} }
c64.CHROUT('\n')
c64scr.print("done!\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
}
} }