This commit is contained in:
Irmen de Jong 2018-09-21 22:43:29 +02:00
parent 2f48406aad
commit 0137478ad4
9 changed files with 105 additions and 64 deletions

View File

@ -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 $*

9
compiler/src/compile.sh Normal file → Executable file
View File

@ -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

View File

@ -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<String>) {
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()
}
}

View File

@ -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

View File

@ -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 {

View File

@ -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<Value, Boolean> {
@ -1493,39 +1486,3 @@ class StackVm(val traceOutputFile: String?) {
return ins.next
}
}
fun main(args: Array<String>) {
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()
}
}

View File

@ -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 $*

View File

@ -597,17 +597,16 @@ class TestStackVmOpcodes {
Instruction(Opcode.NEG)
)
vm.load(makeProg(ins2), null)
assertFailsWith<VmExecutionException> {
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<VmExecutionException> {
vm.step(2)
}
assertEquals(Value(DataType.BYTE, 244), vm.evalstack.pop())
}
@Test