| 633 |      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")
 |