progs/bf/bfc0.sc
author Christian Urban <christian.urban@kcl.ac.uk>
Wed, 06 Oct 2021 20:43:35 +0100
changeset 842 b53ac1bb5f43
parent 825 dca072e2bb7d
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
742
b5b5583a3a08 updated
Christian Urban <christian.urban@kcl.ac.uk>
parents: 740
diff changeset
    10
// gcc with -O3 instead of -O0 (see invocation
b5b5583a3a08 updated
Christian Urban <christian.urban@kcl.ac.uk>
parents: 740
diff changeset
    11
// below).
b5b5583a3a08 updated
Christian Urban <christian.urban@kcl.ac.uk>
parents: 740
diff changeset
    12
633
e4889da2fe29 updated
Christian Urban <urbanc@in.tum.de>
parents:
diff changeset
    13
e4889da2fe29 updated
Christian Urban <urbanc@in.tum.de>
parents:
diff changeset
    14
// simple instructions
e4889da2fe29 updated
Christian Urban <urbanc@in.tum.de>
parents:
diff changeset
    15
def instr(c: Char) : String = c match {
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 '+' => "(*ptr)++;"
e4889da2fe29 updated
Christian Urban <urbanc@in.tum.de>
parents:
diff changeset
    19
  case '-' => "(*ptr)--;"
e4889da2fe29 updated
Christian Urban <urbanc@in.tum.de>
parents:
diff changeset
    20
  case '.' => "putchar(*ptr);"
740
923b946347e6 updated
Christian Urban <christian.urban@kcl.ac.uk>
parents: 738
diff changeset
    21
  case ',' => "*ptr = getchar();"
633
e4889da2fe29 updated
Christian Urban <urbanc@in.tum.de>
parents:
diff changeset
    22
  case '['  => "while(*ptr){"
e4889da2fe29 updated
Christian Urban <urbanc@in.tum.de>
parents:
diff changeset
    23
  case ']'  => "}"
e4889da2fe29 updated
Christian Urban <urbanc@in.tum.de>
parents:
diff changeset
    24
  case _ => ""
e4889da2fe29 updated
Christian Urban <urbanc@in.tum.de>
parents:
diff changeset
    25
}
e4889da2fe29 updated
Christian Urban <urbanc@in.tum.de>
parents:
diff changeset
    26
e4889da2fe29 updated
Christian Urban <urbanc@in.tum.de>
parents:
diff changeset
    27
def instrs(prog: String) : String =
e4889da2fe29 updated
Christian Urban <urbanc@in.tum.de>
parents:
diff changeset
    28
  prog.toList.map(instr(_)).mkString
e4889da2fe29 updated
Christian Urban <urbanc@in.tum.de>
parents:
diff changeset
    29
742
b5b5583a3a08 updated
Christian Urban <christian.urban@kcl.ac.uk>
parents: 740
diff changeset
    30
// adding boilerplate
740
923b946347e6 updated
Christian Urban <christian.urban@kcl.ac.uk>
parents: 738
diff changeset
    31
def compile(prog: String) : String = 
923b946347e6 updated
Christian Urban <christian.urban@kcl.ac.uk>
parents: 738
diff changeset
    32
  s"""#include <string.h> 
923b946347e6 updated
Christian Urban <christian.urban@kcl.ac.uk>
parents: 738
diff changeset
    33
      #include <stdio.h> 
746
6916229b817b updated
Christian Urban <christian.urban@kcl.ac.uk>
parents: 742
diff changeset
    34
      int field[30000]; 
6916229b817b updated
Christian Urban <christian.urban@kcl.ac.uk>
parents: 742
diff changeset
    35
      int *ptr = &field[15000]; 
740
923b946347e6 updated
Christian Urban <christian.urban@kcl.ac.uk>
parents: 738
diff changeset
    36
      int main() { 
923b946347e6 updated
Christian Urban <christian.urban@kcl.ac.uk>
parents: 738
diff changeset
    37
      memset(field, '\\0', 30000); 
923b946347e6 updated
Christian Urban <christian.urban@kcl.ac.uk>
parents: 738
diff changeset
    38
      ${instrs(prog)} 
923b946347e6 updated
Christian Urban <christian.urban@kcl.ac.uk>
parents: 738
diff changeset
    39
      return 0;}"""
633
e4889da2fe29 updated
Christian Urban <urbanc@in.tum.de>
parents:
diff changeset
    40
742
b5b5583a3a08 updated
Christian Urban <christian.urban@kcl.ac.uk>
parents: 740
diff changeset
    41
