Last active
October 29, 2019 11:35
-
-
Save KisaragiEffective/5b3e54c049ed02b930a0936fd5ae0dd6 to your computer and use it in GitHub Desktop.
頼むからILぐらいちゃんと吐いてくれ
This file contains hidden or 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
package com.github.kisaragieffective.bfvm | |
import com.github.kisaragieffective.bfvm.instruction.* | |
import java.net.HttpURLConnection | |
import java.net.URL | |
var errors = 0 | |
fun main() { | |
// `-+><,.[]`以外の8文字は無視しても差し支えない | |
val m = "++++++++[>++++++++<-]>+."//checkGithub() | |
debug(m) | |
debug("m.len is ${m.length}") | |
// exitProcess(0) | |
var eatenIndex = 0 | |
val instructions = mutableListOf<BFInstruction>() | |
val squareBrackets = mutableSetOf<Int>() | |
eater@ while (eatenIndex <= m.lastIndex) { | |
var p: Regex | |
var mr: MatchResult? | |
p = Regex("\\[-](?<value>\\+*+)") | |
mr = p.find(m, eatenIndex) | |
if (mr != null) { // found | |
debug("HIT LDC!") | |
instructions += BFLoadConstant(mr.groups["value"]!!.value.length) | |
eatenIndex += mr.range.last - mr.range.first | |
continue@eater | |
} | |
// [>+<-] | |
p = Regex("\\[(?<rmv>>)\\+(?<lmv><)-\\]") | |
mr = p.find(m, eatenIndex) | |
if (mr != null) { // found | |
if (mr.groups["rmv"] == mr.groups["lmv"]) { | |
debug("HIT BCPY!") | |
instructions += BFBreakingCopy(mr.groups["rmv"]!!.value.length) | |
eatenIndex += mr.range.last - mr.range.first | |
continue@eater | |
} | |
} | |
// [<+>-] | |
p = Regex("\\[(?<lmv><)\\+(?<rmv>>)-\\]") | |
mr = p.find(m, eatenIndex) | |
if (mr != null) { // found | |
if (mr.groups["rmv"] != mr.groups["lmv"]) { | |
debug("HIT BCPY!") | |
instructions += BFBreakingCopy(-mr.groups["rmv"]!!.value.length) | |
eatenIndex += mr.range.last - mr.range.first | |
continue@eater | |
} | |
} | |
// [>+++++++<-] | |
p = Regex("\\[(?<rmv>>)(?<mult>\\+)(?<lmv><)-\\]") | |
mr = p.find(m, eatenIndex) | |
if (mr != null) { // found | |
val groups = mr.groups | |
if (groups["rmv"] != groups["lmv"]) { | |
instructions += BFBreakingMultiple(groups["rmv"]!!.value.length, groups["mult"]!!.value.length) | |
eatenIndex += mr.range.last - mr.range.first | |
continue@eater | |
} | |
} | |
// [<+++++++>-] | |
p = Regex("\\[(?<lmv><)(?<mult>\\+)(?<rmv>>)-\\]") | |
mr = p.find(m, eatenIndex) | |
if (mr != null) { // found | |
val groups = mr.groups | |
if (groups["rmv"] != groups["lmv"]) { | |
debug("HIT BMUL!") | |
instructions += BFBreakingMultiple(-groups["rmv"]!!.value.length, groups["mult"]!!.value.length) | |
eatenIndex += mr.range.last - mr.range.first | |
continue@eater | |
} | |
} | |
// + | |
p = Regex("\\++") | |
mr = p.find(m, eatenIndex) | |
if (mr != null && mr.range.first == eatenIndex) { // found | |
val len = mr.range.last - mr.range.first + 1 | |
instructions += BFAdd(len) | |
eatenIndex += len | |
continue@eater | |
} | |
// - | |
p = Regex("-+") | |
mr = p.find(m, eatenIndex) | |
if (mr != null && mr.range.first == eatenIndex) { // found | |
val len = mr.range.last - mr.range.first + 1 | |
instructions += BFMinus(len) | |
eatenIndex += len | |
continue@eater | |
} | |
// > | |
p = Regex(">+") | |
mr = p.find(m, eatenIndex) | |
if (mr != null && mr.range.first == eatenIndex) { // found | |
val len = mr.range.last - mr.range.first + 1 | |
instructions += BFPtrRight(len) | |
eatenIndex += len | |
continue@eater | |
} | |
// < | |
p = Regex("<+") | |
mr = p.find(m, eatenIndex) | |
if (mr != null && mr.range.first == eatenIndex) { // found | |
val len = mr.range.last - mr.range.first + 1 | |
instructions += BFPtrLeft(len) | |
eatenIndex += len | |
continue@eater | |
} | |
// , | |
p = Regex(",+") | |
mr = p.find(m, eatenIndex) | |
if (mr != null && mr.range.first == eatenIndex) { // found | |
val len = mr.range.last - mr.range.first + 1 | |
if (len != 1) { | |
warn("You used `,` operator multiple times, but it has no effects.") | |
} | |
instructions += BFReadChar | |
eatenIndex += 1 // 複数回同じ番地に同じ値を読み込んでも意味ないのでは? | |
continue@eater | |
} | |
// . | |
p = Regex("\\.+") | |
mr = p.find(m, eatenIndex) | |
if (mr != null && mr.range.first == eatenIndex) { // found | |
val len = mr.range.last - mr.range.first + 1 | |
for (_z in 1..len) { | |
instructions += BFPutChar | |
} | |
eatenIndex += len | |
continue@eater | |
} | |
// [ | |
var sbidx = m.indexOf('[', eatenIndex) | |
if (sbidx != -1 && sbidx !in squareBrackets) { | |
var nest = 0 | |
var lastBreak = -1 | |
for (j in sbidx until m.length) { | |
if (m[j] == '[') { | |
nest++ | |
} else if (m[j] == ']') { | |
nest-- | |
} | |
if (nest == 0) { | |
lastBreak = j | |
break | |
} | |
} | |
if (lastBreak == -1) { | |
error("Square brackets mismatch: `]` * $nest near $eatenIndex") | |
} | |
instructions += BFLabel(sbidx) | |
instructions += BFJumpEquals(lastBreak) | |
eatenIndex++ | |
squareBrackets += sbidx | |
continue@eater | |
} | |
// ] | |
sbidx = m.indexOf(']', eatenIndex) | |
debug("sbidx is ${sbidx}, i is $eatenIndex, in? is ${sbidx !in squareBrackets}") | |
if (sbidx != -1) { | |
var nest = 0 | |
var lastBreak = -1 | |
debug("`]` detected: $sbidx") | |
for (j in sbidx downTo 0) { | |
if (m[j] == ']') { | |
nest++ | |
} else if (m[j] == '[') { | |
nest-- | |
} | |
if (nest == 0) { | |
lastBreak = j | |
break | |
} | |
} | |
if (lastBreak == -1) { | |
error("Square brackets mismatch: `[` * $nest near $eatenIndex") | |
} | |
if (sbidx !in squareBrackets) { | |
instructions += BFLabel(sbidx) | |
instructions += BFJumpNotEquals(lastBreak) | |
squareBrackets += sbidx | |
} | |
eatenIndex++ | |
continue@eater | |
} | |
debug("remain is ${m.slice(eatenIndex..(m.lastIndex))}") | |
} | |
for (instruction in instructions) { | |
val ir = when (instruction) { | |
is BFAdd -> "ADD ${instruction.amount}" | |
is BFLabel -> ":${instruction.idx}" | |
is BFMinus -> "MINUS ${instruction.amount}" | |
is BFPtrLeft -> "PTR -${instruction.amount}" | |
is BFPtrRight -> "PTR ${instruction.amount}" | |
BFPutChar -> "PUTCHAR" | |
BFReadChar -> "READCHAR" | |
is BFJumpEquals -> "JE :${instruction.offset}" | |
is BFJumpNotEquals -> "JNE :${instruction.offset}" | |
is BFBreakingCopy -> "BCP ${instruction.offset}" | |
is BFBreakingMultiple -> "BMPL ${instruction.offset}, ${instruction.times}" | |
is BFLoadConstant -> "LCD ${instruction.value}" | |
BFLoadZero -> "LCD 0" | |
} | |
println(ir) | |
} | |
} | |
fun warn(mes: String) { | |
println("[WARN] $mes") | |
} | |
fun error(mes: String) { | |
println("[ERROR] $mes") | |
errors++ | |
} | |
fun debug(mes: String) { | |
println("[DEBUG] $mes") | |
} | |
fun checkGithub() = (URL("https://raw.githubusercontent.com/kostya/benchmarks/master/brainfuck/mandel.b").openConnection() as HttpURLConnection).apply { | |
requestMethod = "GET" | |
connect() | |
}.inputStream.bufferedReader().lineSequence().joinToString("").replace(Regex("[^-+,.><\\[\\]]+"), "") | |
inline fun handleRegex(regex: String, f: () -> Unit) { | |
val rex = Regex(regex) | |
f() | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment