progs/bf/bfc0.sc
changeset 740 923b946347e6
parent 738 084e2843f478
child 742 b5b5583a3a08
equal deleted inserted replaced
739:220aea0e5517 740:923b946347e6
       
     1 // A Transpiler for the Brainf*** language to C
       
     2 //===============================================
       
     3 //
       
     4 // Call with
       
     5 //
       
     6 //  amm bfc0.sc <<bf_program.bf>>
       
     7 //
       
     8 //
       
     9 // Note: An interesting exercise is to call
       
    10 // gcc with -O3 instead of -O0 
       
    11 
       
    12 // simple instructions
       
    13 def instr(c: Char) : String = c match {
       
    14   case '>' => "ptr++;"
       
    15   case '<' => "ptr--;"
       
    16   case '+' => "(*ptr)++;"
       
    17   case '-' => "(*ptr)--;"
       
    18   case '.' => "putchar(*ptr);"
       
    19   case ',' => "*ptr = getchar();"
       
    20   case '['  => "while(*ptr){"
       
    21   case ']'  => "}"
       
    22   case _ => ""
       
    23 }
       
    24 
       
    25 def instrs(prog: String) : String =
       
    26   prog.toList.map(instr(_)).mkString
       
    27 
       
    28 // adding the boilerplate
       
    29 def compile(prog: String) : String = 
       
    30   s"""#include <string.h> 
       
    31       #include <stdio.h> 
       
    32       char field[30000]; 
       
    33       char *ptr = &field[15000]; 
       
    34       int main() { 
       
    35       memset(field, '\\0', 30000); 
       
    36       ${instrs(prog)} 
       
    37       return 0;}"""
       
    38 
       
    39 def compile_file(name: String, prog: String) = 
       
    40   os.write.over(os.pwd / name, compile(prog))
       
    41 
       
    42 
       
    43 // running the c-compiler over the transpiled
       
    44 // BF program and running the resulting binary
       
    45 
       
    46 def compile_run(prog: String) = {
       
    47   val tn = "tmp"
       
    48   compile_file(s"${tn}.c", prog)
       
    49   os.proc("gcc", "-O0", "-o", tn, s"${tn}.c").call() // call gcc
       
    50   os.proc("./tmp").call(stdout = os.Inherit)         // run binary
       
    51 }
       
    52 
       
    53 // Running Testcases
       
    54 //===================
       
    55 
       
    56 def time_needed[T](n: Int, code: => T) = {
       
    57   val start = System.nanoTime()
       
    58   for (i <- 0 until n) code
       
    59   val end = System.nanoTime()
       
    60   (end - start)/(n * 1.0e9)
       
    61 }
       
    62 
       
    63 @doc(" the argument should be a BF program ")
       
    64 @main
       
    65 def main(fname: String) = {
       
    66   val bf_str = os.read(os.pwd / fname)
       
    67   println(s"${time_needed(1, compile_run(bf_str))} secs")
       
    68 }  
       
    69 
       
    70 
       
    71