11 // * 65k for the transpiled WHILE program |
11 // * 65k for the transpiled WHILE program |
12 // * parsing uses around 30 secs using fastparse |
12 // * parsing uses around 30 secs using fastparse |
13 // * the jasmin assembly file is 236k |
13 // * the jasmin assembly file is 236k |
14 // * the resulting Java program takes about 20 secs |
14 // * the resulting Java program takes about 20 secs |
15 // |
15 // |
16 // Call with (X being 0,1,..,4) |
16 // |
17 // |
17 // Call with scala-cli: |
18 // amm compile_bfc.sc all |
18 // |
19 // amm compile_bfc.sc bfcX |
19 // scala-cli --dep com.lihaoyi::fastparse:3.0.2 compile_bfc.sc |
20 |
20 // |
21 |
21 // Scala-cli is another REPL for scala. Unfortunately |
22 // load the compiler |
22 // fastparse used in this file is not yet supported |
23 import $file.compile_arrays2 |
23 // under ammonite. |
24 import compile_arrays2._ |
24 |
|
25 |
|
26 //> using toolkit latest |
|
27 //> using file compile_arrays2.sc |
|
28 import compile_arrays2._ |
25 |
29 |
26 def time_needed[T](i: Int, code: => T) = { |
30 def time_needed[T](i: Int, code: => T) = { |
27 val start = System.nanoTime() |
31 val start = System.nanoTime() |
28 for (j <- 2 to i) code |
32 for (j <- 2 to i) code |
29 val result = code |
33 val result = code |
70 // post 2.5.0 ammonite |
74 // post 2.5.0 ammonite |
71 import os._ |
75 import os._ |
72 |
76 |
73 |
77 |
74 def compile_to_file(bl: Block, class_name: String) : Unit = |
78 def compile_to_file(bl: Block, class_name: String) : Unit = |
75 write.over(pwd / s"$class_name.j", compile(bl, class_name)) |
79 os.write.over(os.pwd / s"$class_name.j", compile(bl, class_name)) |
76 |
80 |
77 def compile_and_run(bl: Block, class_name: String) : Unit = { |
81 def compile_and_run(bl: Block, class_name: String) : Unit = { |
78 println(s"Start of compilation") |
82 println(s"Start of compilation") |
79 compile_to_file(bl, class_name) |
83 compile_to_file(bl, class_name) |
80 println(s"generated $class_name.j file") |
84 println(s"generated $class_name.j file") |
90 |
94 |
91 //===================================== |
95 //===================================== |
92 // Grammar Rules for WHILE with arrays |
96 // Grammar Rules for WHILE with arrays |
93 //===================================== |
97 //===================================== |
94 |
98 |
95 import $ivy.`com.lihaoyi::fastparse:3.0.2` |
99 //> using dep com.lihaoyi::fastparse:3.0.2 |
|
100 |
96 import fastparse._ |
101 import fastparse._ |
97 import MultiLineWhitespace._ |
102 import MultiLineWhitespace._ |
98 |
103 |
99 def string[A: P]: P[String] = P(CharIn("a-zA-Z0-9").rep(1).!) |
|
100 |
|
101 /* |
|
102 def lowercase [$ : P] = P( CharIn("a-z") ) |
104 def lowercase [$ : P] = P( CharIn("a-z") ) |
103 def uppercase[$ : P] = P( CharIn("A-Z") ) |
105 def uppercase[$ : P] = P( CharIn("A-Z") ) |
104 def letter[$ : P] = P( lowercase | uppercase ) |
106 def letter[$ : P] = P( lowercase | uppercase ) |
105 def digit [$ : P] = P( CharIn("0-9") ) |
107 def digit [$ : P] = P( CharIn("0-9") ) |
106 |
108 |
115 def Te[$ : P]: P[AExp] = |
117 def Te[$ : P]: P[AExp] = |
116 P( P(Fa ~ "*" ~ Te).map{ case (l, r) => Aop("*", l, r)} |
118 P( P(Fa ~ "*" ~ Te).map{ case (l, r) => Aop("*", l, r)} |
117 | Fa ) |
119 | Fa ) |
118 def Fa[$ : P]: P[AExp] = |
120 def Fa[$ : P]: P[AExp] = |
119 P( "(" ~ AExp ~ ")" |
121 P( "(" ~ AExp ~ ")" |
120 | P (Ident ~ "[" ~ AExp ~ "]").map{Ref.tupled} |
122 | P (Ident ~ "[" ~ AExp ~ "]").map{Ref(_, _)} |
121 | P(Number).map{Num} |
123 | P(Number).map{Num} |
122 | P(Ident).map{Var} ) |
124 | P(Ident).map{Var} ) |
123 |
125 |
124 // boolean expressions |
126 // boolean expressions |
125 def BExp[$ : P]: P[BExp] = |
127 def BExp[$ : P]: P[BExp] = |
132 | "(" ~ BExp ~ ")" ) |
134 | "(" ~ BExp ~ ")" ) |
133 |
135 |
134 // statements and blocks |
136 // statements and blocks |
135 def Stmt[$ : P]: P[Stmt] = |
137 def Stmt[$ : P]: P[Stmt] = |
136 P( P("skip").map( _ => Skip) |
138 P( P("skip").map( _ => Skip) |
137 | P(Ident ~ ":=" ~ AExp).map{Assign.tupled} |
139 | P(Ident ~ ":=" ~ AExp).map{Assign(_, _)} |
138 | P(Ident ~ "[" ~ AExp ~ "]" ~ ":=" ~ AExp).map{AssignA.tupled} |
140 | P(Ident ~ "[" ~ AExp ~ "]" ~ ":=" ~ AExp).map{AssignA(_, _, _)} |
139 | P("if" ~ BExp ~ "then" ~ Block ~ "else" ~ Block).map{If.tupled} |
141 | P("if" ~ BExp ~ "then" ~ Block ~ "else" ~ Block).map{If(_, _, _)} |
140 | P("while" ~ BExp ~ "do" ~ Block).map{While.tupled} |
142 | P("while" ~ BExp ~ "do" ~ Block).map{While(_, _)} |
141 | P("new(" ~ Ident ~ "[" ~ Number ~ "])").map{ArrayDef.tupled} |
143 | P("new(" ~ Ident ~ "[" ~ Number ~ "])").map{ArrayDef(_, _)} |
142 | P("write(" ~ Ident ~ ")").map{Write} ) |
144 | P("write(" ~ Ident ~ ")").map{Write} ) |
143 |
145 |
144 def Stmts[$ : P]: P[Block] = |
146 def Stmts[$ : P]: P[Block] = |
145 P( P(Stmt ~ ";" ~ Stmts).map{ case (x, z) => x :: z } |
147 P( P(Stmt ~ ";" ~ Stmts).map{ case (x, z) => x :: z } |
146 | P(Stmt).map{s => List(s)} ) |
148 | P(Stmt).map{s => List(s)} ) |
257 compile_and_run(bf_prog, name) |
259 compile_and_run(bf_prog, name) |
258 } |
260 } |
259 |
261 |
260 // a benchmark program (counts down from 'Z' to 'A') |
262 // a benchmark program (counts down from 'Z' to 'A') |
261 //@doc(" Benchmark 'Z' to 'A'.") |
263 //@doc(" Benchmark 'Z' to 'A'.") |
262 @main |
264 //@main |
263 def bfc0() = bf_run(read(pwd / "benchmark.bf"), "bench") |
265 def bfc0() = bf_run(read(pwd / "benchmark.bf"), "bench") |
264 |
266 |
265 |
267 |
266 //@doc(" Sierpinski triangle.") |
268 //@doc(" Sierpinski triangle.") |
267 @main |
269 //@main |
268 def bfc1() = bf_run(read(pwd / "sierpinski.bf"), "sier") |
270 def bfc1() = bf_run(read(pwd / "sierpinski.bf"), "sier") |
269 |
271 |
270 // Hello World |
272 // Hello World |
271 val bf2 = """++++++++[>++++[>++>+++>+++>+<<<<-]>+>+>->>+[<]<-] |
273 val bf2 = """++++++++[>++++[>++>+++>+++>+<<<<-]>+>+>->>+[<]<-] |
272 >>.>---.+++++++..+++.>>.<-.<.+++.------.--------.>>+.>++.""" |
274 >>.>---.+++++++..+++.>>.<-.<.+++.------.--------.>>+.>++.""" |
273 |
275 |
274 //@doc(" Hello world.") |
276 //@doc(" Hello world.") |
275 @main |
277 //@main |
276 def bfc2() = bf_run(bf2, "hello") |
278 def bfc2() = bf_run(bf2, "hello") |
277 |
279 |
278 // Fibonacci |
280 // Fibonacci |
279 val bf3 = """+++++++++++ |
281 val bf3 = """+++++++++++ |
280 >+>>>>++++++++++++++++++++++++++++++++++++++++++++ |
282 >+>>>>++++++++++++++++++++++++++++++++++++++++++++ |
288 <<<<<<<<<<[>>>+>+<<<<-]>>>>[<<<<+>>>>-]<-[>>.>.<<< |
290 <<<<<<<<<<[>>>+>+<<<<-]>>>>[<<<<+>>>>-]<-[>>.>.<<< |
289 [-]]<<[>>+>+<<<-]>>>[<<<+>>>-]<<[<+>-]>[<+>-]<<<-] |
291 [-]]<<[>>+>+<<<-]>>>[<<<+>>>-]<<[<+>-]>[<+>-]<<<-] |
290 [-]++++++++++.""" |
292 [-]++++++++++.""" |
291 |
293 |
292 //@doc(" Fibonacci numbers.") |
294 //@doc(" Fibonacci numbers.") |
293 @main |
295 //@main |
294 def bfc3() = bf_run(bf3, "fibs") |
296 def bfc3() = bf_run(bf3, "fibs") |
295 |
297 |
296 // Mandelbrot Set |
298 // Mandelbrot Set |
297 //---------------- |
299 //---------------- |
298 // |
300 // |
299 // Note: Parsing of the generated WHILE program (around 60K in size) |
301 // Note: Parsing of the generated WHILE program (around 60K in size) |
300 // takes approximately 10 minutes to parse with our parser combinators, |
302 // takes approximately 10 minutes to parse with our parser combinators, |
301 // and approximately 30 seconds with Ammonite's fastparse. |
303 // and approximately 30 seconds with Ammonite's fastparse. |
302 |
304 |
303 //@doc(" Mandelbrot set.") |
305 //@doc(" Mandelbrot set.") |
304 @main |
306 //@main |
305 def bfc4() = bf_run(read(pwd / "mandelbrot.bf"), "mandelbrot") |
307 def bfc4() = bf_run(read(pwd / "mandelbrot.bf"), "mandelbrot") |
306 |
308 |
307 |
309 |
308 // this unfortunately hits the capacity of the JVM, even with optimisations |
310 // this unfortunately hits the capacity of the JVM, even with optimisations |
309 //@doc(" Coolatz serries up to 30.") |
311 //@doc(" Collatz series up to 30.") |
310 //@main |
312 //@main |
311 //def bfc5() = bf_run(read(pwd / "collatz.bf"), "coll") |
313 //def bfc5() = bf_run(read(pwd / "collatz.bf"), "coll") |
312 |
314 |
313 // this unfortunately hits the capacity of the JVM, even with optimisations |
315 // this unfortunately hits the capacity of the JVM, even with optimisations |
314 //@doc(" Towers of Hanoi.") |
316 //@doc(" Towers of Hanoi.") |
315 //@main |
317 //@main |
316 //def bfc6() = bf_run(read(pwd / "hanoi.bf"), "hanoi") |
318 //def bfc6() = bf_run(read(pwd / "hanoi.bf"), "hanoi") |
317 |
319 |
318 // |
320 // |
319 //@doc(" All benchmarks.") |
321 //@doc(" All benchmarks.") |
320 @main |
322 //@main |
321 def all() = { bfc0(); bfc1(); bfc2(); bfc3(); bfc4() } |
323 def all() = { bfc0(); bfc1(); bfc2(); bfc3(); bfc4() } |
322 |
324 |
323 |
325 all() |
324 |
326 |
325 |
327 |
326 |
328 |
327 */ |
329 |
|
330 |
|
331 // old way to run it with Ammonite |
|
332 // |
|
333 // Call with (X being 0,1,..,4) |
|
334 // |
|
335 // amm compile_bfc.sc all |
|
336 // amm compile_bfc.sc bfcX |
|
337 // |
|
338 // |
|
339 // load the compiler |
|
340 //import $file.compile_arrays2 |
|
341 //import compile_arrays2._ |
|
342 // |
|
343 // load fastparse |
|
344 //import $ivy.`com.lihaoyi::fastparse:3.0.2` |