Skip to content

Instantly share code, notes, and snippets.

@uehaj
Created September 18, 2013 19:17
Show Gist options
  • Select an option

  • Save uehaj/6614136 to your computer and use it in GitHub Desktop.

Select an option

Save uehaj/6614136 to your computer and use it in GitHub Desktop.
Brainfuck compiler for JVM using indy(invokedynamic)
// ネストしたループにおけるラベル名を管理するためのデータとコード。
def list = [].withDefault{0}
def nestLevel = 0
def level = { it << list[0..nestLevel-1].join('_') }.asWritable()
def increaseLevel = { list[nestLevel++]++; level(it) }.asWritable()
def decreaseLevel = { level(it); nestLevel-- }.asWritable()
// Brainfuck命令をJVMバイトコードにコンバートする
def genCode = {
new File(args[0]).text.replaceAll(/[^\+\-\<\>\.\,\[\]]/, '').eachMatch(/[^\[\]]+|[\[\]]/) { g0 ->
if (g0 == '[') {
it << """ _GOTO tmp$increaseLevel
lab$level:
"""
}
else if (g0 == ']') {
it << """ tmp$level:
getstatic '.data','[B'
getstatic '.dp','I'
baload
ifne lab$decreaseLevel
"""
}
else {
it << """ invokedynamic 'dummy', '()V', [H_INVOKESTATIC, 'Brainfuck', 'bootstrap', [CallSite, Lookup, String, MethodType, String]], '$g0'
"""
}
}
}.asWritable()
println """\
@GrabResolver(name="maven-repo", root="https://raw.github.com/uehaj/maven-repo/gh-pages/snapshot")
@Grab("groovyx.ast.bytecode:groovy-bytecode-ast:0.2.0-separate-asm")
import groovyx.ast.bytecode.Bytecode
import java.lang.invoke.*
import java.lang.invoke.MethodHandles.Lookup
import static groovyjarjarasm.asm.Opcodes.H_INVOKESTATIC
class Brainfuck {
// Bootstrapメソッド
public static CallSite bootstrap(Lookup lookup, String methodName, MethodType type, String instructions) {
MethodHandle result = null
instructions.tr('<>.','lgo').each { insn ->
MethodHandle mh = lookup.findStatic(Brainfuck, insn, MethodType.methodType(void.class))
result = (result == null) ? mh : MethodHandles.filterReturnValue(result, mh)
}
new ConstantCallSite(result)
}
// Brainfuck実行のためのデータ構造
static int dp // データポインタ
static byte[] data = new byte[30000] // メモリ
// Brainfuck命令群
static void '+'(){data[dp]++}
static void '-'(){data[dp]--}
static void l(){dp--} // メソッド名が'<'だとクラスファイルとして違法なメソッド名になるので妥協
static void g(){dp++} // '>'
static void o(){print((char)data[dp])} // '.'
static void ','(){System.in.read(data, dp, 1)}
@Bytecode
static void main(String[] args) throws Exception {
// Brainfuckからコンバートされたコード
$genCode
return
}
}"""
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment