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