| 
     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 def splice(cs: List[Char], acc: List[(Char, Int)]) : List[(Char, Int)] = (cs, acc) match { | 
         | 
    13   case (Nil, acc) => acc  | 
         | 
    14   case (c :: cs, Nil) => splice(cs, List((c, 1)))  | 
         | 
    15   case (c :: cs, (d, n) :: acc) =>   | 
         | 
    16     if (c == d) splice(cs, (c, n + 1) :: acc)  | 
         | 
    17     else splice(cs, (c, 1) :: (d, n) :: acc)  | 
         | 
    18 }  | 
         | 
    19   | 
         | 
    20 def spl(s: String) = splice(s.toList, Nil).reverse  | 
         | 
    21   | 
         | 
    22 def instr2(c: Char, n: Int) : String = c match { | 
         | 
    23   case '>' => "ptr += " + n.toString + ";"  | 
         | 
    24   case '<' => "ptr -= " + n.toString + ";"  | 
         | 
    25   case '+' => "(*ptr) += " + n.toString + ";"  | 
         | 
    26   case '-' => "(*ptr) -= " + n.toString + ";"  | 
         | 
    27   case '.' => "putchar(*ptr);" * n  | 
         | 
    28   case ',' => "*ptr = getchar();\n" * n  | 
         | 
    29   case '['  => "while(*ptr){" * n | 
         | 
    30   case ']'  => "}" * n  | 
         | 
    31   case _ => ""  | 
         | 
    32 }  | 
         | 
    33   | 
         | 
    34   | 
         | 
    35 def instrs2(prog: String) : String =  | 
         | 
    36   spl(prog).map{ case (c, n) => instr2(c, n) }.mkString | 
         | 
    37   | 
         | 
    38   | 
         | 
    39 def compile_str(prog: String) : String = { | 
         | 
    40   "#include <string.h>\n" ++  | 
         | 
    41   "#include <stdio.h>\n" ++  | 
         | 
    42   "char field[30000];\n" ++  | 
         | 
    43   "char *ptr = &field[15000];" ++  | 
         | 
    44   "int main()\n{\n" ++ | 
         | 
    45   "memset(field, '\\0', 30000);\n" ++  | 
         | 
    46   instrs2(prog) ++  | 
         | 
    47   "\n return 0;\n}"  | 
         | 
    48 }  | 
         | 
    49   | 
         | 
    50 def compile(name: String, prog: String) = { | 
         | 
    51   val fw = new java.io.FileWriter(name + ".c")   | 
         | 
    52   val is = compile_str(prog)  | 
         | 
    53   //println(is)  | 
         | 
    54   fw.write(is)   | 
         | 
    55   fw.close()  | 
         | 
    56 }  | 
         | 
    57   | 
         | 
    58 import sys.process._  | 
         | 
    59   | 
         | 
    60 def compile_run(prog: String) = { | 
         | 
    61   compile("tmp", prog) | 
         | 
    62   "gcc -O3 -o tmp tmp.c".!  | 
         | 
    63   "./tmp".!  | 
         | 
    64   ()  | 
         | 
    65 }  | 
         | 
    66   | 
         | 
    67 def time_needed[T](n: Int, code: => T) = { | 
         | 
    68   val start = System.nanoTime()  | 
         | 
    69   for (i <- 0 until n) code  | 
         | 
    70   val end = System.nanoTime()  | 
         | 
    71   (end - start) / (n * 1.0e9)  | 
         | 
    72 }  | 
         | 
    73   | 
         | 
    74   | 
         | 
    75 println(s"${time_needed(1, compile_run(load_bff("mandelbrot.bf")))} secs") | 
         | 
    76   | 
         | 
    77   | 
         | 
    78   | 
         | 
    79 // a benchmark program (counts down from 'Z' to 'A')  | 
         | 
    80 val b1 = """>++[<+++++++++++++>-]<[[>+>+<<-]>[<+>-]++++++++  | 
         | 
    81             [>++++++++<-]>.[-]<<>++++++++++[>++++++++++[>++  | 
         | 
    82             ++++++++[>++++++++++[>++++++++++[>++++++++++[>+  | 
         | 
    83             +++++++++[-]<-]<-]<-]<-]<-]<-]<-]++++++++++."""  | 
         | 
    84   | 
         | 
    85 println(s"${time_needed(1, compile_run(b1))} secs") |