diff --git a/compiler/compile.sh b/compiler/compile.sh index da9dd45de..875f330bd 100755 --- a/compiler/compile.sh +++ b/compiler/compile.sh @@ -2,6 +2,7 @@ PROG8_LIBDIR=../prog8lib PROG8CLASSPATH=out/production/compiler -LIBJARS=/opt/irmen/idea-2018/plugins/Kotlin/lib/kotlin-stdlib.jar:/opt/irmen/idea-2018/plugins/Kotlin/lib/kotlin-reflect.jar:antlr/lib/antlr-runtime-4.7.1.jar +KOTLINPATH=${HOME}/.IntelliJIdea2018.2/config/plugins/Kotlin +LIBJARS=${KOTLINPATH}/lib/kotlin-stdlib.jar:${KOTLINPATH}/lib/kotlin-reflect.jar:antlr/lib/antlr-runtime-4.7.1.jar -java -Dprog8.libdir=${PROG8_LIBDIR} -cp ${PROG8CLASSPATH}:${LIBJARS} prog8.MainKt $* +java -Dprog8.libdir=${PROG8_LIBDIR} -cp ${PROG8CLASSPATH}:${LIBJARS} prog8.CompilerMainKt $* diff --git a/compiler/src/compile.sh b/compiler/src/compile.sh old mode 100644 new mode 100755 index 76bc5c5fd..bb4a7a0e3 --- a/compiler/src/compile.sh +++ b/compiler/src/compile.sh @@ -1,5 +1,8 @@ -#!/bin/sh +#!/usr/bin/env bash mkdir -p compiled_java -javac -d compiled_java -cp ../antlr/lib/antlr-runtime-4.7.1.jar $(find . -name \*.java) +javac -verbose -d compiled_java -cp ../antlr/lib/antlr-runtime-4.7.1.jar $(find . -name \*.java) jar cf parser.jar -C compiled_java prog8 -kotlinc -d prog8_kotlin.jar -include-runtime -cp ../antlr/lib/antlr-runtime-4.7.1.jar:parser.jar prog8 + +KOTLINC="bash ${HOME}/.IntelliJIdea2018.2/config/plugins/Kotlin/kotlinc/bin/kotlinc" + +${KOTLINC} -verbose -include-runtime -d prog8_kotlin.jar -cp ../antlr/lib/antlr-runtime-4.7.1.jar:parser.jar prog8 diff --git a/compiler/src/prog8/Main.kt b/compiler/src/prog8/CompilerMain.kt similarity index 100% rename from compiler/src/prog8/Main.kt rename to compiler/src/prog8/CompilerMain.kt diff --git a/compiler/src/prog8/StackVmMain.kt b/compiler/src/prog8/StackVmMain.kt new file mode 100644 index 000000000..e18a740d0 --- /dev/null +++ b/compiler/src/prog8/StackVmMain.kt @@ -0,0 +1,41 @@ +package prog8 + +import prog8.stackvm.* +import java.awt.EventQueue +import javax.swing.Timer +import kotlin.system.exitProcess + +fun main(args: Array) { + println("\nProg8 StackVM by Irmen de Jong (irmen@razorvine.net)") + // @todo software license string + // println("This software is licensed under the GNU GPL 3.0, see https://www.gnu.org/licenses/gpl.html\n") + println("**** This is a prerelease version. Please do not distribute! ****\n") + + if(args.size != 1) { + System.err.println("requires one argument: name of stackvm sourcecode file") + exitProcess(1) + } + + val program = Program.load(args.first()) + val vm = StackVm(traceOutputFile = null) + val dialog = ScreenDialog() + vm.load(program, dialog.canvas) + EventQueue.invokeLater { + dialog.pack() + dialog.isVisible = true + dialog.start() + + val programTimer = Timer(10) { a -> + try { + vm.step() + } catch(bp: VmBreakpointException) { + println("Breakpoint: execution halted. Press enter to resume.") + readLine() + } catch (tx: VmTerminationException) { + println("Execution halted: ${tx.message}") + (a.source as Timer).stop() + } + } + programTimer.start() + } +} diff --git a/compiler/src/prog8/optimizing/SimplifyExpressions.kt b/compiler/src/prog8/optimizing/SimplifyExpressions.kt index 7bae6db70..469fce799 100644 --- a/compiler/src/prog8/optimizing/SimplifyExpressions.kt +++ b/compiler/src/prog8/optimizing/SimplifyExpressions.kt @@ -4,17 +4,54 @@ import prog8.ast.IAstProcessor import prog8.ast.INameScope /* - todo eliminate useless terms: - *0 -> constant 0 - X*1, X/1, X//1 -> just X + todo simplify expression terms: + X*0 -> 0 + X*1 -> X + X*2 -> X << 1 + X*3 -> X + (X << 1) + X*4 -> X << 2 + X*5 -> X + (X << 2) + X*6 -> (X<<1) + (X << 2) + X*7 -> X + (X<<1) + (X << 2) + X*8 -> X << 3 + X*9 -> X + (X<<3) + X*10 -> (X<<1) + (X<<3) + + X/1, X//1, X**1 -> just X + X/2, X//2 -> X >> 1 (if X is byte or word) + X/4, X//4 -> X >> 2 (if X is byte or word) + X/8, X//8 -> X >> 3 (if X is byte or word) + X/16, X//16 -> X >> 4 (if X is byte or word) + X/32, X//32 -> X >> 5 (if X is byte or word) + X/64, X//64 -> X >> 6 (if X is byte or word) + X/128, X//128 -> X >> 7 (if X is byte or word) + X / (n>=256) -> 0 (if x is byte) X >> 8 (if X is word) + X // (n>=256) -> 0 (if x is byte) X >> 8 (if X is word) + + X+X -> X << 1 + X << n << m -> X << (n+m) + + 1**X -> 1 + 0**X -> 0 X*-1 -> unary prefix -X X**0 -> 1 X**1 -> X + X**2 -> X*X + X**3 -> X*X*X + X**0.5 -> sqrt(X) X**-1 -> 1.0/X + X**-2 -> 1.0/X/X + X**-3 -> 1.0/X/X/X X << 0 -> X X | 0 -> X x & 0 -> 0 X ^ 0 -> X + X*Y - X -> X*(Y-1) + -X + A -> A - X + -X - A -> -(X+A) + X % 1 -> constant 0 (if X is byte/word) + X % 2 -> X and 255 (byte) X and 65535 (word) + todo expression optimization: remove redundant builtin function calls todo expression optimization: reduce expression nesting / flattening of parenthesis diff --git a/compiler/src/prog8/optimizing/StatementOptimizer.kt b/compiler/src/prog8/optimizing/StatementOptimizer.kt index eb27e7361..ecadaa23b 100644 --- a/compiler/src/prog8/optimizing/StatementOptimizer.kt +++ b/compiler/src/prog8/optimizing/StatementOptimizer.kt @@ -16,6 +16,8 @@ import prog8.functions.BuiltinFunctionsWithoutSideEffects todo analyse for unreachable code and remove that (f.i. code after goto or return that has no label so can never be jumped to) todo merge sequence of assignments into one (as long as the value is a constant and the target not a MEMORY type!) todo report more always true/always false conditions + todo inline subroutines that are only called once + todo inline subroutines that are "sufficiently small" */ class StatementOptimizer(private val globalNamespace: INameScope) : IAstProcessor { diff --git a/compiler/src/prog8/stackvm/StackVm.kt b/compiler/src/prog8/stackvm/StackVm.kt index 0cadb37a4..78bc7ea31 100644 --- a/compiler/src/prog8/stackvm/StackVm.kt +++ b/compiler/src/prog8/stackvm/StackVm.kt @@ -3,14 +3,11 @@ package prog8.stackvm import prog8.ast.DataType import prog8.compiler.target.c64.Petscii import prog8.compiler.target.c64.Mflpt5 -import java.awt.EventQueue import java.io.File import java.io.PrintStream import java.util.* import java.util.regex.Pattern -import javax.swing.Timer import kotlin.math.* -import kotlin.system.exitProcess enum class Opcode { @@ -237,15 +234,11 @@ class Value(val type: DataType, numericvalue: Number?, val stringvalue: String?= init { when(type) { DataType.BYTE -> { - byteval = numericvalue!!.toShort() - if(byteval!! <0 || byteval!! > 255) - throw VmExecutionException("byte value overflow: $byteval") + byteval = (numericvalue!!.toInt() and 255).toShort() // byte wrap around 0..255 asBooleanValue = byteval != (0.toShort()) } DataType.WORD -> { - wordval = numericvalue!!.toInt() - if(wordval!! <0 || wordval!! > 65535) - throw VmExecutionException("word value overflow: $wordval") + wordval = numericvalue!!.toInt() and 65535 // word wrap around 0..65535 asBooleanValue = wordval != 0 } DataType.FLOAT -> { @@ -362,17 +355,17 @@ class Value(val type: DataType, numericvalue: Number?, val stringvalue: String?= val v1 = numericValue() val v2 = other.numericValue() val result = v1.toDouble().pow(v2.toDouble()) - return Value(type, result) // @todo datatype? + return Value(type, result) // @todo datatype of pow is now always float, maybe allow byte/word results as well } fun shl(): Value { val v = integerValue() - return Value(type, v.shl(1)) + return Value(type, v shl 1) } fun shr(): Value { val v = integerValue() - return Value(type, v.ushr(1)) + return Value(type, v ushr 1) } fun rol(carry: Boolean): Pair { @@ -1493,39 +1486,3 @@ class StackVm(val traceOutputFile: String?) { return ins.next } } - - -fun main(args: Array) { - println("\nProg8 StackVM by Irmen de Jong (irmen@razorvine.net)") - // @todo software license string - // println("This software is licensed under the GNU GPL 3.0, see https://www.gnu.org/licenses/gpl.html\n") - println("**** This is a prerelease version. Please do not distribute! ****\n") - - if(args.size != 1) { - System.err.println("requires one argument: name of stackvm sourcecode file") - exitProcess(1) - } - - val program = Program.load(args.first()) - val vm = StackVm(traceOutputFile = null) - val dialog = ScreenDialog() - vm.load(program, dialog.canvas) - EventQueue.invokeLater { - dialog.pack() - dialog.isVisible = true - dialog.start() - - val programTimer = Timer(10) { a -> - try { - vm.step() - } catch(bp: VmBreakpointException) { - println("Breakpoint: execution halted. Press enter to resume.") - readLine() - } catch (tx: VmTerminationException) { - println("Execution halted: ${tx.message}") - (a.source as Timer).stop() - } - } - programTimer.start() - } -} diff --git a/compiler/stackvm.sh b/compiler/stackvm.sh index efc8ba4cf..67b15fee4 100755 --- a/compiler/stackvm.sh +++ b/compiler/stackvm.sh @@ -1,6 +1,7 @@ #!/usr/bin/env sh PROG8CLASSPATH=out/production/compiler -LIBJARS=/opt/irmen/idea-2018/plugins/Kotlin/lib/kotlin-stdlib.jar:/opt/irmen/idea-2018/plugins/Kotlin/lib/kotlin-reflect.jar:antlr/lib/antlr-runtime-4.7.1.jar +KOTLINPATH=${HOME}/.IntelliJIdea2018.2/config/plugins/Kotlin +LIBJARS=${KOTLINPATH}/lib/kotlin-stdlib.jar:${KOTLINPATH}/lib/kotlin-reflect.jar:antlr/lib/antlr-runtime-4.7.1.jar -java -cp ${PROG8CLASSPATH}:${LIBJARS} prog8.stackvm.StackVmKt $* +java -cp ${PROG8CLASSPATH}:${LIBJARS} prog8.StackVmMainKt $* diff --git a/compiler/test/StackVMOpcodes.kt b/compiler/test/StackVMOpcodes.kt index c8078947d..d5151e09c 100644 --- a/compiler/test/StackVMOpcodes.kt +++ b/compiler/test/StackVMOpcodes.kt @@ -597,17 +597,16 @@ class TestStackVmOpcodes { Instruction(Opcode.NEG) ) vm.load(makeProg(ins2), null) - assertFailsWith { - vm.step(2) - } + vm.step(2) + assertEquals(Value(DataType.WORD, 64302), vm.evalstack.pop()) + val ins3 = mutableListOf( Instruction(Opcode.PUSH, Value(DataType.BYTE, 12)), Instruction(Opcode.NEG) ) vm.load(makeProg(ins3), null) - assertFailsWith { - vm.step(2) - } + vm.step(2) + assertEquals(Value(DataType.BYTE, 244), vm.evalstack.pop()) } @Test