b5b5583a3a08 updated
Christian Urban <christian.urban@kcl.ac.uk>
parents: 740
diff changeset
    42
def compile_to_file(name: String, prog: String) = 
740
923b946347e6 updated
Christian Urban <christian.urban@kcl.ac.uk>
parents: 738
diff changeset
    43
  os.write.over(os.pwd / name, compile(prog))
923b946347e6 updated
Christian Urban <christian.urban@kcl.ac.uk>
parents: 738
diff changeset
    44
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
// running the c-compiler over the transpiled
923b946347e6 updated
Christian Urban <christian.urban@kcl.ac.uk>
parents: 738
diff changeset
    47
// BF program and running the resulting binary
923b946347e6 updated
Christian Urban <christian.urban@kcl.ac.uk>
parents: 738
diff changeset
    48
742
b5b5583a3a08 updated
Christian Urban <christian.urban@kcl.ac.uk>
parents: 740
diff changeset
    49
def compile_and_run(prog: String) = {
740
923b946347e6 updated
Christian Urban <christian.urban@kcl.ac.uk>
parents: 738
diff changeset
    50
  val tn = "tmp"
742
b5b5583a3a08 updated
Christian Urban <christian.urban@kcl.ac.uk>
parents: 740
diff changeset
    51
  compile_to_file(s"${tn}.c", prog)
740
923b946347e6 updated
Christian Urban <christian.urban@kcl.ac.uk>
parents: 738
diff changeset
    52
  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
    53
  os.proc("./tmp").call(stdout = os.Inherit)         // run binary
633
e4889da2fe29 updated
Christian Urban <urbanc@in.tum.de>
parents:
diff changeset
    54
}
e4889da2fe29 updated
Christian Urban <urbanc@in.tum.de>
parents:
diff changeset
    55
740
923b946347e6 updated
Christian Urban <christian.urban@kcl.ac.uk>
parents: 738
diff changeset
    56
// Running Testcases
923b946347e6 updated
Christian Urban <christian.urban@kcl.ac.uk>
parents: 738
diff changeset
    57
//===================
633
e4889da2fe29 updated
Christian Urban <urbanc@in.tum.de>
parents:
diff changeset
    58
e4889da2fe29 updated
Christian Urban <urbanc@in.tum.de>
parents:
diff changeset
    59
def time_needed[T](n: Int, code: => T) = {
e4889da2fe29 updated
Christian Urban <urbanc@in.tum.de>
parents:
diff changeset
    60
  val start = System.nanoTime()
e4889da2fe29 updated
Christian Urban <urbanc@in.tum.de>
parents:
diff changeset
    61
  for (i <- 0 until n) code
e4889da2fe29 updated
Christian Urban <urbanc@in.tum.de>
parents:
diff changeset
    62
  val end = System.nanoTime()
e4889da2fe29 updated
Christian Urban <urbanc@in.tum.de>
parents:
diff changeset
    63
  (end - start)/(n * 1.0e9)
e4889da2fe29 updated
Christian Urban <urbanc@in.tum.de>
parents:
diff changeset
    64
}
e4889da2fe29 updated
Christian Urban <urbanc@in.tum.de>
parents:
diff changeset
    65
825
dca072e2bb7d updated
Christian Urban <christian.urban@kcl.ac.uk>
parents: 746
diff changeset
    66
//@doc(" the argument should be a BF program ")
738
084e2843f478 updated
Christian Urban <christian dot urban at kcl dot ac dot uk>
parents: 736
diff changeset
    67
@main
084e2843f478 updated
Christian Urban <christian dot urban at kcl dot ac dot uk>
parents: 736
diff changeset
    68
def main(fname: String) = {
084e2843f478 updated
Christian Urban <christian dot urban at kcl dot ac dot uk>
parents: 736
diff changeset
    69
  val bf_str = os.read(os.pwd / fname)
742
b5b5583a3a08 updated
Christian Urban <christian.urban@kcl.ac.uk>
parents: 740
diff changeset
    70
  println(s"${time_needed(1, compile_and_run(bf_str))} secs")
738
084e2843f478 updated
Christian Urban <christian dot urban at kcl dot ac dot uk>
parents: 736
diff changeset
    71
}  
633
e4889da2fe29 updated
Christian Urban <urbanc@in.tum.de>
parents:
diff changeset
    72
e4889da2fe29 updated
Christian Urban <urbanc@in.tum.de>
parents:
diff changeset
    73
e4889da2fe29 updated
Christian Urban <urbanc@in.tum.de>
parents:
diff changeset
    74