progs/bf/bfc0.sc
author Christian Urban <christian.urban@kcl.ac.uk>
Fri, 24 Oct 2025 11:26:43 +0100
changeset 1018 fd6a64c53f0e
parent 990 8cb2e171d952
permissions -rw-r--r--
updated
Ignore whitespace changes - Everywhere: Within whitespace: At end of lines:
738
03f46065ef04 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
03f46065ef04 updated
Christian Urban <christian dot urban at kcl dot ac dot uk>
parents: 736
diff changeset
     2
//===============================================
03f46065ef04 updated
Christian Urban <christian dot urban at kcl dot ac dot uk>
parents: 736
diff changeset
     3
//
03f46065ef04 updated
Christian Urban <christian dot urban at kcl dot ac dot uk>
parents: 736
diff changeset
     4
// Call with
03f46065ef04 updated
Christian Urban <christian dot urban at kcl dot ac dot uk>
parents: 736
diff changeset
     5
//
03f46065ef04 updated
Christian Urban <christian dot urban at kcl dot ac dot uk>
parents: 736
diff changeset
     6
//  amm bfc0.sc <<bf_program.bf>>
03f46065ef04 updated
Christian Urban <christian dot urban at kcl dot ac dot uk>
parents: 736
diff changeset
     7
//
740
cdfc278e37b9 updated
Christian Urban <christian.urban@kcl.ac.uk>
parents: 738
diff changeset
     8
//
cdfc278e37b9 updated
Christian Urban <christian.urban@kcl.ac.uk>
parents: 738
diff changeset
     9
// Note: An interesting exercise is to call
742
155426396b5f updated
Christian Urban <christian.urban@kcl.ac.uk>
parents: 740
diff changeset
    10
// gcc with -O3 instead of -O0 (see invocation
155426396b5f updated
Christian Urban <christian.urban@kcl.ac.uk>
parents: 740
diff changeset
    11
// below).
155426396b5f updated
Christian Urban <christian.urban@kcl.ac.uk>
parents: 740
diff changeset
    12
633
b7fda9e18953 updated
Christian Urban <urbanc@in.tum.de>
parents:
diff changeset
    13
b7fda9e18953 updated
Christian Urban <urbanc@in.tum.de>
parents:
diff changeset
    14
// simple instructions
b7fda9e18953 updated
Christian Urban <urbanc@in.tum.de>
parents:
diff changeset
    15
