progs/bf/bfc0.scala
author Christian Urban <christian dot urban at kcl dot ac dot uk>
Fri, 24 Jul 2020 12:58:19 +0100
changeset 738 084e2843f478
parent 736 d3e477fe6c66
permissions -rw-r--r--
updated

// A Transpiler for the Brainf*** language to C
//===============================================
//
// Call with
//
//  amm bfc0.sc <<bf_program.bf>>
//


import scala.util._


// loding a bf-file 
def load_bff(name: String) : String = 
  Try(Source.fromFile(name)("ISO-8859-1").mkString).getOrElse("")


// simple instructions
def instr(c: Char) : String = c match {
  case '>' => "ptr++;"
  case '<' => "ptr--;"
  case '+' => "(*ptr)++;"
  case '-' => "(*ptr)--;"
  case '.' => "putchar(*ptr);"
  case ',' => "*ptr = getchar();\n"
  case '['  => "while(*ptr){"
  case ']'  => "}"
  case _ => ""
}

def instrs(prog: String) : String =
  prog.toList.map(instr(_)).mkString


def compile_str(prog: String) : String = {
  "#include <string.h>\n" ++
  "#include <stdio.h>\n" ++
  "char field[30000];\n" ++
  "char *ptr = &field[15000];" ++
  "int main()\n{\n" ++
  "memset(field, '\\0', 30000);\n" ++
  instrs(prog) ++
  "\n return 0;\n}"
}

def compile(name: String, prog: String) = {
  val fw = new java.io.FileWriter(name + ".c") 
  val is = compile_str(prog)
  //println(is)
  fw.write(is) 
  fw.close()
}

// running the c-compiler over the transpiled
// BF program and running the result
import sys.process._

def compile_run(prog: String) = {
  compile("tmp", prog)
  "gcc -O3 -o tmp tmp.c".!
  "./tmp".!
  ()
}

def time_needed[T](n: Int, code: => T) = {
  val start = System.nanoTime()
  for (i <- 0 until n) code
  val end = System.nanoTime()
  (end - start)/(n * 1.0e9)
}

// Running Testcases
//===================

@doc(" the argument should be a BF program ")
@main
def main(fname: String) = {
  val bf_str = os.read(os.pwd / fname)
  println(s"${time_needed(1, run(bf_str))} secs")
}