|     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` |