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-- |
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 | 8 |
// |
9 |
// Note: An interesting exercise is to call |
|
742 | 10 |
// gcc with -O3 instead of -O0 (see invocation |
11 |
// below). |
|
12 |
||
633 | 13 |
|
14 |
// simple instructions |
|
15 |
def instr(c: Char) : String = c match { |
|
16 |
case '>' => "ptr++;" |
|
17 |
case '<' => "ptr--;" |
|
18 |
case '+' => "(*ptr)++;" |
|
19 |
case '-' => "(*ptr)--;" |
|
20 |
case '.' => "putchar(*ptr);" |
|
740 | 21 |
case ',' => "*ptr = getchar();" |
633 | 22 |
case '[' => "while(*ptr){" |
23 |
case ']' => "}" |
|
24 |
case _ => "" |
|
25 |
} |
|
26 |
||
27 |
def instrs(prog: String) : String = |
|
28 |
prog.toList.map(instr(_)).mkString |
|
29 |
||
742 | 30 |
// adding boilerplate |
740 | 31 |
def compile(prog: String) : String = |
32 |
s"""#include <string.h> |
|
33 |
#include <stdio.h> |
|
746 | 34 |
int field[30000]; |
35 |
int *ptr = &field[15000]; |
|
740 | 36 |
int main() { |
37 |
memset(field, '\\0', 30000); |
|
38 |
${instrs(prog)} |
|
39 |
return 0;}""" |
|
633 | 40 |
|
742 | 41 |
|
42 |
def compile_to_file(name: String, prog: String) = |
|
740 | 43 |
os.write.over(os.pwd / name, compile(prog)) |
44 |
||
45 |
||
46 |
// running the c-compiler over the transpiled |
|
47 |
// BF program and running the resulting binary |
|
48 |
||
742 | 49 |
def compile_and_run(prog: String) = { |
740 | 50 |
val tn = "tmp" |
742 | 51 |
compile_to_file(s"${tn}.c", prog) |
740 | 52 |
os.proc("gcc", "-O0", "-o", tn, s"${tn}.c").call() // call gcc |
53 |
os.proc("./tmp").call(stdout = os.Inherit) // run binary |
|
633 | 54 |
} |
55 |
||
740 | 56 |
// Running Testcases |
57 |
//=================== |
|
633 | 58 |
|
59 |
def time_needed[T](n: Int, code: => T) = { |
|
60 |
val start = System.nanoTime() |
|
61 |
for (i <- 0 until n) code |
|
62 |
val end = System.nanoTime() |
|
63 |
(end - start)/(n * 1.0e9) |
|
64 |
} |
|
65 |
||
825 | 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 | 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 | 72 |
|
73 |
||
74 |