progs/bf/bfc1.sc
author Christian Urban <christian.urban@kcl.ac.uk>
Mon, 24 Aug 2020 00:24:58 +0100
changeset 746 1779f8488689
parent 742 155426396b5f
child 825 fb9f63a22114
permissions -rw-r--r--
updated
Ignore whitespace changes - Everywhere: Within whitespace: At end of lines:
633
b7fda9e18953 updated
Christian Urban <urbanc@in.tum.de>
parents:
diff changeset
     1
// A Transpiler for the Brainf*** language
b7fda9e18953 updated
Christian Urban <urbanc@in.tum.de>
parents:
diff changeset
     2
//=========================================
740
cdfc278e37b9 updated
Christian Urban <christian.urban@kcl.ac.uk>
parents: 736
diff changeset
     3
//
cdfc278e37b9 updated
Christian Urban <christian.urban@kcl.ac.uk>
parents: 736
diff changeset
     4
// This version "optimises" the code by replacing 
742
155426396b5f updated
Christian Urban <christian.urban@kcl.ac.uk>
parents: 740
diff changeset
     5
// for example +++ by (*ptr) += 3, instead of three
155426396b5f updated
Christian Urban <christian.urban@kcl.ac.uk>
parents: 740
diff changeset
     6
// separate (*ptr)++, (*ptr)++, (*ptr)++
740
cdfc278e37b9 updated
Christian Urban <christian.urban@kcl.ac.uk>
parents: 736
diff changeset
     7
// 
cdfc278e37b9 updated
Christian Urban <christian.urban@kcl.ac.uk>
parents: 736
diff changeset
     8
// Call with
cdfc278e37b9 updated
Christian Urban <christian.urban@kcl.ac.uk>
parents: 736
diff changeset
     9
//
cdfc278e37b9 updated
Christian Urban <christian.urban@kcl.ac.uk>
parents: 736
diff changeset
    10
//  amm bfc1.sc <<bf_program.bf>>
cdfc278e37b9 updated
Christian Urban <christian.urban@kcl.ac.uk>
parents: 736
diff changeset
    11
//
633
b7fda9e18953 updated
Christian Urban <urbanc@in.tum.de>
parents:
diff changeset
    12
b7fda9e18953 updated
Christian Urban <urbanc@in.tum.de>
parents:
diff changeset
    13
742
155426396b5f updated
Christian Urban <christian.urban@kcl.ac.uk>
parents: 740
diff changeset
    14
// generate "compound" c-instructions 
633
b7fda9e18953 updated
Christian Urban <urbanc@in.tum.de>
parents:
diff changeset
    15
def instr2(c: Char, n: Int) : String = c match {
740
cdfc278e37b9 updated
Christian Urban <christian.urban@kcl.ac.uk>
parents: 736
diff changeset
    16
  case '>' => s"ptr += $n ;"
cdfc278e37b9 updated
Christian Urban <christian.urban@kcl.ac.uk>
parents: 736
diff changeset
    17
  case '<' => s"ptr -= $n ;"
cdfc278e37b9 updated
Christian Urban <christian.urban@kcl.ac.uk>
parents: 736
diff changeset
    18
  case '+' => s"(*ptr) += $n ;"
cdfc278e37b9 updated
Christian Urban <christian.urban@kcl.ac.uk>
parents: 736
diff changeset
    19
  case '-' => s"(*ptr) -= $n ;"
633
b7fda9e18953 updated
Christian Urban <urbanc@in.tum.de>
parents:
diff changeset
    20
  case '.' => "putchar(*ptr);" * n
740
cdfc278e37b9 updated
Christian Urban <christian.urban@kcl.ac.uk>
parents: 736
diff changeset
    21
  case ',' => "*ptr = getchar(); " * n
633
b7fda9e18953 updated
Christian Urban <urbanc@in.tum.de>
parents:
diff changeset
    22
  case '['  => "while(*ptr){" * n
b7fda9e18953 updated
Christian Urban <urbanc@in.tum.de>
parents:
diff changeset
    23
  case ']'  => "}" * n
b7fda9e18953 updated
Christian Urban <urbanc@in.tum.de>
parents:
diff changeset
    24
  case _ => ""
b7fda9e18953 updated
Christian Urban <urbanc@in.tum.de>
parents:
diff changeset
    25
}
b7fda9e18953 updated
Christian Urban <urbanc@in.tum.de>
parents:
diff changeset
    26
740
cdfc278e37b9 updated
Christian Urban <christian.urban@kcl.ac.uk>
parents: 736
diff changeset
    27
