// A Transpiler for the Brainf*** language to C+ −
//===============================================+ −
//+ −
// Call with+ −
//+ −
// amm bfc0.sc <<bf_program.bf>>+ −
//+ −
//+ −
// Note: An interesting exercise is to call+ −
// gcc with -O3 instead of -O0 (see invocation+ −
// below).+ −
+ −
+ −
// simple instructions+ −
def instr(c: Char) : String = c match {+ −
case '>' => "ptr++;"+ −
case '<' => "ptr--;"+ −
case '+' => "(*ptr)++;"+ −
case '-' => "(*ptr)--;"+ −
case '.' => "putchar(*ptr);"+ −
case ',' => "*ptr = getchar();"+ −
case '[' => "while(*ptr){"+ −
case ']' => "}"+ −
case _ => ""+ −
}+ −
+ −
def instrs(prog: String) : String =+ −
prog.toList.map(instr(_)).mkString+ −
+ −
// adding boilerplate+ −
def compile(prog: String) : String = + −
s"""#include <string.h> + −
#include <stdio.h> + −
int field[30000]; + −
int *ptr = &field[15000]; + −
int main() { + −
memset(field, '\\0', 30000); + −
${instrs(prog)} + −
return 0;}"""+ −
+ −
+ −
def compile_to_file(name: String, prog: String) = + −
os.write.over(os.pwd / name, compile(prog))+ −
+ −
+ −
// running the c-compiler over the transpiled+ −
// BF program and running the resulting binary+ −
+ −
def compile_and_run(prog: String) = {+ −
val tn = "tmp"+ −
compile_to_file(s"${tn}.c", prog)+ −
os.proc("gcc", "-O0", "-o", tn, s"${tn}.c").call() // call gcc+ −
os.proc("./tmp").call(stdout = os.Inherit) // run binary+ −
}+ −
+ −
// Running Testcases+ −
//===================+ −
+ −
def time_needed[T](n: Int, code: => T) = {+ −
val start = System.nanoTime()+ −
for (i <- 0 until n) code+ −
val end = System.nanoTime()+ −
(end - start)/(n * 1.0e9)+ −
}+ −
+ −
//@doc(" the argument should be a BF program ")+ −
@main+ −
def main(fname: String) = {+ −
val bf_str = os.read(os.pwd / fname)+ −
println(s"${time_needed(1, compile_and_run(bf_str))} secs")+ −
} + −
+ −
+ −
+ −