From eb25b4c800154e3eda1ad522082770eb4e9e3cf1 Mon Sep 17 00:00:00 2001 From: Irmen de Jong Date: Mon, 24 Jun 2019 04:09:30 +0200 Subject: [PATCH] fix some initial value datatypes and type casting in assignments --- compiler/src/prog8/ast/StmtReorderer.kt | 1 + compiler/src/prog8/astvm/AstVm.kt | 172 +++++++++++------- ...blesInitializer.kt => VariablesCreator.kt} | 2 +- examples/primes.p8 | 4 +- examples/test.p8 | 49 ++++- 5 files changed, 152 insertions(+), 76 deletions(-) rename compiler/src/prog8/astvm/{VariablesInitializer.kt => VariablesCreator.kt} (91%) diff --git a/compiler/src/prog8/ast/StmtReorderer.kt b/compiler/src/prog8/ast/StmtReorderer.kt index d1bb37761..673843efd 100644 --- a/compiler/src/prog8/ast/StmtReorderer.kt +++ b/compiler/src/prog8/ast/StmtReorderer.kt @@ -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() diff --git a/compiler/src/prog8/astvm/AstVm.kt b/compiler/src/prog8/astvm/AstVm.kt index f50e25d8d..a35759b26 100644 --- a/compiler/src/prog8/astvm/AstVm.kt +++ b/compiler/src/prog8/astvm/AstVm.kt @@ -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()) { + for (s in b.statements.filterIsInstance()) { + 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): Exception() + internal fun executeSubroutine(sub: INameScope, arguments: List): List { 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 -> { diff --git a/compiler/src/prog8/astvm/VariablesInitializer.kt b/compiler/src/prog8/astvm/VariablesCreator.kt similarity index 91% rename from compiler/src/prog8/astvm/VariablesInitializer.kt rename to compiler/src/prog8/astvm/VariablesCreator.kt index 34b27d317..5986fc122 100644 --- a/compiler/src/prog8/astvm/VariablesInitializer.kt +++ b/compiler/src/prog8/astvm/VariablesCreator.kt @@ -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) { diff --git a/examples/primes.p8 b/examples/primes.p8 index e894ebc6e..b2b548c9a 100644 --- a/examples/primes.p8 +++ b/examples/primes.p8 @@ -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 } diff --git a/examples/test.p8 b/examples/test.p8 index 506e12781..b2b548c9a 100644 --- a/examples/test.p8 +++ b/examples/test.p8 @@ -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 + } }