Last active
April 11, 2019 06:41
-
-
Save parrot-studio/a38965f997bf3f35c92e4ce7e7a6faa7 to your computer and use it in GitHub Desktop.
BrainF**k interpreter by Kotlin
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
object BF { | |
private val commends = mapOf( | |
'>' to "pinc", | |
'<' to "pdec", | |
'+' to "inc", | |
'-' to "dec", | |
'.' to "out", | |
',' to "inp", | |
'[' to "jmp", | |
']' to "ret" | |
) | |
fun execute(code: String): Unit { | |
val coms = parse(code) | |
val str = Machine(coms).execute() | |
println(str) | |
} | |
private fun parse(code: String): Sequence<String> { | |
return code.asSequence() | |
.map { commends.getOrDefault(it, "") } | |
.filter { it != "" } | |
} | |
class Machine(coms: Sequence<String>) { | |
private val cmap: Map<Int, String> | |
private val jmap: Map<Int, Int> | |
private val buffer: MutableMap<Int, Int> = mutableMapOf() | |
private var result: String = "" | |
init { | |
val cs = generateSequence(0) { it + 1 }.zip(coms).toList() | |
cmap = cs.toMap() | |
jmap = parseJump(cs) | |
} | |
fun execute(): String { | |
return stepExecute(1, 0, 0) | |
} | |
private fun parseJump(cs: List<Pair<Int, String>>): Map<Int, Int> { | |
val sj = cs.filter { it.second == "jmp" }.map { it.first } | |
val ej = cs.filter { it.second == "ret" }.map { it.first } | |
val list = sj.zip(ej) + ej.zip(sj) | |
return list.toMap() | |
} | |
private fun stepExecute(step: Int, cind: Int, pind: Int): String { | |
val com = cmap.getOrDefault(cind, "fin") | |
when (com) { | |
"pinc" -> stepExecute(step + 1, cind + 1, pind + 1) | |
"pdec" -> stepExecute(step + 1, cind + 1, pind - 1) | |
"inc" -> { | |
increment(pind) | |
stepExecute(step + 1, cind + 1, pind) | |
} | |
"dec" -> { | |
decrement(pind) | |
stepExecute(step + 1, cind + 1, pind) | |
} | |
"out" -> { | |
output(pind) | |
stepExecute(step + 1, cind + 1, pind) | |
} | |
"inp" -> stepExecute(step + 1, cind + 1, pind) // do nothing | |
"jmp" -> stepExecute(step + 1, jumpTo(cind, pind), pind) | |
"ret" -> stepExecute(step + 1, returnTo(cind, pind), pind) | |
} | |
return result | |
} | |
private fun increment(pind: Int): Unit { | |
val value = buffer.getOrDefault(pind, 0) | |
buffer[pind] = value + 1 | |
} | |
private fun decrement(pind: Int): Unit { | |
val value = buffer.getOrDefault(pind, 0) | |
buffer[pind] = value - 1 | |
} | |
private fun output(pind: Int): Unit { | |
val value = buffer.getOrDefault(pind, 0) | |
result += value.toChar() | |
} | |
private fun jumpTo(cind: Int, pind: Int): Int { | |
val value = buffer.getOrDefault(pind, 0) | |
val jv = jmap[cind] | |
checkNotNull(jv, { "jump index error" }) | |
return if (value == 0) jv else cind + 1 | |
} | |
private fun returnTo(cind: Int, pind: Int): Int { | |
val value = buffer.getOrDefault(pind, 0) | |
val jv = jmap[cind] | |
checkNotNull(jv, { "jump index error" }) | |
return if (value != 0) jv else cind + 1 | |
} | |
} | |
} | |
fun main() { | |
val hello = """ | |
+++++++++[>++++++++>+++++++++++>+++++<<<-]>. | |
>++.+++++++..+++.>-.------------.<++++++++. | |
--------.+++.------.--------.>+. | |
""".trimIndent() | |
BF.execute(hello) // -> Hello, world! | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment