| 392 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |      1 | // Part 2 about a "Compiler" for the Brainf*** language
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |      2 | //======================================================
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |      3 | 
 | 
| 421 |      4 | object M5b {
 | 
| 392 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |      5 | 
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |      6 | // !!! Copy any function you need from file bf.scala !!!
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |      7 | //
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |      8 | // If you need any auxiliary function, feel free to 
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |      9 | // implement it, but do not make any changes to the
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |     10 | // templates below.
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |     11 | 
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |     12 | 
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |     13 | def time_needed[T](n: Int, code: => T) = {
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |     14 |   val start = System.nanoTime()
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |     15 |   for (i <- 0 until n) code
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |     16 |   val end = System.nanoTime()
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |     17 |   (end - start)/(n * 1.0e9)
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |     18 | }
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |     19 | 
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |     20 | type Mem = Map[Int, Int]
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |     21 | 
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |     22 | 
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |     23 | import io.Source
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |     24 | import scala.util._
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |     25 | 
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |     26 | def load_bff(name: String) : String = 
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |     27 |   Try(Source.fromFile(name)("ISO-8859-1").mkString).getOrElse("")
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |     28 | 
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |     29 | def sread(mem: Mem, mp: Int) : Int = 
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |     30 |   mem.getOrElse(mp, 0)
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |     31 | 
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |     32 | def write(mem: Mem, mp: Int, v: Int) : Mem =
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |     33 |   mem.updated(mp, v)
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |     34 | 
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |     35 | def jumpRight(prog: String, pc: Int, level: Int) : Int = {
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |     36 |   if (prog.length <= pc) pc 
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |     37 |   else (prog(pc), level) match {
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |     38 |     case (']', 0) => pc + 1
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |     39 |     case (']', l) => jumpRight(prog, pc + 1, l - 1)
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |     40 |     case ('[', l) => jumpRight(prog, pc + 1, l + 1)
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |     41 |     case (_, l) => jumpRight(prog, pc + 1, l)
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |     42 |   }
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |     43 | }
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |     44 | 
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |     45 | def jumpLeft(prog: String, pc: Int, level: Int) : Int = {
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |     46 |   if (pc < 0) pc 
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |     47 |   else (prog(pc), level) match {
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |     48 |     case ('[', 0) => pc + 1
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |     49 |     case ('[', l) => jumpLeft(prog, pc - 1, l - 1)
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |     50 |     case (']', l) => jumpLeft(prog, pc - 1, l + 1)
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |     51 |     case (_, l) => jumpLeft(prog, pc - 1, l)
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |     52 |   }
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |     53 | }
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |     54 | 
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |     55 | def compute(prog: String, pc: Int, mp: Int, mem: Mem) : Mem = {
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |     56 |   if (0 <= pc && pc < prog.length) { 
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |     57 |     val (new_pc, new_mp, new_mem) = prog(pc) match {
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |     58 |       case '>' => (pc + 1, mp + 1, mem)
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |     59 |       case '<' => (pc + 1, mp - 1, mem)
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |     60 |       case '+' => (pc + 1, mp, write(mem, mp, sread(mem, mp) + 1))
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |     61 |       case '-' => (pc + 1, mp, write(mem, mp, sread(mem, mp) - 1))
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |     62 |       case '.' => { print(sread(mem, mp).toChar); (pc + 1, mp, mem) }
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |     63 |       case '['  => 
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |     64 | 	if (sread(mem, mp) == 0) (jumpRight(prog, pc + 1, 0), mp, mem) else (pc + 1, mp, mem) 
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |     65 |       case ']'  => 
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |     66 | 	if (sread(mem, mp) != 0) (jumpLeft(prog, pc - 1, 0), mp, mem) else (pc + 1, mp, mem) 
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |     67 |       case _ => (pc + 1, mp, mem)
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |     68 |     }		     
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |     69 |     compute(prog, new_pc, new_mp, new_mem)	
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |     70 |   }
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |     71 |   else mem
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |     72 | }
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |     73 | 
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |     74 | def run(prog: String, m: Mem = Map()) = compute(prog, 0, 0, m)
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |     75 | 
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |     76 | 
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |     77 | // The baseline to what we can compare our "compiler"
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |     78 | // implemented below. It should require something like 
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |     79 | // 60 seconds for the calculation on my laptop
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |     80 | //
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |     81 | //time_needed(1, run(load_bff("benchmark.bf")))
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |     82 | 
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |     83 | 
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |     84 | 
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |     85 | // DEBUGGING INFORMATION!!!
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |     86 | //
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |     87 | // Compiler, even real ones, are fiedishly difficult to get
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |     88 | // to prduce correct code. The point is that for example for
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |     89 | // the sierpinski program, they need to still generate code
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |     90 | // that displays such a triangle. If yes, then one usually
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |     91 | // can take comfort that all is well. If not, then something
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |     92 | // went wrong during the optimisations.
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |     93 | 
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |     94 | 
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |     95 | 
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |     96 | // (5) Write a function jtable that precomputes the "jump
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |     97 | //     table" for a bf-program. This function takes a bf-program 
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |     98 | //     as an argument and Returns a Map[Int, Int]. The 
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |     99 | //     purpose of this map is to record the information
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    100 | //     that given on the position pc is a '[' or a ']',
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    101 | //     then to which pc-position do we need to jump next?
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    102 | // 
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    103 | //     For example for the program
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    104 | //    
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    105 | //       "+++++[->++++++++++<]>--<+++[->>++++++++++<<]>>++<<----------[+>.>.<+<]"
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    106 | //
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    107 | //     we obtain the map
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    108 | //
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    109 | //       Map(69 -> 61, 5 -> 20, 60 -> 70, 27 -> 44, 43 -> 28, 19 -> 6)
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    110 | //  
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    111 | //     This states that for the '[' on position 5, we need to
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    112 | //     jump to position 20, which is just after the corresponding ']'.
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    113 | //     Similarly, for the ']' on position 19, we need to jump to
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    114 | //     position 6, which is just after the '[' on position 5, and so
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    115 | //     on. The idea is to not calculate this information each time
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    116 | //     we hit a bracket, but just look up this information in the 
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    117 | //     jtable. You can use the jumpLeft and jumpRight functions
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    118 | //     from Part 1 for calculating the jtable.
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    119 | //
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    120 | //     Then adapt the compute and run functions from Part 1 in order 
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    121 | //     to take advantage of the information stored in the jtable. 
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    122 | //     This means whenever jumpLeft and jumpRight was called previously,
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    123 | //     you should look up the jump address in the jtable.
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    124 |  
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    125 | 
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    126 | def jtable(pg: String) : Map[Int, Int] = 
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    127 |     (0 until pg.length).collect { pc => pg(pc) match {
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    128 |       case '[' => (pc -> jumpRight(pg, pc + 1, 0))
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    129 |       case ']' => (pc -> jumpLeft(pg, pc - 1, 0))
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    130 |     }}.toMap
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    131 | 
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    132 | 
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    133 | // testcase
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    134 | // jtable("""+++++[->++++++++++<]>--<+++[->>++++++++++<<]>>++<<----------[+>.>.<+<]""")
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    135 | // =>  Map(69 -> 61, 5 -> 20, 60 -> 70, 27 -> 44, 43 -> 28, 19 -> 6)
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    136 | 
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    137 | 
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    138 | def compute2(pg: String, tb: Map[Int, Int], pc: Int, mp: Int, mem: Mem) : Mem = {
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    139 |   if (0 <= pc && pc < pg.length) { 
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    140 |     val (new_pc, new_mp, new_mem) = pg(pc) match {
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    141 |       case '>' => (pc + 1, mp + 1, mem)
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    142 |       case '<' => (pc + 1, mp - 1, mem)
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    143 |       case '+' => (pc + 1, mp, write(mem, mp, sread(mem, mp) + 1))
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    144 |       case '-' => (pc + 1, mp, write(mem, mp, sread(mem, mp) - 1))
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    145 |       case '.' => { print(sread(mem, mp).toChar); (pc + 1, mp, mem) }
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    146 |        case '['  => 
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    147 | 	if (sread(mem, mp) == 0) (tb(pc), mp, mem) else (pc + 1, mp, mem) 
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    148 |       case ']'  => 
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    149 | 	if (sread(mem, mp) != 0) (tb(pc), mp, mem) else (pc + 1, mp, mem) 
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    150 |       case _ => (pc + 1, mp, mem)
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    151 |     }		     
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    152 |     compute2(pg, tb, new_pc, new_mp, new_mem)	
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    153 |   }
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    154 |   else mem
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    155 | }
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    156 | 
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    157 | 
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    158 | def run2(pg: String, m: Mem = Map()) = 
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    159 |   compute2(pg, jtable(pg), 0, 0, m)
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    160 | 
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    161 | //time_needed(1, run2(load_bff("benchmark.bf")))
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    162 | 
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    163 | 
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    164 | 
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    165 | // (6) Write a function optimise which deletes "dead code" (everything
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    166 | // that is not a bf-command) and also replaces substrings of the form
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    167 | // [-] by a new command 0. The idea is that the loop [-] just resets the
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    168 | // memory at the current location to 0. In the compute3 and run3 functions
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    169 | // below you implement this command by writing the number 0 to mem(mp), 
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    170 | // that is write(mem, mp, 0). 
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    171 | //
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    172 | // The easiest way to modify a string in this way is to use the regular
 | 
| 421 |    173 | // expression """[^<>+-.\[\]""", which recognises everything that is 
 | 
| 392 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    174 | // not a bf-command and replace it by the empty string. Similarly the
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    175 | // regular expression """\[-\]""" finds all occurences of [-] and 
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    176 | // by using the Scala method .replaceAll you can repplace it with the 
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    177 | // string "0" standing for the new bf-command.
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    178 | 
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    179 | def optimise(s: String) : String = {
 | 
| 421 |    180 |   s.replaceAll("""[^<>+-.\[\]]""","")
 | 
| 392 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    181 |    .replaceAll("""\[-\]""", "0")
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    182 | }
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    183 | 
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    184 | 
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    185 | def compute3(pg: String, tb: Map[Int, Int], pc: Int, mp: Int, mem: Mem) : Mem = {
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    186 |   if (0 <= pc && pc < pg.length) { 
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    187 |     val (new_pc, new_mp, new_mem) = pg(pc) match {
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    188 |       case '0' => (pc + 1, mp, write(mem, mp, 0))
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    189 |       case '>' => (pc + 1, mp + 1, mem)
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    190 |       case '<' => (pc + 1, mp - 1, mem)
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    191 |       case '+' => (pc + 1, mp, write(mem, mp, sread(mem, mp) + 1))
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    192 |       case '-' => (pc + 1, mp, write(mem, mp, sread(mem, mp) - 1))
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    193 |       case '.' => { print(sread(mem, mp).toChar); (pc + 1, mp, mem) }
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    194 |       case '['  => 
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    195 | 	if (sread(mem, mp) == 0) (tb(pc), mp, mem) else (pc + 1, mp, mem) 
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    196 |       case ']'  => 
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    197 | 	if (sread(mem, mp) != 0) (tb(pc), mp, mem) else (pc + 1, mp, mem) 
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    198 |       case _ => (pc + 1, mp, mem)
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    199 |     }		     
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    200 |     compute3(pg, tb, new_pc, new_mp, new_mem)	
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    201 |   }
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    202 |   else mem
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    203 | }
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    204 | 
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    205 | def run3(pg: String, m: Mem = Map()) = { 
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    206 |   val pg_opt = optimise(pg)
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    207 |   compute3(pg_opt, jtable(pg_opt), 0, 0, m)
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    208 | }
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    209 | 
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    210 | 
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    211 | // testcases
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    212 | 
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    213 | //println(optimise(load_bff("collatz.bf")))
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    214 | //optimise(load_bff("benchmark.bf"))          // should have inserted 0's
 | 
| 460 |    215 | //optimise(load_bff("mandelbrot.bf")).length  // => 11203
 | 
| 392 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    216 |  
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    217 | //time_needed(1, run3(load_bff("benchmark.bf")))
 | 
| 421 |    218 | //time_needed(1, run3(load_bff("mandelbrot.bf")))
 | 
| 392 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    219 | 
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    220 | 
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    221 | 
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    222 | // (7)  Write a function combine which replaces sequences
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    223 | // of repated increment and decrement commands by appropriate
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    224 | // two-character commands. For example for sequences of +
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    225 | //
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    226 | //              orig bf-cmds  | replacement
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    227 | //            ------------------------------
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    228 | //              +             | +A 
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    229 | //              ++            | +B
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    230 | //              +++           | +C
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    231 | //                            |
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    232 | //              ...           |
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    233 | //                            | 
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    234 | //              +++....+++    | +Z
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    235 | //                (where length = 26)
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    236 | //
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    237 | //  Similar for the bf-command -, > and <. All other commands should
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    238 | //  be unaffected by this change.
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    239 | //
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    240 | //  Adapt the compute4 and run4 functions such that they can deal
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    241 | //  appropriately with such two-character commands.
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    242 | 
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    243 | def splice(cs: List[Char], acc: List[(Char, Int)]) : List[(Char, Int)] = (cs, acc) match {
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    244 |   case (Nil, acc) => acc  
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    245 |   case ('[' :: cs, acc) => splice(cs, ('[', 1) :: acc)
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    246 |   case (']' :: cs, acc) => splice(cs, (']', 1) :: acc)
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    247 |   case ('.' :: cs, acc) => splice(cs, ('.', 1) :: acc)
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    248 |   case ('0' :: cs, acc) => splice(cs, ('0', 1) :: acc)
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    249 |   case (c :: cs, Nil) => splice(cs, List((c, 1)))
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    250 |   case (c :: cs, (d, n) :: acc) => 
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    251 |     if (c == d && n < 26) splice(cs, (c, n + 1) :: acc)
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    252 |     else splice(cs, (c, 1) :: (d, n) :: acc)
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    253 | }
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    254 | 
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    255 | def spl(s: String) = splice(s.toList, Nil).reverse
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    256 | 
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    257 | //spl(load_bff("benchmark.bf"))
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    258 | 
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    259 | def combine(s: String) : String = {
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    260 |   (for ((c, n) <- spl(s)) yield c match {
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    261 |     case '>' => List('>', (n + '@').toChar)
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    262 |     case '<' => List('<', (n + '@').toChar)
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    263 |     case '+' => List('+', (n + '@').toChar)
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    264 |     case '-' => List('-', (n + '@').toChar)
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    265 |     case _ => List(c)
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    266 |   }).flatten.mkString
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    267 | }
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    268 | 
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    269 | 
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    270 | //combine(load_bff("benchmark.bf"))
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    271 | 
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    272 | def compute4(pg: String, tb: Map[Int, Int], pc: Int, mp: Int, mem: Mem) : Mem = {
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    273 |   if (0 <= pc && pc < pg.length) { 
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    274 |     val (new_pc, new_mp, new_mem) = pg(pc) match {
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    275 |       case '0' => (pc + 1, mp, write(mem, mp, 0))
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    276 |       case '>' => (pc + 2, mp + (pg(pc + 1) - '@'), mem)
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    277 |       case '<' => (pc + 2, mp - (pg(pc + 1) - '@'), mem)
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    278 |       case '+' => (pc + 2, mp, write(mem, mp, sread(mem, mp) + (pg(pc + 1) - '@')))
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    279 |       case '-' => (pc + 2, mp, write(mem, mp, sread(mem, mp) - (pg(pc + 1) - '@')))
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    280 |       case '.' => { print(sread(mem, mp).toChar); (pc + 1, mp, mem) }
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    281 |        case '['  => 
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    282 | 	if (sread(mem, mp) == 0) (tb(pc), mp, mem) else (pc + 1, mp, mem) 
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    283 |       case ']'  => 
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    284 | 	if (sread(mem, mp) != 0) (tb(pc), mp, mem) else (pc + 1, mp, mem) 
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    285 |       case _ => (pc + 1, mp, mem)
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    286 |     }		     
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    287 |     compute4(pg, tb, new_pc, new_mp, new_mem)	
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    288 |   }
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    289 |   else mem
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    290 | }
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    291 | 
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    292 | def run4(pg: String, m: Mem = Map()) = { 
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    293 |   val pg_opt = combine(optimise(pg))
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    294 |   compute4(pg_opt, jtable(pg_opt), 0, 0, m)
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    295 | }
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    296 | 
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    297 | // testcases
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    298 | //println(combine(optimise(load_bff("mandelbrot.bf").drop(123))))
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    299 | 
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    300 | //combine(optimise(load_bff("benchmark.bf"))) // => """>A+B[<A+M>A-A]<A[[....."""
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    301 | 
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    302 | //time_needed(1, run4(load_bff("benchmark.bf")))
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    303 | 
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    304 | //time_needed(1, run(load_bff("sierpinski.bf"))) 
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    305 | //time_needed(1, run4(load_bff("sierpinski.bf"))) 
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    306 | 
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    307 | //println(time_needed(1, run4(load_bff("mandelbrot.bf"))))
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    308 | 
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    309 | 
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    310 | 
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    311 | 
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    312 | 
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    313 | }
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    314 | 
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    315 | /*
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    316 | import CW10b._
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    317 | println(time_needed(1, run(load_bff("collatz.bf"))))
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    318 | println(time_needed(1, run2(load_bff("collatz.bf"))))
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    319 | println(time_needed(1, run3(load_bff("collatz.bf"))))
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    320 | println(time_needed(1, run4(load_bff("collatz.bf"))))
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    321 | */
 |