Skip to content

Instantly share code, notes, and snippets.

@okwrtdsh
Last active May 31, 2018 15:08
Show Gist options
  • Save okwrtdsh/c8e36d485d7c57849935d788b97f19b4 to your computer and use it in GitHub Desktop.
Save okwrtdsh/c8e36d485d7c57849935d788b97f19b4 to your computer and use it in GitHub Desktop.
import java.io.InputStream
import java.io.File
fun String.binaryToUnsignedInt(): Int = this.fold(0) {
acc, c -> acc * 2 + if (c == 'T') 1 else 0
}
fun String.binaryToInt(): Int =
this.drop(1).binaryToUnsignedInt() * if (this.first() == 'S') 1 else -1
fun <T> MutableList<T>.pop(index: Int = 0) = this.removeAt(this.lastIndex - index)
fun <T> MutableList<T>.popN(n: Int) = (1..n).map{this.pop(1)}
fun <T> MutableList<T>.swapTop() = this.addAll((0..1).map{this.pop()})
fun <T> MutableList<T>.duplicate(index: Int = 0) = this.add(this[this.lastIndex - index])
tailrec fun String.createLabel(label: MutableMap<String, String>): Unit {
val code = when {
this.startsWith("STL") -> this.drop(3).substringAfter('L')
this.startsWith("SL") -> this.drop(3)
this.startsWith("S") -> this.substringAfter('L')
this.startsWith("TT") -> this.drop(3)
this.startsWith("T") -> this.drop(4)
this.startsWith("LSS") -> {
label.put(
this.drop(3).substringBefore('L'),
this.drop(3).substringAfter('L'))
this.drop(3).substringAfter('L')
}
this.startsWith("LLL") -> this.drop(3)
this.startsWith("LTL") -> this.drop(3)
this.startsWith("L") -> this.drop(3).substringAfter('L')
else -> ""
}
if (code.isNotEmpty()) code.createLabel(label)
}
tailrec fun String.exec(
stack: MutableList<Int>,
heap: MutableMap<Int, Int>,
label: MutableMap<String, String>,
callStack: MutableList<String>,
debug: Boolean = false,
showInstruction: Boolean = false): Unit {
val code = when {
this.startsWith("S") -> this.drop(1).operateStack(stack, showInstruction)
this.startsWith("TS") -> this.drop(2).operateArithmetic(stack, showInstruction)
this.startsWith("TT") -> this.drop(2).operateHeap(stack, heap, showInstruction)
this.startsWith("TL") -> this.drop(2).operateIO(stack, heap, showInstruction)
this.startsWith("L") -> this.drop(1).operateFlow(stack, label, callStack, showInstruction)
else -> ""
}
var nextDebug = debug
if(debug) {
loop@ while(true) {
println("\nS: Show Stack, H: Show heap, L: Show Label, C: Show Call Stack, Q: Run All, Empty: Next Step")
print(">>> ")
val cmd: String = readLine() ?: ""
when {
cmd == "S" || cmd == "s" -> println(stack)
cmd == "H" || cmd == "h" -> println(heap.map{it.key})
cmd == "L" || cmd == "l" -> println(label.map{it.key})
cmd == "C" || cmd == "c" -> println(callStack.map{it.take(20)})
cmd == "Q" || cmd == "q" -> {
nextDebug = false
break@loop
}
cmd.startsWith("H") || cmd.startsWith("h") -> {
if (cmd.filter{it in '0'..'9'}.isNotEmpty())
println(heap[cmd.filter{it in '0'..'9'}.toInt()])
}
cmd.startsWith("L") || cmd.startsWith("l") -> {
if (cmd.filter{it in "ST"}.isNotEmpty())
println(label[cmd.filter{it in "ST"}]?.take(20))
}
cmd.startsWith("C") || cmd.startsWith("c") -> {
if (cmd.filter{it in '0'..'9'}.isNotEmpty()) {
val index = cmd.filter{it in '0'..'9'}.toInt()
if (callStack.size > index) println(callStack[callStack.lastIndex - index].take(20))
}
}
cmd == "" -> break@loop
else -> {}
}
}
}
if (code.isNotEmpty()) code.exec(stack, heap, label, callStack, nextDebug, showInstruction)
}
fun String.operateStack(
stack: MutableList<Int>,
showInstruction: Boolean): String = when {
this.startsWith("S") -> {
if (showInstruction) println(
"S-S-${this.drop(1).substringBefore('L')}L "
+ "# stack push ${this.drop(1).substringBefore('L').binaryToInt()}"
)
stack.add(this.drop(1).substringBefore('L').binaryToInt())
this.substringAfter('L')
}
this.startsWith("TS") -> {
if (showInstruction) println(
"S-TS-${this.drop(2).substringBefore('L')}L "
+ "# stack duplicate index: ${this.drop(2).substringBefore('L').binaryToInt()}"
)
stack.duplicate(this.drop(2).substringBefore('L').binaryToInt())
this.substringAfter('L')
}
this.startsWith("TL") -> {
if (showInstruction) println(
"S-TL-${this.drop(2).substringBefore('L')}L "
+ "# stack pop 2 to ${this.drop(2).substringBefore('L').binaryToInt()}"
)
stack.popN(this.drop(2).substringBefore('L').binaryToInt())
this.drop(2).substringAfter('L')
}
this.startsWith("LS") -> {
if (showInstruction) println(
"S-LS "
+ "# stack duplicate top"
)
stack.duplicate()
this.drop(2)
}
this.startsWith("LT") -> {
if (showInstruction) println(
"S-LT "
+ "# stack swap top"
)
stack.swapTop()
this.drop(2)
}
this.startsWith("LL") -> {
if (showInstruction) println(
"S-LL "
+ "# stack pop"
)
stack.pop()
this.drop(2)
}
else -> ""
}
fun String.operateArithmetic(
stack: MutableList<Int>,
showInstruction: Boolean): String = when {
this.startsWith("SS") -> {
if (showInstruction) println(
"TS-SS "
+ "# arithmetic ${stack[stack.lastIndex-1]} + ${stack.last()}"
)
stack.add(stack.pop(1)+stack.pop())
this.drop(2)
}
this.startsWith("ST") -> {
if (showInstruction) println(
"TS-ST "
+ "# arithmetic ${stack[stack.lastIndex-1]} - ${stack.last()}"
)
stack.add(stack.pop(1)-stack.pop())
this.drop(2)
}
this.startsWith("SL") -> {
if (showInstruction) println(
"TS-SL "
+ "# arithmetic ${stack[stack.lastIndex-1]} * ${stack.last()}"
)
stack.add(stack.pop(1)*stack.pop())
this.drop(2)
}
this.startsWith("TS") -> {
if (showInstruction) println(
"TS-TS "
+ "# arithmetic ${stack[stack.lastIndex-1]} / ${stack.last()}"
)
stack.add(stack.pop(1)/stack.pop())
this.drop(2)
}
this.startsWith("TT") -> {
if (showInstruction) println(
"TS-TT "
+ "# arithmetic ${stack[stack.lastIndex-1]} % ${stack.last()}"
)
stack.add(stack.pop(1)%stack.pop())
this.drop(2)
}
else -> ""
}
fun String.operateHeap(
stack: MutableList<Int>,
heap: MutableMap<Int, Int>,
showInstruction: Boolean): String = when {
this.startsWith("S") -> {
if (showInstruction) println(
"TT-S "
+ "# heap put {${stack[stack.lastIndex-1]}=${stack.last()}}"
)
heap.put(stack.pop(1), stack.pop())
this.drop(1)
}
this.startsWith("T") -> {
if (showInstruction) println(
"TT-T "
+ "# heap stack push from heap[${stack.last()}]"
)
stack.add(heap[stack.pop()]!!)
this.drop(1)
}
else -> ""
}
fun String.operateIO(
stack: MutableList<Int>,
heap: MutableMap<Int, Int>,
showInstruction: Boolean): String = when {
this.startsWith("SS") -> {
if (showInstruction) print(
"TL-SS "
+ "# io print char from ${stack.last()}: "
)
print(stack.pop().toChar())
if (showInstruction) println()
this.drop(2)
}
this.startsWith("ST") -> {
if (showInstruction) print(
"TL-ST "
+ "# io print number: "
)
print(stack.pop().toString())
if (showInstruction) println()
this.drop(2)
}
this.startsWith("TS") -> {
if (showInstruction) println(
"TL-TS "
+ "# io read char to heap[${stack.last()}]"
)
val iStream : InputStream = System.`in`
heap.put(stack.pop(), iStream.read().toInt())
this.drop(2)
}
this.startsWith("TT") -> {
if (showInstruction) println(
"TL-TT "
+ "# io read number to heap[${stack.last()}]"
)
heap.put(stack.pop(), readLine()!!.toInt())
this.drop(2)
}
else -> ""
}
fun String.operateFlow(
stack: MutableList<Int>,
label: MutableMap<String, String>,
callStack: MutableList<String>,
showInstruction: Boolean): String = when {
this.startsWith("SS") -> {
if (showInstruction) println(
"L-SS-${this.drop(2).substringBefore('L')}L "
+ "# flow define label ${this.drop(2).substringBefore('L')}"
)
this.substringAfter('L')
}
this.startsWith("ST") -> {
if (showInstruction) println(
"L-ST-${this.drop(2).substringBefore('L')}L "
+ "# flow callstack push now point and jump to label ${this.drop(2).substringBefore('L')}"
)
callStack.add(this.substringAfter('L'))
label[this.drop(2).substringBefore('L')]!!
}
this.startsWith("SL") -> {
if (showInstruction) println(
"L-SL-${this.drop(2).substringBefore('L')}L "
+ "# flow jump to label ${this.drop(2).substringBefore('L')}"
)
label[this.drop(2).substringBefore('L')]!!
}
this.startsWith("TS") -> {
if (showInstruction) println(
"L-TS-${this.drop(2).substringBefore('L')}L "
+ "# flow if stack pop (${stack.last()}) == 0 then jump to label ${this.drop(2).substringBefore('L')}"
)
if (stack.pop() == 0) label[this.drop(2).substringBefore('L')]!!
else this.substringAfter('L')
}
this.startsWith("TT") -> {
if (showInstruction) println(
"L-TT-${this.drop(2).substringBefore('L')}L "
+ "# flow if stack pop (${stack.last()}) < 0 then jump to label ${this.drop(2).substringBefore('L')}"
)
if (stack.pop() < 0) label[this.drop(2).substringBefore('L')]!!
else this.substringAfter('L')
}
this.startsWith("TL") -> {
if (showInstruction) println(
"L-TL "
+ "# flow callstack pop"
)
callStack.pop()
}
this.startsWith("LL") -> {
if (showInstruction) println(
"L-LL "
+ "# flow exit"
)
""
}
else -> ""
}
fun main(args: Array<String>) {
if (args.size < 1) return
val showInstruction: Boolean = args.size >= 2 && args[1] == "true"
val debug: Boolean = args.size == 3 && args[2] == "true"
val stack = mutableListOf<Int>()
val heap = mutableMapOf<Int, Int>()
val label = mutableMapOf<String, String>()
val callStack = mutableListOf<String>()
val code = File(args[0]).readText().filter{it in " \t\n"}
.replace(' ', 'S').replace('\t', 'T').replace('\n', 'L')
code.createLabel(label)
code.exec(stack, heap, label, callStack, debug, showInstruction)
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment