|     73 } |     73 } | 
|     74  |     74  | 
|     75 def run(prog: String, m: Mem = Map()) = compute(prog, 0, 0, m) |     75 def run(prog: String, m: Mem = Map()) = compute(prog, 0, 0, m) | 
|     76  |     76  | 
|     77  |     77  | 
|     78 // The baseline to what we compare our "compiler"; |     78 // The baseline to what we can compare our "compiler" | 
|     79 // it requires something like 60 seconds on my laptop |     79 // implemented below. It should require something like  | 
|         |     80 // 60 seconds for the calculation on my laptop | 
|     80 // |     81 // | 
|     81 //time_needed(1, run(load_bff("benchmark.bf"))) |     82 //time_needed(1, run(load_bff("benchmark.bf"))) | 
|     82  |     83  | 
|         |     84  | 
|         |     85  | 
|         |     86 // DEBUGGING INFORMATION!!! | 
|         |     87 // | 
|         |     88 // Compiler, even real ones, are fiedishly difficult to get | 
|         |     89 // to prduce correct code. The point is that for example for | 
|         |     90 // the sierpinski program, they need to still generate code | 
|         |     91 // that displays such a triangle. If yes, then one usually | 
|         |     92 // can take comfort that all is well. If not, then something | 
|         |     93 // went wrong during the optimisations. | 
|     83  |     94  | 
|     84  |     95  | 
|     85  |     96  | 
|     86 // (5) Write a function jtable that precomputes the "jump |     97 // (5) Write a function jtable that precomputes the "jump | 
|     87 //     table" for a bf-program. This function takes a bf-program  |     98 //     table" for a bf-program. This function takes a bf-program  | 
|     88 //     as an argument and Returns a Map[Int, Int]. The  |     99 //     as an argument and Returns a Map[Int, Int]. The  | 
|     89 //     purpose of this map is to record the information |    100 //     purpose of this map is to record the information | 
|     90 //     that given on the pc-position, say n, is a '[' or a ']', |    101 //     that given on the position pc is a '[' or a ']', | 
|     91 //     then to which pc-position do we need to jump? |    102 //     then to which pc-position do we need to jump next? | 
|     92 //  |    103 //  | 
|     93 //     For example for the program |    104 //     For example for the program | 
|     94 //     |    105 //     | 
|     95 //       "+++++[->++++++++++<]>--<+++[->>++++++++++<<]>>++<<----------[+>.>.<+<]" |    106 //       "+++++[->++++++++++<]>--<+++[->>++++++++++<<]>>++<<----------[+>.>.<+<]" | 
|     96 // |    107 // | 
|    100 //   |    111 //   | 
|    101 //     This states that for the '[' on position 5, we need to |    112 //     This states that for the '[' on position 5, we need to | 
|    102 //     jump to position 20, which is just after the corresponding ']'. |    113 //     jump to position 20, which is just after the corresponding ']'. | 
|    103 //     Similarly, for the ']' on position 19, we need to jump to |    114 //     Similarly, for the ']' on position 19, we need to jump to | 
|    104 //     position 6, which is just after the '[' on position 5, and so |    115 //     position 6, which is just after the '[' on position 5, and so | 
|    105 //     on. The idea to not calculate this information each time |    116 //     on. The idea is to not calculate this information each time | 
|    106 //     we hit a bracket, but just loop uu this information in the  |    117 //     we hit a bracket, but just look up this information in the  | 
|    107 //     jtable. |    118 //     jtable. You can use the jumpLeft and jumpRight functions | 
|    108 // |    119 //     from Part 1 for calculating the jtable. | 
|    109 //     Adapt the compute and run functions from Part 1 in order to |    120 // | 
|    110 //     take advantage of the information in the jtable.  |    121 //     Then adapt the compute and run functions from Part 1 in order  | 
|         |    122 //     to take advantage of the information stored in the jtable.  | 
|         |    123 //     This means whenever jumpLeft and jumpRight was called previously, | 
|         |    124 //     you should look up the jump address in the jtable. | 
|    111   |    125   | 
|    112  |    126  | 
|    113 def jtable(pg: String) : Map[Int, Int] =  |    127 def jtable(pg: String) : Map[Int, Int] =  | 
|    114     (0 until pg.length).collect { pc => pg(pc) match { |    128     (0 until pg.length).collect { pc => pg(pc) match { | 
|    115       case '[' => (pc -> jumpRight(pg, pc + 1, 0)) |    129       case '[' => (pc -> jumpRight(pg, pc + 1, 0)) | 
|    147   compute2(pg, jtable(pg), 0, 0, m) |    161   compute2(pg, jtable(pg), 0, 0, m) | 
|    148  |    162  | 
|    149 //time_needed(1, run2(load_bff("benchmark.bf"))) |    163 //time_needed(1, run2(load_bff("benchmark.bf"))) | 
|    150  |    164  | 
|    151  |    165  | 
|         |    166  | 
|    152 // (6) Write a function optimise which deletes "dead code" (everything |    167 // (6) Write a function optimise which deletes "dead code" (everything | 
|    153 // that is not a bf-command) and also replaces substrings of the form |    168 // that is not a bf-command) and also replaces substrings of the form | 
|    154 // [-] by a new command 0. The idea is that the the loop [-] resets the |    169 // [-] by a new command 0. The idea is that the loop [-] just resets the | 
|    155 // memory at the current location to 0. In the compute3 and run3 functions |    170 // memory at the current location to 0. In the compute3 and run3 functions | 
|    156 // below we implement this command by writing 0 to mem(mp), then is |    171 // below you implement this command by writing the number 0 to mem(mp),  | 
|    157 // write(mem, mp, 0).  |    172 // that is write(mem, mp, 0).  | 
|    158 // |    173 // | 
|    159 // The easiest way to modify a string in this way is to use the regular |    174 // The easiest way to modify a string in this way is to use the regular | 
|    160 // expression """[^<>+-.,\[\]]""", whcih recognises everything that is  |    175 // expression """[^<>+-.,\[\]]""", which recognises everything that is  | 
|    161 // not a bf-command and replace it by the empty string. Similarly the |    176 // not a bf-command and replace it by the empty string. Similarly the | 
|    162 // regular expression """\[-\]""" finds all occurences of [-] and  |    177 // regular expression """\[-\]""" finds all occurences of [-] and  | 
|    163 // by using the Scala method .replaceAll you can repplace it with the  |    178 // by using the Scala method .replaceAll you can repplace it with the  | 
|    164 // string "0" standing for the new bf-program. |    179 // string "0" standing for the new bf-command. | 
|    165  |    180  | 
|    166 def optimise(s: String) : String =  |    181 def optimise(s: String) : String =  | 
|    167   s.replaceAll("""[^<>+-.,\[\]]""","").replaceAll("""\[-\]""", "0") |    182   s.replaceAll("""[^<>+-.,\[\]]""","").replaceAll("""\[-\]""", "0") | 
|         |    183  | 
|    168  |    184  | 
|    169 def compute3(pg: String, tb: Map[Int, Int], pc: Int, mp: Int, mem: Mem) : Mem = { |    185 def compute3(pg: String, tb: Map[Int, Int], pc: Int, mp: Int, mem: Mem) : Mem = { | 
|    170   if (0 <= pc && pc < pg.length) {  |    186   if (0 <= pc && pc < pg.length) {  | 
|    171     val (new_pc, new_mp, new_mem) = pg(pc) match { |    187     val (new_pc, new_mp, new_mem) = pg(pc) match { | 
|    172       case '0' => (pc + 1, mp, write(mem, mp, 0)) |    188       case '0' => (pc + 1, mp, write(mem, mp, 0)) | 
|    191   val pg_opt = optimise(pg) |    207   val pg_opt = optimise(pg) | 
|    192   compute3(pg_opt, jtable(pg_opt), 0, 0, m) |    208   compute3(pg_opt, jtable(pg_opt), 0, 0, m) | 
|    193 } |    209 } | 
|    194  |    210  | 
|    195  |    211  | 
|    196 time_needed(1, run3(load_bff("benchmark.bf"))) |    212 // testcases | 
|    197  |    213  | 
|    198  |    214 //optimise(load_bff("benchmark.bf"))          // should have inserted 0's | 
|    199 // (7)  |    215 //optimise(load_bff("mandelbrot.bf")).length  // => 11203 | 
|         |    216   | 
|         |    217 //time_needed(1, run3(load_bff("benchmark.bf"))) | 
|         |    218  | 
|         |    219  | 
|         |    220  | 
|         |    221 // (7)  Write a function combine which replaces sequences | 
|         |    222 // of repated increment and decrement commands by appropriate | 
|         |    223 // two-character commands. For example for sequences of + | 
|         |    224 // | 
|         |    225 //              orig bf-cmds  | replacement | 
|         |    226 //            ------------------------------ | 
|         |    227 //              +             | +A  | 
|         |    228 //              ++            | +B | 
|         |    229 //              +++           | +C | 
|         |    230 //                            | | 
|         |    231 //              ...           | | 
|         |    232 //                            |  | 
|         |    233 //              +++....+++    | +Z | 
|         |    234 //                (where length = 26) | 
|         |    235 // | 
|         |    236 //  Similar for the bf-command -, > and <. All other commands should | 
|         |    237 //  be unaffected by this change. | 
|         |    238 // | 
|         |    239 //  Adapt the compute4 and run4 functions such that they can deal | 
|         |    240 //  appropriately with such two-character commands. | 
|    200  |    241  | 
|    201 def splice(cs: List[Char], acc: List[(Char, Int)]) : List[(Char, Int)] = (cs, acc) match { |    242 def splice(cs: List[Char], acc: List[(Char, Int)]) : List[(Char, Int)] = (cs, acc) match { | 
|    202   case (Nil, acc) => acc   |    243   case (Nil, acc) => acc   | 
|    203   case ('[' :: cs, acc) => splice(cs, ('[', 1) :: acc) |    244   case ('[' :: cs, acc) => splice(cs, ('[', 1) :: acc) | 
|    204   case (']' :: cs, acc) => splice(cs, (']', 1) :: acc) |    245   case (']' :: cs, acc) => splice(cs, (']', 1) :: acc) | 
|    213  |    254  | 
|    214 def spl(s: String) = splice(s.toList, Nil).reverse |    255 def spl(s: String) = splice(s.toList, Nil).reverse | 
|    215  |    256  | 
|    216 spl(load_bff("benchmark.bf")) |    257 spl(load_bff("benchmark.bf")) | 
|    217  |    258  | 
|    218 def combine(cs: List[(Char, Int)]) : String = { |    259 def combine(s: String) : String = { | 
|    219   (for ((c, n) <- cs) yield c match { |    260   (for ((c, n) <- spl(s)) yield c match { | 
|    220     case '>' => List('>', (n + '@').toChar) |    261     case '>' => List('>', (n + '@').toChar) | 
|    221     case '<' => List('<', (n + '@').toChar) |    262     case '<' => List('<', (n + '@').toChar) | 
|    222     case '+' => List('+', (n + '@').toChar) |    263     case '+' => List('+', (n + '@').toChar) | 
|    223     case '-' => List('-', (n + '@').toChar) |    264     case '-' => List('-', (n + '@').toChar) | 
|    224     case _ => List(c) |    265     case _ => List(c) | 
|    225   }).flatten.mkString |    266   }).flatten.mkString | 
|    226 } |    267 } | 
|    227  |    268  | 
|    228  |    269  | 
|    229 combine(spl(load_bff("benchmark.bf"))) |    270 combine(load_bff("benchmark.bf")) | 
|    230  |         | 
|    231  |    271  | 
|    232 def compute4(pg: String, tb: Map[Int, Int], pc: Int, mp: Int, mem: Mem) : Mem = { |    272 def compute4(pg: String, tb: Map[Int, Int], pc: Int, mp: Int, mem: Mem) : Mem = { | 
|    233   if (0 <= pc && pc < pg.length) {  |    273   if (0 <= pc && pc < pg.length) {  | 
|    234     val (new_pc, new_mp, new_mem) = pg(pc) match { |    274     val (new_pc, new_mp, new_mem) = pg(pc) match { | 
|    235       case '0' => (pc + 1, mp, write(mem, mp, 0)) |    275       case '0' => (pc + 1, mp, write(mem, mp, 0)) | 
|    249   } |    289   } | 
|    250   else mem |    290   else mem | 
|    251 } |    291 } | 
|    252  |    292  | 
|    253 def run4(pg: String, m: Mem = Map()) = {  |    293 def run4(pg: String, m: Mem = Map()) = {  | 
|    254   val pg_opt = combine(spl(optimise(pg))) |    294   val pg_opt = combine(optimise(pg)) | 
|    255   compute4(pg_opt, jtable(pg_opt), 0, 0, m) |    295   compute4(pg_opt, jtable(pg_opt), 0, 0, m) | 
|    256 } |    296 } | 
|    257  |    297  | 
|    258  |    298  | 
|         |    299 combine(optimise(load_bff("benchmark.bf"))) // => """>A+B[<A+M>A-A]<A[[.....""" | 
|         |    300  | 
|    259 //time_needed(1, run4(load_bff("benchmark.bf"))) |    301 //time_needed(1, run4(load_bff("benchmark.bf"))) | 
|         |    302  | 
|         |    303 //time_needed(1, run(load_bff("sierpinski.bf")))  | 
|         |    304 //time_needed(1, run4(load_bff("sierpinski.bf")))  | 
|         |    305  | 
|    260 //time_needed(1, run4(load_bff("mandelbrot.bf"))) |    306 //time_needed(1, run4(load_bff("mandelbrot.bf"))) | 
|    261  |    307  | 
|    262  |    308  | 
|    263 } |    309 //} |