| author | Christian Urban <christian.urban@kcl.ac.uk> | 
| Tue, 27 Oct 2020 13:46:01 +0000 | |
| changeset 792 | 1f9a45fb5429 | 
| parent 746 | 1779f8488689 | 
| child 825 | fb9f63a22114 | 
| permissions | -rw-r--r-- | 
| 738 
03f46065ef04
updated
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: 
736diff
changeset | 1 | // A Transpiler for the Brainf*** language to C | 
| 
03f46065ef04
updated
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: 
736diff
changeset | 2 | //=============================================== | 
| 
03f46065ef04
updated
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: 
736diff
changeset | 3 | // | 
| 
03f46065ef04
updated
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: 
736diff
changeset | 4 | // Call with | 
| 
03f46065ef04
updated
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: 
736diff
changeset | 5 | // | 
| 
03f46065ef04
updated
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: 
736diff
changeset | 6 | // amm bfc0.sc <<bf_program.bf>> | 
| 
03f46065ef04
updated
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: 
736diff
changeset | 7 | // | 
| 740 | 8 | // | 
| 9 | // Note: An interesting exercise is to call | |
| 742 | 10 | // gcc with -O3 instead of -O0 (see invocation | 
| 11 | // below). | |
| 12 | ||
| 633 | 13 | |
| 14 | // simple instructions | |
| 15 | def instr(c: Char) : String = c match {
 | |
| 16 | case '>' => "ptr++;" | |
| 17 | case '<' => "ptr--;" | |
| 18 | case '+' => "(*ptr)++;" | |
| 19 | case '-' => "(*ptr)--;" | |
| 20 | case '.' => "putchar(*ptr);" | |
| 740 | 21 | case ',' => "*ptr = getchar();" | 
| 633 | 22 |   case '['  => "while(*ptr){"
 | 
| 23 | case ']' => "}" | |
| 24 | case _ => "" | |
| 25 | } | |
| 26 | ||
| 27 | def instrs(prog: String) : String = | |
| 28 | prog.toList.map(instr(_)).mkString | |
| 29 | ||
| 742 | 30 | // adding boilerplate | 
| 740 | 31 | def compile(prog: String) : String = | 
| 32 | s"""#include <string.h> | |
| 33 | #include <stdio.h> | |
| 746 | 34 | int field[30000]; | 
| 35 | int *ptr = &field[15000]; | |
| 740 | 36 |       int main() { 
 | 
| 37 | memset(field, '\\0', 30000); | |
| 38 |       ${instrs(prog)} 
 | |
| 39 | return 0;}""" | |
| 633 | 40 | |
| 742 | 41 | |
| 42 | def compile_to_file(name: String, prog: String) = | |
| 740 | 43 | os.write.over(os.pwd / name, compile(prog)) | 
| 44 | ||
| 45 | ||
| 46 | // running the c-compiler over the transpiled | |
| 47 | // BF program and running the resulting binary | |
| 48 | ||
| 742 | 49 | def compile_and_run(prog: String) = {
 | 
| 740 | 50 | val tn = "tmp" | 
| 742 | 51 |   compile_to_file(s"${tn}.c", prog)
 | 
| 740 | 52 |   os.proc("gcc", "-O0", "-o", tn, s"${tn}.c").call() // call gcc
 | 
| 53 |   os.proc("./tmp").call(stdout = os.Inherit)         // run binary
 | |
| 633 | 54 | } | 
| 55 | ||
| 740 | 56 | // Running Testcases | 
| 57 | //=================== | |
| 633 | 58 | |
| 59 | def time_needed[T](n: Int, code: => T) = {
 | |
| 60 | val start = System.nanoTime() | |
| 61 | for (i <- 0 until n) code | |
| 62 | val end = System.nanoTime() | |
| 63 | (end - start)/(n * 1.0e9) | |
| 64 | } | |
| 65 | ||
| 738 
03f46065ef04
updated
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: 
736diff
changeset | 66 | @doc(" the argument should be a BF program ")
 | 
| 
03f46065ef04
updated
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: 
736diff
changeset | 67 | @main | 
| 
03f46065ef04
updated
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: 
736diff
changeset | 68 | def main(fname: String) = {
 | 
| 
03f46065ef04
updated
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: 
736diff
changeset | 69 | val bf_str = os.read(os.pwd / fname) | 
| 742 | 70 |   println(s"${time_needed(1, compile_and_run(bf_str))} secs")
 | 
| 738 
03f46065ef04
updated
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: 
736diff
changeset | 71 | } | 
| 633 | 72 | |
| 73 | ||
| 74 |