| 
     1 // A Transpiler for the Brainf*** language  | 
         | 
     2 //=========================================  | 
         | 
     3   | 
         | 
     4 import io.Source  | 
         | 
     5 import scala.util._  | 
         | 
     6   | 
         | 
     7   | 
         | 
     8 // loding a bf-file   | 
         | 
     9 def load_bff(name: String) : String =   | 
         | 
    10   Try(Source.fromFile(name)("ISO-8859-1").mkString).getOrElse("") | 
         | 
    11   | 
         | 
    12   | 
         | 
    13 // simple instructions  | 
         | 
    14 def instr(c: Char) : String = c match { | 
         | 
    15   case '>' => "ptr++;"  | 
         | 
    16   case '<' => "ptr--;"  | 
         | 
    17   case '+' => "(*ptr)++;"  | 
         | 
    18   case '-' => "(*ptr)--;"  | 
         | 
    19   case '.' => "putchar(*ptr);"  | 
         | 
    20   case ',' => "*ptr = getchar();\n"  | 
         | 
    21   case '['  => "while(*ptr){" | 
         | 
    22   case ']'  => "}"  | 
         | 
    23   case _ => ""  | 
         | 
    24 }  | 
         | 
    25   | 
         | 
    26 def instrs(prog: String) : String =  | 
         | 
    27   prog.toList.map(instr(_)).mkString  | 
         | 
    28   | 
         | 
    29   | 
         | 
    30 def compile_str(prog: String) : String = { | 
         | 
    31   "#include <string.h>\n" ++  | 
         | 
    32   "#include <stdio.h>\n" ++  | 
         | 
    33   "char field[30000];\n" ++  | 
         | 
    34   "char *ptr = &field[15000];" ++  | 
         | 
    35   "int main()\n{\n" ++ | 
         | 
    36   "memset(field, '\\0', 30000);\n" ++  | 
         | 
    37   instrs(prog) ++  | 
         | 
    38   "\n return 0;\n}"  | 
         | 
    39 }  | 
         | 
    40   | 
         | 
    41 def compile(name: String, prog: String) = { | 
         | 
    42   val fw = new java.io.FileWriter(name + ".c")   | 
         | 
    43   val is = compile_str(prog)  | 
         | 
    44   //println(is)  | 
         | 
    45   fw.write(is)   | 
         | 
    46   fw.close()  | 
         | 
    47 }  | 
         | 
    48   | 
         | 
    49 // running the c-compiler over the transpiled  | 
         | 
    50 // BF program and running the result  | 
         | 
    51 import sys.process._  | 
         | 
    52   | 
         | 
    53 def compile_run(prog: String) = { | 
         | 
    54   compile("tmp", prog) | 
         | 
    55   "gcc -O3 -o tmp tmp.c".!  | 
         | 
    56   "./tmp".!  | 
         | 
    57   ()  | 
         | 
    58 }  | 
         | 
    59   | 
         | 
    60 def time_needed[T](n: Int, code: => T) = { | 
         | 
    61   val start = System.nanoTime()  | 
         | 
    62   for (i <- 0 until n) code  | 
         | 
    63   val end = System.nanoTime()  | 
         | 
    64   (end - start)/(n * 1.0e9)  | 
         | 
    65 }  | 
         | 
    66   | 
         | 
    67 // the mandelbrot program  | 
         | 
    68 val b0 = load_bff("mandelbrot.bf") | 
         | 
    69   | 
         | 
    70 println(s"${time_needed(1, compile_run(b0))} secs") | 
         | 
    71   | 
         | 
    72   | 
         | 
    73   | 
         | 
    74 // a benchmark program (counts down from 'Z' to 'A')  | 
         | 
    75 val b1 = """>++[<+++++++++++++>-]<[[>+>+<<-]>[<+>-]++++++++  | 
         | 
    76             [>++++++++<-]>.[-]<<>++++++++++[>++++++++++[>++  | 
         | 
    77             ++++++++[>++++++++++[>++++++++++[>++++++++++[>+  | 
         | 
    78             +++++++++[-]<-]<-]<-]<-]<-]<-]<-]++++++++++."""  | 
         | 
    79   | 
         | 
    80 println(s"${time_needed(1, compile_run(b1))} secs") | 
         | 
    81   | 
         | 
    82   | 
         | 
    83   | 
         | 
    84   |