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