def instr(c: Char) : String = c match {
b7fda9e18953 updated
Christian Urban <urbanc@in.tum.de>
parents:
diff changeset
    16
  case '>' => "ptr++;"
b7fda9e18953 updated
Christian Urban <urbanc@in.tum.de>
parents:
diff changeset
    17
  case '<' => "ptr--;"
b7fda9e18953 updated
Christian Urban <urbanc@in.tum.de>
parents:
diff changeset
    18
  case '+' => "(*ptr)++;"
b7fda9e18953 updated
Christian Urban <urbanc@in.tum.de>
parents:
diff changeset
    19
  case '-' => "(*ptr)--;"
b7fda9e18953 updated
Christian Urban <urbanc@in.tum.de>
parents:
diff changeset
    20
  case '.' => "putchar(*ptr);"
740
cdfc278e37b9 updated
Christian Urban <christian.urban@kcl.ac.uk>
parents: 738
diff changeset
    21
  case ',' => "*ptr = getchar();"
633
b7fda9e18953 updated
Christian Urban <urbanc@in.tum.de>
parents:
diff changeset
    22
  case '['  => "while(*ptr){"
b7fda9e18953 updated
Christian Urban <urbanc@in.tum.de>
parents:
diff changeset
    23
  case ']'  => "}"
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
b7fda9e18953 updated
Christian Urban <urbanc@in.tum.de>
parents:
diff changeset
    27
def instrs(prog: String) : String =
b7fda9e18953 updated
Christian Urban <urbanc@in.tum.de>
parents:
diff changeset
    28
  prog.toList.map(instr(_)).mkString
b7fda9e18953 updated
Christian Urban <urbanc@in.tum.de>
parents:
diff changeset
    29
742
155426396b5f updated
Christian Urban <christian.urban@kcl.ac.uk>
parents: 740
diff changeset
    30
// adding boilerplate
740
cdfc278e37b9 updated
Christian Urban <christian.urban@kcl.ac.uk>
parents: 738
diff changeset
    31
def compile(prog: String) : String = 
cdfc278e37b9 updated
Christian Urban <christian.urban@kcl.ac.uk>
parents: 738
diff changeset
    32
  s"""#include <string.h> 
cdfc278e37b9 updated
Christian Urban <christian.urban@kcl.ac.uk>
parents: 738
diff changeset
    33
      #include <stdio.h> 
746
1779f8488689 updated
Christian Urban <christian.urban@kcl.ac.uk>
parents: 742
diff changeset
    34
      int field[30000]; 
1779f8488689 updated
Christian Urban <christian.urban@kcl.ac.uk>
parents: 742
diff changeset
    35
      int *ptr = &field[15000]; 
740
cdfc278e37b9 updated
Christian Urban <christian.urban@kcl.ac.uk>
parents: 738
diff changeset
    36
      int main() { 
cdfc278e37b9 updated
Christian Urban <christian.urban@kcl.ac.uk>
parents: 738
diff changeset
    37
      memset(field, '\\0', 30000); 
cdfc278e37b9 updated
Christian Urban <christian.urban@kcl.ac.uk>
parents: 738
diff changeset
    38
      ${instrs(prog)} 
cdfc278e37b9 updated
Christian Urban <christian.urban@kcl.ac.uk>
parents: 738
diff changeset
    39
      return 0;}"""
633
b7fda9e18953 updated
Christian Urban <urbanc@in.tum.de>
parents:
diff changeset
    40
742
155426396b5f updated
Christian Urban <christian.urban@kcl.ac.uk>
parents: 740
diff changeset
    41
155426396b5f updated
Christian Urban <christian.urban@kcl.ac.uk>
parents: 740
diff changeset
    42
def compile_to_file(name: String, prog: String) = 
740
cdfc278e37b9 updated
Christian Urban <christian.urban@kcl.ac.uk>
parents: 738
diff changeset
    43
  os.write.over(os.pwd / name, compile(prog))
cdfc278e37b9 updated
Christian Urban <christian.urban@kcl.ac.uk>
parents: 738
diff changeset
    44
cdfc278e37b9 updated
Christian Urban <christian.urban@kcl.ac.uk>
parents: 738
diff changeset
    45
cdfc278e37b9 updated
Christian Urban <christian.urban@kcl.ac.uk>
parents: 738
diff changeset
    46
// running the c-compiler over the transpiled
cdfc278e37b9 updated
Christian Urban <christian.urban@kcl.ac.uk>
parents: 738
diff changeset
    47
// BF program and running the resulting binary
cdfc278e37b9 updated
Christian Urban <christian.urban@kcl.ac.uk>
parents: 738
diff changeset
    48
742
155426396b5f updated
Christian Urban <christian.urban@kcl.ac.uk>
parents: 740
diff changeset
    49
def compile_and_run(prog: String) = {
990
8cb2e171d952 updated
Christian Urban <christian.urban@kcl.ac.uk>
parents: 825
diff changeset
    50
  val hash = java.util.UUID.randomUUID().toString.take(4)
8cb2e171d952 updated
Christian Urban <christian.urban@kcl.ac.uk>
parents: 825
diff changeset
    51
  val tn = s"tmp_$hash"
742
155426396b5f updated
Christian Urban <christian.urban@kcl.ac.uk>
parents: 740
diff changeset
    52
  compile_to_file(s"${tn}.c", prog)
740
cdfc278e37b9 updated
Christian Urban <christian.urban@kcl.ac.uk>
parents: 738
diff changeset
    53
  os.proc("gcc", "-O0", "-o", tn, s"${tn}.c").call() // call gcc
990
8cb2e171d952 updated
Christian Urban <christian.urban@kcl.ac.uk>
parents: 825
diff changeset
    54
  os.proc(os.pwd / s"${tn}").call(stdout = os.Inherit)         // run binary
633
b7fda9e18953 updated
Christian Urban <urbanc@in.tum.de>
parents:
diff changeset
    55
}
b7fda9e18953 updated
Christian Urban <urbanc@in.tum.de>
parents:
diff changeset
    56
740
cdfc278e37b9 updated
Christian Urban <christian.urban@kcl.ac.uk>
parents: 738
diff changeset
    57
// Running Testcases
cdfc278e37b9 updated
Christian Urban <christian.urban@kcl.ac.uk>
parents: 738
diff changeset
    58
//===================
633
b7fda9e18953 updated
Christian Urban <urbanc@in.tum.de>
parents:
diff changeset
    59
b7fda9e18953 updated
Christian Urban <urbanc@in.tum.de>
parents:
diff changeset
    60
def time_needed[T](n: Int, code: => T) = {
b7fda9e18953 updated
Christian Urban <urbanc@in.tum.de>
parents:
diff changeset
    61
  val start = System.nanoTime()
b7fda9e18953 updated
Christian Urban <urbanc@in.tum.de>
parents:
diff changeset
    62
  for (i <- 0 until n) code
b7fda9e18953 updated
Christian Urban <urbanc@in.tum.de>
parents:
diff changeset
    63
  val end = System.nanoTime()
b7fda9e18953 updated
Christian Urban <urbanc@in.tum.de>
parents:
diff changeset
    64
  (end - start)/(n * 1.0e9)
b7fda9e18953 updated
Christian Urban <urbanc@in.tum.de>
parents:
diff changeset
    65
}
b7fda9e18953 updated
Christian Urban <urbanc@in.tum.de>
parents:
diff changeset
    66
825
fb9f63a22114 updated
Christian Urban <christian.urban@kcl.ac.uk>
parents: 746
diff changeset
    67
//@doc(" the argument should be a BF program ")
738
03f46065ef04 updated
Christian Urban <christian dot urban at kcl dot ac dot uk>
parents: 736
diff changeset
    68
@main
03f46065ef04 updated
Christian Urban <christian dot urban at kcl dot ac dot uk>
parents: 736
diff changeset
    69
def main(fname: String) = {
03f46065ef04 updated
Christian Urban <christian dot urban at kcl dot ac dot uk>
parents: 736
diff changeset
    70
  val bf_str = os.read(os.pwd / fname)
742
155426396b5f updated
Christian Urban <christian.urban@kcl.ac.uk>
parents: 740
diff changeset
    71
  println(s"${time_needed(1, compile_and_run(bf_str))} secs")
738
03f46065ef04 updated
Christian Urban <christian dot urban at kcl dot ac dot uk>
parents: 736
diff changeset
    72
}  
633
b7fda9e18953 updated
Christian Urban <urbanc@in.tum.de>
parents:
diff changeset
    73
b7fda9e18953 updated
Christian Urban <urbanc@in.tum.de>
parents:
diff changeset
    74
b7fda9e18953 updated
Christian Urban <urbanc@in.tum.de>
parents:
diff changeset
    75