progs/bf/bfc0.sc
changeset 740 923b946347e6
parent 738 084e2843f478
child 742 b5b5583a3a08
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/progs/bf/bfc0.sc	Mon Jul 27 01:55:05 2020 +0100
@@ -0,0 +1,71 @@
+// 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 
+
+// 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 the boilerplate
+def compile(prog: String) : String = 
+  s"""#include <string.h> 
+      #include <stdio.h> 
+      char field[30000]; 
+      char *ptr = &field[15000]; 
+      int main() { 
+      memset(field, '\\0', 30000); 
+      ${instrs(prog)} 
+      return 0;}"""
+
+def compile_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_run(prog: String) = {
+  val tn = "tmp"
+  compile_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_run(bf_str))} secs")
+}  
+
+
+