// "splicing" a BF program into "spans" 
cdfc278e37b9 updated
Christian Urban <christian.urban@kcl.ac.uk>
parents: 736
diff changeset
    28
// and counting the number of occurrences in
cdfc278e37b9 updated
Christian Urban <christian.urban@kcl.ac.uk>
parents: 736
diff changeset
    29
// each span; then generate the new intruction
cdfc278e37b9 updated
Christian Urban <christian.urban@kcl.ac.uk>
parents: 736
diff changeset
    30
// accordingly
633
b7fda9e18953 updated
Christian Urban <urbanc@in.tum.de>
parents:
diff changeset
    31
740
cdfc278e37b9 updated
Christian Urban <christian.urban@kcl.ac.uk>
parents: 736
diff changeset
    32
def splice(cs: List[Char], acc: List[String]) : List[String] = cs match {
cdfc278e37b9 updated
Christian Urban <christian.urban@kcl.ac.uk>
parents: 736
diff changeset
    33
  case Nil => acc
cdfc278e37b9 updated
Christian Urban <christian.urban@kcl.ac.uk>
parents: 736
diff changeset
    34
  case hd :: _ => {
cdfc278e37b9 updated
Christian Urban <christian.urban@kcl.ac.uk>
parents: 736
diff changeset
    35
    val (hds, rest) = cs.span(_ == hd)
cdfc278e37b9 updated
Christian Urban <christian.urban@kcl.ac.uk>
parents: 736
diff changeset
    36
    splice(rest, instr2(hd, hds.length) :: acc) 
cdfc278e37b9 updated
Christian Urban <christian.urban@kcl.ac.uk>
parents: 736
diff changeset
    37
  }
633
b7fda9e18953 updated
Christian Urban <urbanc@in.tum.de>
parents:
diff changeset
    38
}
b7fda9e18953 updated
Christian Urban <urbanc@in.tum.de>
parents:
diff changeset
    39
740
cdfc278e37b9 updated
Christian Urban <christian.urban@kcl.ac.uk>
parents: 736
diff changeset
    40
def instrs2(prog: String) : String =
cdfc278e37b9 updated
Christian Urban <christian.urban@kcl.ac.uk>
parents: 736
diff changeset
    41
  splice(prog.toList, Nil).reverse.mkString
cdfc278e37b9 updated
Christian Urban <christian.urban@kcl.ac.uk>
parents: 736
diff changeset
    42
742
155426396b5f updated
Christian Urban <christian.urban@kcl.ac.uk>
parents: 740
diff changeset
    43
// adding boilerplate
740
cdfc278e37b9 updated
Christian Urban <christian.urban@kcl.ac.uk>
parents: 736
diff changeset
    44
def compile(prog: String) : String = 
cdfc278e37b9 updated
Christian Urban <christian.urban@kcl.ac.uk>
parents: 736
diff changeset
    45
  s"""#include <string.h> 
cdfc278e37b9 updated
Christian Urban <christian.urban@kcl.ac.uk>
parents: 736
diff changeset
    46
      #include <stdio.h> 
746
1779f8488689 updated
Christian Urban <christian.urban@kcl.ac.uk>
parents: 742
diff changeset
    47
      int field[30000]; 
1779f8488689 updated
Christian Urban <christian.urban@kcl.ac.uk>
parents: 742
diff changeset
    48
      int *ptr = &field[15000]; 
740
cdfc278e37b9 updated
Christian Urban <christian.urban@kcl.ac.uk>
parents: 736
diff changeset
    49
      int main() { 
cdfc278e37b9 updated
Christian Urban <christian.urban@kcl.ac.uk>
parents: 736
diff changeset
    50
      memset(field, '\\0', 30000); 
cdfc278e37b9 updated
Christian Urban <christian.urban@kcl.ac.uk>
parents: 736
diff changeset
    51
      ${instrs2(prog)} 
cdfc278e37b9 updated
Christian Urban <christian.urban@kcl.ac.uk>
parents: 736
diff changeset
    52
      return 0;}"""
cdfc278e37b9 updated
Christian Urban <christian.urban@kcl.ac.uk>
parents: 736
diff changeset
    53
742
155426396b5f updated
Christian Urban <christian.urban@kcl.ac.uk>
parents: 740
diff changeset
    54
def compile_to_file(name: String, prog: String) = 
740
cdfc278e37b9 updated
Christian Urban <christian.urban@kcl.ac.uk>
parents: 736
diff changeset
    55
  os.write.over(os.pwd / name, compile(prog))
