progs/bf/bfc0.sc
author Christian Urban <christian.urban@kcl.ac.uk>
Mon, 27 Jul 2020 01:55:05 +0100
changeset 740 923b946347e6
parent 738 progs/bf/bfc0.scala@084e2843f478
child 742 b5b5583a3a08
permissions -rw-r--r--
updated
Ignore whitespace changes - Everywhere: Within whitespace: At end of lines:
738
084e2843f478 updated
Christian Urban <christian dot urban at kcl dot ac dot uk>
parents: 736
diff changeset
     1
// A Transpiler for the Brainf*** language to C
084e2843f478 updated
Christian Urban <christian dot urban at kcl dot ac dot uk>
parents: 736
diff changeset
     2
//===============================================
084e2843f478 updated
Christian Urban <christian dot urban at kcl dot ac dot uk>
parents: 736
diff changeset
     3
//
084e2843f478 updated
Christian Urban <christian dot urban at kcl dot ac dot uk>
parents: 736
diff changeset
     4
// Call with
084e2843f478 updated
Christian Urban <christian dot urban at kcl dot ac dot uk>
parents: 736
diff changeset
     5
//
084e2843f478 updated
Christian Urban <christian dot urban at kcl dot ac dot uk>
parents: 736
diff changeset
     6
//  amm bfc0.sc <<bf_program.bf>>
084e2843f478 updated
Christian Urban <christian dot urban at kcl dot ac dot uk>
parents: 736
diff changeset
     7
//
740
923b946347e6 updated
Christian Urban <christian.urban@kcl.ac.uk>
parents: 738
diff changeset
     8
//
923b946347e6 updated
Christian Urban <christian.urban@kcl.ac.uk>
parents: 738
diff changeset
     9
// Note: An interesting exercise is to call
923b946347e6 updated
Christian Urban <christian.urban@kcl.ac.uk>
parents: 738
diff changeset
    10
// gcc with -O3 instead of -O0 
633
e4889da2fe29 updated
Christian Urban <urbanc@in.tum.de>
parents:
diff changeset
    11
e4889da2fe29 updated
Christian Urban <urbanc@in.tum.de>
parents:
diff changeset
    12
// simple instructions
e4889da2fe29 updated
Christian Urban <urbanc@in.tum.de>
parents:
diff changeset
    13
def instr(c: Char) : String = c match {
e4889da2fe29 updated
Christian Urban <urbanc@in.tum.de>
parents:
diff changeset
    14
  case '>' => "ptr++;"
e4889da2fe29 updated
Christian Urban <urbanc@in.tum.de>
parents:
diff changeset
    15
  case '<' => "ptr--;"
e4889da2fe29 updated
Christian Urban <urbanc@in.tum.de>
parents:
diff changeset
    16
  case '+' => "(*ptr)++;"
e4889da2fe29 updated
Christian Urban <urbanc@in.tum.de>
parents:
diff changeset
    17
  case '-' => "(*ptr)--;"
e4889da2fe29 updated
Christian Urban <urbanc@in.tum.de>
parents:
diff changeset
    18
  case '.' => "putchar(*ptr);"
740
923b946347e6 updated
Christian Urban <christian.urban@kcl.ac.uk>
parents: 738
diff changeset
    19
  case ',' => "*ptr = getchar();"
633
e4889da2fe29 updated
Christian Urban <urbanc@in.tum.de>
parents:
diff changeset
    20
  case '['  => "while(*ptr){"
e4889da2fe29 updated
Christian Urban <urbanc@in.tum.de>
parents:
diff changeset
    21
  case ']'  => "}"
e4889da2fe29 updated
Christian Urban <urbanc@in.tum.de>
parents:
diff changeset
    22
  case _ => ""
e4889da2fe29 updated
Christian Urban <urbanc@in.tum.de>
parents:
diff changeset
    23
}
e4889da2fe29 updated
Christian Urban <urbanc@in.tum.de>
parents:
diff changeset
    24
e4889da2fe29 updated
Christian Urban <urbanc@in.tum.de>
parents:
diff changeset
    25
def instrs(prog: String) : String =
e4889da2fe29 updated
Christian Urban <urbanc@in.tum.de>
parents:
diff changeset
    26
  prog.toList.map(instr(_)).mkString
e4889da2fe29 updated
Christian Urban <urbanc@in.tum.de>
parents:
diff changeset
    27
740
923b946347e6 updated
Christian Urban <christian.urban@kcl.ac.uk>
parents: 738
diff changeset
    28
// adding the boilerplate
923b946347e6 updated
Christian Urban <christian.urban@kcl.ac.uk>
parents: 738
diff changeset
    29
def compile(prog: String) : String = 
923b946347e6 updated
Christian Urban <christian.urban@kcl.ac.uk>
parents: 738
diff changeset
    30
  s"""#include <string.h> 
923b946347e6 updated
Christian Urban <christian.urban@kcl.ac.uk>
parents: 738
diff changeset
    31
      #include <stdio.h> 
923b946347e6 updated
Christian Urban <christian.urban@kcl.ac.uk>
parents: 738
diff changeset
    32
      char field[30000]; 
923b946347e6 updated
Christian Urban <christian.urban@kcl.ac.uk>
parents: 738
diff changeset
    33
      char *ptr = &field[15000]; 
923b946347e6 updated
Christian Urban <christian.urban@kcl.ac.uk>
parents: 738
diff changeset
    34
      int main() { 
923b946347e6 updated
Christian Urban <christian.urban@kcl.ac.uk>
parents: 738
diff changeset
    35
      memset(field, '\\0', 30000); 
923b946347e6 updated
Christian Urban <christian.urban@kcl.ac.uk>
parents: 738
diff changeset
    36
      ${instrs(prog)} 
923b946347e6 updated
Christian Urban <christian.urban@kcl.ac.uk>
parents: 738
diff changeset
    37
      return 0;}"""
