// 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")
}