cdfc278e37b9 updated
Christian Urban <christian.urban@kcl.ac.uk>
parents: 736
diff changeset
    56
cdfc278e37b9 updated
Christian Urban <christian.urban@kcl.ac.uk>
parents: 736
diff changeset
    57
cdfc278e37b9 updated
Christian Urban <christian.urban@kcl.ac.uk>
parents: 736
diff changeset
    58
// running the c-compiler over the transpiled
cdfc278e37b9 updated
Christian Urban <christian.urban@kcl.ac.uk>
parents: 736
diff changeset
    59
// BF program and running the resulting binary
cdfc278e37b9 updated
Christian Urban <christian.urban@kcl.ac.uk>
parents: 736
diff changeset
    60
742
155426396b5f updated
Christian Urban <christian.urban@kcl.ac.uk>
parents: 740
diff changeset
    61
def compile_and_run(prog: String) = {
740
cdfc278e37b9 updated
Christian Urban <christian.urban@kcl.ac.uk>
parents: 736
diff changeset
    62
  val tn = "tmp"
742
155426396b5f updated
Christian Urban <christian.urban@kcl.ac.uk>
parents: 740
diff changeset
    63
  compile_to_file(s"${tn}.c", prog)
740
cdfc278e37b9 updated
Christian Urban <christian.urban@kcl.ac.uk>
parents: 736
diff changeset
    64
  os.proc("gcc", "-O0", "-o", tn, s"${tn}.c").call() // call gcc
cdfc278e37b9 updated
Christian Urban <christian.urban@kcl.ac.uk>
parents: 736
diff changeset
    65
  os.proc("./tmp").call(stdout = os.Inherit)         // run binary
633
b7fda9e18953 updated
Christian Urban <urbanc@in.tum.de>
parents:
diff changeset
    66
}
b7fda9e18953 updated
Christian Urban <urbanc@in.tum.de>
parents:
diff changeset
    67
740
cdfc278e37b9 updated
Christian Urban <christian.urban@kcl.ac.uk>
parents: 736
diff changeset
    68
// Running Testcases
cdfc278e37b9 updated
Christian Urban <christian.urban@kcl.ac.uk>
parents: 736
diff changeset
    69
//===================
633
b7fda9e18953 updated
Christian Urban <urbanc@in.tum.de>
parents:
diff changeset
    70
b7fda9e18953 updated
Christian Urban <urbanc@in.tum.de>
parents:
diff changeset
    71
def time_needed[T](n: Int, code: => T) = {
b7fda9e18953 updated
Christian Urban <urbanc@in.tum.de>
parents:
diff changeset
    72
  val start = System.nanoTime()
b7fda9e18953 updated
Christian Urban <urbanc@in.tum.de>
parents:
diff changeset
    73
  for (i <- 0 until n) code
b7fda9e18953 updated
Christian Urban <urbanc@in.tum.de>
parents:
diff changeset
    74
  val end = System.nanoTime()
740
cdfc278e37b9 updated
Christian Urban <christian.urban@kcl.ac.uk>
parents: 736
diff changeset
    75
  (end - start)/(n * 1.0e9)
633
b7fda9e18953 updated
Christian Urban <urbanc@in.tum.de>
parents:
diff changeset
    76
}
b7fda9e18953 updated
Christian Urban <urbanc@in.tum.de>
parents:
diff changeset
    77
740
cdfc278e37b9 updated
Christian Urban <christian.urban@kcl.ac.uk>
parents: 736
diff changeset
    78
@doc(" the argument should be a BF program ")
cdfc278e37b9 updated
Christian Urban <christian.urban@kcl.ac.uk>
parents: 736
diff changeset
    79
@main
cdfc278e37b9 updated
Christian Urban <christian.urban@kcl.ac.uk>
parents: 736
diff changeset
    80
def main(fname: String) = {
cdfc278e37b9 updated
Christian Urban <christian.urban@kcl.ac.uk>
parents: 736
diff changeset
    81
  val bf_str = os.read(os.pwd / fname)
742
155426396b5f updated
Christian Urban <christian.urban@kcl.ac.uk>
parents: 740
diff changeset
    82
  println(s"${time_needed(1, compile_and_run(bf_str))} secs")
740
cdfc278e37b9 updated
Christian Urban <christian.urban@kcl.ac.uk>
parents: 736
diff changeset
    83
}  
633
b7fda9e18953 updated
Christian Urban <urbanc@in.tum.de>
parents:
diff changeset
    84