633
e4889da2fe29 updated
Christian Urban <urbanc@in.tum.de>
parents:
diff changeset
    38
740
923b946347e6 updated
Christian Urban <christian.urban@kcl.ac.uk>
parents: 738
diff changeset
    39
def compile_file(name: String, prog: String) = 
923b946347e6 updated
Christian Urban <christian.urban@kcl.ac.uk>
parents: 738
diff changeset
    40
  os.write.over(os.pwd / name, compile(prog))
923b946347e6 updated
Christian Urban <christian.urban@kcl.ac.uk>
parents: 738
diff changeset
    41
923b946347e6 updated
Christian Urban <christian.urban@kcl.ac.uk>
parents: 738
diff changeset
    42
923b946347e6 updated
Christian Urban <christian.urban@kcl.ac.uk>
parents: 738
diff changeset
    43
// running the c-compiler over the transpiled
923b946347e6 updated
Christian Urban <christian.urban@kcl.ac.uk>
parents: 738
diff changeset
    44
// BF program and running the resulting binary
923b946347e6 updated
Christian Urban <christian.urban@kcl.ac.uk>
parents: 738
diff changeset
    45
923b946347e6 updated
Christian Urban <christian.urban@kcl.ac.uk>
parents: 738
diff changeset
    46
def compile_run(prog: String) = {
923b946347e6 updated
Christian Urban <christian.urban@kcl.ac.uk>
parents: 738
diff changeset
    47
  val tn = "tmp"
923b946347e6 updated
Christian Urban <christian.urban@kcl.ac.uk>
parents: 738
diff changeset
    48
  compile_file(s"${tn}.c", prog)
923b946347e6 updated
Christian Urban <christian.urban@kcl.ac.uk>
parents: 738
diff changeset
    49
  os.proc("gcc", "-O0", "-o", tn, s"${tn}.c").call() // call gcc
923b946347e6 updated
Christian Urban <christian.urban@kcl.ac.uk>
parents: 738
diff changeset
    50
  os.proc("./tmp").call(stdout = os.Inherit)         // run binary
633
e4889da2fe29 updated
Christian Urban <urbanc@in.tum.de>
parents:
diff changeset
    51
}
e4889da2fe29 updated
Christian Urban <urbanc@in.tum.de>
parents:
diff changeset
    52
740
923b946347e6 updated
Christian Urban <christian.urban@kcl.ac.uk>
parents: 738
diff changeset
    53
// Running Testcases
923b946347e6 updated
Christian Urban <christian.urban@kcl.ac.uk>
parents: 738
diff changeset
    54
//===================
633
e4889da2fe29 updated
Christian Urban <urbanc@in.tum.de>
parents:
diff changeset
    55
e4889da2fe29 updated
Christian Urban <urbanc@in.tum.de>
parents:
diff changeset
    56
def time_needed[T](n: Int, code: => T) = {
e4889da2fe29 updated
Christian Urban <urbanc@in.tum.de>
parents:
diff changeset
    57
  val start = System.nanoTime()
e4889da2fe29 updated
Christian Urban <urbanc@in.tum.de>
parents:
diff changeset
    58
  for (i <- 0 until n) code
e4889da2fe29 updated
Christian Urban <urbanc@in.tum.de>
parents:
diff changeset
    59
  val end = System.nanoTime()
e4889da2fe29 updated
Christian Urban <urbanc@in.tum.de>
parents:
diff changeset
    60
  (end - start)/(n * 1.0e9)
e4889da2fe29 updated
Christian Urban <urbanc@in.tum.de>
parents:
diff changeset
    61
}
e4889da2fe29 updated
Christian Urban <urbanc@in.tum.de>
parents:
diff changeset
    62
738
084e2843f478 updated
Christian Urban <christian dot urban at kcl dot ac dot uk>
parents: 736
diff changeset
    63
@doc(" the argument should be a BF program ")
084e2843f478 updated
Christian Urban <christian dot urban at kcl dot ac dot uk>
parents: 736
diff changeset
    64
@main
084e2843f478 updated
Christian Urban <christian dot urban at kcl dot ac dot uk>
parents: 736
diff changeset
    65
def main(fname: String) = {
084e2843f478 updated
Christian Urban <christian dot urban at kcl dot ac dot uk>
parents: 736
diff changeset
    66
  val bf_str = os.read(os.pwd / fname)
740
923b946347e6 updated
Christian Urban <christian.urban@kcl.ac.uk>
parents: 738
diff changeset
    67
  println(s"${time_needed(1, compile_run(bf_str))} secs")
738
084e2843f478 updated
Christian Urban <christian dot urban at kcl dot ac dot uk>
parents: 736
diff changeset
    68
}  
633
e4889da2fe29 updated
Christian Urban <urbanc@in.tum.de>
parents:
diff changeset
    69
e4889da2fe29 updated
Christian Urban <urbanc@in.tum.de>
parents:
diff changeset
    70
e4889da2fe29 updated
Christian Urban <urbanc@in.tum.de>
parents:
diff changeset
    71