kotlin runtime update

This commit is contained in:
Song Minjae
2017-04-29 22:53:32 +09:00
parent 9508249533
commit 9a7885fc80
6 changed files with 631 additions and 403 deletions

View File

@@ -0,0 +1,228 @@
import java.io.InputStream
import java.io.OutputStream
/**
* Just to make things slow down
*
* This version of Brainfuck fills memory with sanitised input program, and initialises
* memory pointer to be just right after your input program. This brings three major improvements:
*
* 1. Possibility of Self-modifying code
* 2. Fucks your brain even more
* 3. Forces you to enhance your calm
*
* Also note that program counter and memory pointer will wrap around when commands are executed,
* but not when program is being loaded (will throw OutOfMemoryException).
*
* If memory at Program Counter is equal to 0xFF, it is interpreted as termination. (0xFF is NOT a
* valid opcode for input program, however)
*
* Created by minjaesong on 17-04-29.
*/
class BFVM(
val memSize: Int = 65536,
val stdout: OutputStream = System.out,
val stdin: InputStream = System.`in`
) {
private val ZERO = 0.toByte()
private val INP = '>'.toByte()
private val DEP = '<'.toByte()
private val INC = '+'.toByte()
private val DEC = '-'.toByte()
private val PRN = '.'.toByte()
private val RDI = ','.toByte()
private val JPZ = '['.toByte()
private val JPN = ']'.toByte()
private val CYA = 0xFF.toByte()
private val bfOpcodes = hashSetOf<Byte>(43,44,45,46,60,62,91,93)
private val instSet = hashMapOf<Byte, () -> Unit>(
Pair(INP, { INP() }),
Pair(DEP, { DEP() }),
Pair(INC, { INC() }),
Pair(DEC, { DEC() }),
Pair(PRN, { PRN() }),
Pair(RDI, { RDI() }),
Pair(JPZ, { JPZ() }),
Pair(JPN, { JPN() })
)
private var r1: Byte = ZERO // Register One (Data register)
private var r2 = 0 // Register Two (Scratchpad); theoretically I can use R1 but it limits bracket depth to 254
private var mp = 0 // Memory Pointer
private var pc = 0 // Program Counter
private var ir = 0 // Instruction Register; does lookahead ahd lookbehind
private val mem = ByteArray(memSize)
/*
Input program is loaded into the memory from index zero.
Interrupts are hard-coded, 'cause why not?
Code Mnemo. Desc.
----|------|-----
INP > Increment pointer
DEP < Decrement pointer
INC + Increment memory
DEC - Decrement memory
PRN . Print as text
RDI , Read from input
JPZ [ Jump past to matching ] when mem is zero
JPN ] Jump back to matching [ when mem is non-zero
[ Internal operations ]
CYA 0xFF Marks end of the input program
*/
// NOTE: INC_PC is implied
private fun INP() {
INC_MP()
}
private fun DEP() {
DEC_MP()
}
private fun INC() {
r1 = mem[mp]
r1++
mem[mp] = r1
}
private fun DEC() {
r1 = mem[mp]
r1--
mem[mp] = r1
}
private fun PRN() {
stdout.write(mem[mp].toInt())
}
private fun RDI() {
r1 = stdin.read().toByte()
mem[mp] = r1
}
private fun JPZ() {
if (mem[mp] == ZERO) {
// lookahead
ir = pc
r2 = 0
while (r2 != -1) {
INC_IR()
if (JPZ == mem[ir]) {
r2++
}
else if (JPN == mem[ir]) {
r2--
}
}
pc = ir
}
}
private fun JPN() {
if (mem[mp] != ZERO) {
// lookbehind
ir = pc
r2 = 0
while (r2 != -1) {
DEC_IR()
if (JPN == mem[ir]) {
r2++
}
else if (JPZ == mem[ir]) {
r2--
}
}
pc = ir
}
}
// END OF NOTE (INC_PC is implied)
fun execute() {
while (mem[pc] != CYA) {
//println("pc = $pc, mp = $mp, inst = ${mem[pc].toChar()}, mem = ${mem[mp]}")
instSet[mem[pc]]?.invoke() // fetch-decode-execute in one line
INC_PC()
}
}
fun loadProgram(program: String) {
val program = program.toByteArray(charset = Charsets.US_ASCII)
pc = 0 // FOR NOW it's PC for input program
mp = 0 // where to dump input bytes
while (pc < program.size) {
if (pc >= memSize - 1) {
throw OutOfMemoryError("Virtual Machine Out of Memory")
}
r1 = program[pc]
if (r1 in bfOpcodes) {
mem[mp] = r1
INC_MP()
}
INC_PC()
}
mem[program.size] = CYA
mp = (program.size + 1) mod memSize
pc = 0
ir = 0
}
private fun INC_PC() { pc = (pc + 1) mod memSize }
private fun INC_IR() { ir = (ir + 1) mod memSize }
private fun DEC_IR() { ir = (ir - 1) mod memSize }
private fun INC_MP() { mp = (mp + 1) mod memSize }
private fun DEC_MP() { mp = (mp - 1) mod memSize }
private infix fun Int.mod(other: Int) = Math.floorMod(this, other)
}
val vm = BFVM()
val factorials = """
github (dot) com/saulpw/brainfuck/blob/master/tests/facto (dot) b
++++++++++>>>+>>>>+>+<[[+++++[>++++
++++<-]>.<++++++[>--------<-]+<<]<<
[<<]<.>>>>+<[->[<+>-[<+>-[<+>-[<+>-
[<+>-[<+>-[<+>-[<+>-[<+>-[<[-]>-+>[
<->-]<[->>>[>>]<<[->[>>+<<-]>+<<<<]
<]>[-]+>+<<]]]]]]]]]]<[>+<-]+>>]<<[
<<]>>[->>[>>]>>[-<<[<<]<<[<<]>[>[>>
]>>[>>]>>[>>]>+>+<<<<[<<]<<[<<]<<[<
<]>-]>[>>]>>[>>]>>[>>]>[<<<[<<]<<[<
<]<<[<<]>+>[>>]>>[>>]>>[>>]>-]<<<[<
<]>[>[>>]>+>>+<<<<<[<<]>-]>[>>]>[<<
<[<<]>+>[>>]>-]>>[<[<<+>+>-]<[>>>+<
<<-]<[>>+<<-]>>>-]<[-]>>+[>[>>>>]>[
>>>>]>[-]+>+<[<<<<]>-]>[>>>>]>[>>>>
]>->-[<<<+>>+>-]<[>+<-]>[[<<+>+>-]<
[<->-[<->-[<->-[<->-[<->-[<->-[<->-
[<->-[<->-[<-<---------->>[-]>>>>[-
]+>+<<<<<]]]]]]]]]]<[>>+<<-]>>]<+<+
<[>>>+<<<-]<<[<<<<]<<<<<[<<]+>>]>>>
>>[>>>>]+>[>>>>]<<<<[-<<<<]>>>>>[<<
<<]<<<<<[<<]<<[<<]+>>]>>[>>]>>>>>[-
>>>>]<<[<<<<]>>>>[>>>>]<<<<<<<<[>>>
>[<<+>>->[<<+>>-]>]<<<<[<<]<<]<<<<<
[->[-]>>>>>>>>[<<+>>->[<<+>>-]>]<<<
<[<<]<<<<<<<]>>>>>>>>>[<<<<<<<+>>>>
>>>->[<<<<<<<+>>>>>>>-]>]<<<<<<<<<]
"""
vm.loadProgram(factorials)
vm.execute()

Binary file not shown.

Binary file not shown.

Binary file not shown.

File diff suppressed because it is too large Load Diff

Binary file not shown.

Before

Width:  |  Height:  |  Size: 150 KiB

After

Width:  |  Height:  |  Size: 164 KiB