main_testing5/bfc.scala
changeset 384 6e1237691307
parent 348 b5b6ed38c2f2
child 404 bf20a9fa5c29
equal deleted inserted replaced
383:c02929f2647c 384:6e1237691307
     1 // Part 2 about a "Compiler" for the Brainf*** language
     1 // Core Part about a "Compiler" for the Brainf*** language
     2 //======================================================
     2 //======================================================
     3 
     3 
       
     4 
     4 object CW10b {
     5 object CW10b {
       
     6 
     5 
     7 
     6 // !!! Copy any function you need from file bf.scala !!!
     8 // !!! Copy any function you need from file bf.scala !!!
     7 //
     9 //
     8 // If you need any auxiliary function, feel free to 
    10 // If you need any auxiliary function, feel free to 
     9 // implement it, but do not make any changes to the
    11 // implement it, but do not make any changes to the
    10 // templates below.
    12 // templates below.
    11 
    13 
    12 
    14 type Mem = Map[Int, Int]
       
    15 
       
    16 import io.Source
       
    17 import scala.util._
       
    18 
       
    19 def load_bff(name: String) : String = 
       
    20   Try(scala.io.Source.fromFile(name)("ISO-8859-1").mkString).getOrElse("")
       
    21 
       
    22 def sread(mem: Mem, mp: Int) : Int = mem.getOrElse(mp, 0)
       
    23 
       
    24 def write(mem: Mem, mp: Int, v: Int) : Mem = mem + (mp -> v)
       
    25 
       
    26 def jumpRight(prog: String, pc: Int, level: Int) : Int = {
       
    27     pc match {
       
    28         case pc: Int if (pc >= 0 && pc < prog.length) => {
       
    29             prog(pc) match {
       
    30                 case '[' => jumpRight(prog, pc + 1, level + 1)
       
    31                 case ']' => if (level == 0) pc + 1 else jumpRight(prog, pc + 1, level - 1)
       
    32                 case _ => jumpRight(prog, pc + 1, level)
       
    33             }
       
    34         }
       
    35         case _ => pc
       
    36     }
       
    37 }
       
    38 
       
    39 def jumpLeft(prog: String, pc: Int, level: Int) : Int = {
       
    40     pc match {
       
    41         case pc: Int if (pc >= 0 && pc < prog.length) => {
       
    42             prog(pc) match {
       
    43                 case '[' => if (level == 0) pc + 1 else jumpLeft(prog, pc - 1, level - 1)
       
    44                 case ']' => jumpLeft(prog, pc - 1, level + 1)
       
    45                 case _ => jumpLeft(prog, pc - 1, level)
       
    46             }
       
    47         }
       
    48         case _ => pc
       
    49     }
       
    50 }
       
    51 
       
    52 def get_position(prog: String, pc: Int, level: Int) : Int = {
       
    53   prog(pc) match {
       
    54     case '[' => jumpRight(prog, pc + 1, level)
       
    55     case ']' => jumpLeft(prog, pc - 1, level)
       
    56     case _ => println("Something went horrible wrong, I am sorry"); 0
       
    57   }
       
    58 }
       
    59 
       
    60 // DEBUGGING INFORMATION FOR COMPILERS!!!
       
    61 //
       
    62 // Compiler, even real ones, are fiendishly difficult to get
       
    63 // to produce correct code. One way to debug them is to run
       
    64 // example programs ``unoptimised''; and then optimised. Does
       
    65 // the optimised version still produce the same result?
       
    66 
       
    67 
       
    68 // for timing purposes
    13 def time_needed[T](n: Int, code: => T) = {
    69 def time_needed[T](n: Int, code: => T) = {
    14   val start = System.nanoTime()
    70   val start = System.nanoTime()
    15   for (i <- 0 until n) code
    71   for (i <- 0 until n) code
    16   val end = System.nanoTime()
    72   val end = System.nanoTime()
    17   (end - start)/(n * 1.0e9)
    73   (end - start)/(n * 1.0e9)
    18 }
    74 }
    19 
    75 
    20 type Mem = Map[Int, Int]
    76 
    21 
    77 
    22 
    78 // TASKS
    23 import io.Source
    79 //=======
    24 import scala.util._
       
    25 
       
    26 def load_bff(name: String) : String = 
       
    27   Try(Source.fromFile(name)("ISO-8859-1").mkString).getOrElse("")
       
    28 
       
    29 def sread(mem: Mem, mp: Int) : Int = 
       
    30   mem.getOrElse(mp, 0)
       
    31 
       
    32 def write(mem: Mem, mp: Int, v: Int) : Mem =
       
    33   mem.updated(mp, v)
       
    34 
       
    35 def jumpRight(prog: String, pc: Int, level: Int) : Int = {
       
    36   if (prog.length <= pc) pc 
       
    37   else (prog(pc), level) match {
       
    38     case (']', 0) => pc + 1
       
    39     case (']', l) => jumpRight(prog, pc + 1, l - 1)
       
    40     case ('[', l) => jumpRight(prog, pc + 1, l + 1)
       
    41     case (_, l) => jumpRight(prog, pc + 1, l)
       
    42   }
       
    43 }
       
    44 
       
    45 def jumpLeft(prog: String, pc: Int, level: Int) : Int = {
       
    46   if (pc < 0) pc 
       
    47   else (prog(pc), level) match {
       
    48     case ('[', 0) => pc + 1
       
    49     case ('[', l) => jumpLeft(prog, pc - 1, l - 1)
       
    50     case (']', l) => jumpLeft(prog, pc - 1, l + 1)
       
    51     case (_, l) => jumpLeft(prog, pc - 1, l)
       
    52   }
       
    53 }
       
    54 
       
    55 def compute(prog: String, pc: Int, mp: Int, mem: Mem) : Mem = {
       
    56   if (0 <= pc && pc < prog.length) { 
       
    57     val (new_pc, new_mp, new_mem) = prog(pc) match {
       
    58       case '>' => (pc + 1, mp + 1, mem)
       
    59       case '<' => (pc + 1, mp - 1, mem)
       
    60       case '+' => (pc + 1, mp, write(mem, mp, sread(mem, mp) + 1))
       
    61       case '-' => (pc + 1, mp, write(mem, mp, sread(mem, mp) - 1))
       
    62       case '.' => { print(sread(mem, mp).toChar); (pc + 1, mp, mem) }
       
    63       case ',' => (pc + 1, mp, write(mem, mp, Console.in.read().toByte))
       
    64       case '['  => 
       
    65 	if (sread(mem, mp) == 0) (jumpRight(prog, pc + 1, 0), mp, mem) else (pc + 1, mp, mem) 
       
    66       case ']'  => 
       
    67 	if (sread(mem, mp) != 0) (jumpLeft(prog, pc - 1, 0), mp, mem) else (pc + 1, mp, mem) 
       
    68       case _ => (pc + 1, mp, mem)
       
    69     }		     
       
    70     compute(prog, new_pc, new_mp, new_mem)	
       
    71   }
       
    72   else mem
       
    73 }
       
    74 
       
    75 def run(prog: String, m: Mem = Map()) = compute(prog, 0, 0, m)
       
    76 
       
    77 
       
    78 // The baseline to what we can compare our "compiler"
       
    79 // implemented below. It should require something like 
       
    80 // 60 seconds for the calculation on my laptop
       
    81 //
       
    82 //time_needed(1, run(load_bff("benchmark.bf")))
       
    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.
       
    94 
       
    95 
       
    96 
    80 
    97 // (5) Write a function jtable that precomputes the "jump
    81 // (5) Write a function jtable that precomputes the "jump
    98 //     table" for a bf-program. This function takes a bf-program 
    82 //     table" for a bf-program. This function takes a bf-program 
    99 //     as an argument and Returns a Map[Int, Int]. The 
    83 //     as an argument and Returns a Map[Int, Int]. The 
   100 //     purpose of this map is to record the information
    84 //     purpose of this map is to record the information about
   101 //     that given on the position pc is a '[' or a ']',
    85 //     pc positions where '[' or a ']' are stored. The information
   102 //     then to which pc-position do we need to jump next?
    86 //     is to which pc-position do we need to jump next?
   103 // 
    87 // 
   104 //     For example for the program
    88 //     For example for the program
   105 //    
    89 //    
   106 //       "+++++[->++++++++++<]>--<+++[->>++++++++++<<]>>++<<----------[+>.>.<+<]"
    90 //       "+++++[->++++++++++<]>--<+++[->>++++++++++<<]>>++<<----------[+>.>.<+<]"
   107 //
    91 //
   116 //     on. The idea is to not calculate this information each time
   100 //     on. The idea is to not calculate this information each time
   117 //     we hit a bracket, but just look up this information in the 
   101 //     we hit a bracket, but just look up this information in the 
   118 //     jtable. You can use the jumpLeft and jumpRight functions
   102 //     jtable. You can use the jumpLeft and jumpRight functions
   119 //     from Part 1 for calculating the jtable.
   103 //     from Part 1 for calculating the jtable.
   120 //
   104 //
   121 //     Then adapt the compute and run functions from Part 1 in order 
   105 //     Then adapt the compute and run functions from Part 1 
   122 //     to take advantage of the information stored in the jtable. 
   106 //     in order to take advantage of the information stored in the jtable. 
   123 //     This means whenever jumpLeft and jumpRight was called previously,
   107 //     This means whenever jumpLeft and jumpRight was called previously,
   124 //     you should look up the jump address in the jtable.
   108 //     you should immediately look up the jump address in the jtable.
       
   109 //  for ((char, index) <- str.zipWithIndex if (List('[', ']').contains(char))) yield (index, get_position(str, index, 0))
   125  
   110  
   126 
   111 
   127 def jtable(pg: String) : Map[Int, Int] = 
   112 def jtable(pg: String) : Map[Int, Int] = {
   128     (0 until pg.length).collect { pc => pg(pc) match {
   113   val table = for ((char, index) <- pg.zipWithIndex if (List('[', ']').contains(char))) yield (index, get_position(pg, index, 0))
   129       case '[' => (pc -> jumpRight(pg, pc + 1, 0))
   114   table.toMap
   130       case ']' => (pc -> jumpLeft(pg, pc - 1, 0))
   115 }
   131     }}.toMap
       
   132 
   116 
   133 
   117 
   134 // testcase
   118 // testcase
       
   119 //
   135 // jtable("""+++++[->++++++++++<]>--<+++[->>++++++++++<<]>>++<<----------[+>.>.<+<]""")
   120 // jtable("""+++++[->++++++++++<]>--<+++[->>++++++++++<<]>>++<<----------[+>.>.<+<]""")
   136 // =>  Map(69 -> 61, 5 -> 20, 60 -> 70, 27 -> 44, 43 -> 28, 19 -> 6)
   121 // =>  Map(69 -> 61, 5 -> 20, 60 -> 70, 27 -> 44, 43 -> 28, 19 -> 6)
   137 
   122 
   138 
   123 
   139 def compute2(pg: String, tb: Map[Int, Int], pc: Int, mp: Int, mem: Mem) : Mem = {
   124 def compute2(pg: String, tb: Map[Int, Int], pc: Int, mp: Int, mem: Mem) : Mem = {
   140   if (0 <= pc && pc < pg.length) { 
   125   pc match {
   141     val (new_pc, new_mp, new_mem) = pg(pc) match {
   126     case pc: Int if (pc >= 0 && pc < pg.length) => {
   142       case '>' => (pc + 1, mp + 1, mem)
   127       pg(pc) match {
   143       case '<' => (pc + 1, mp - 1, mem)
   128         case '>' => compute2(pg, tb, pc + 1, mp + 1, mem)
   144       case '+' => (pc + 1, mp, write(mem, mp, sread(mem, mp) + 1))
   129         case '<' => compute2(pg, tb, pc + 1, mp - 1, mem)
   145       case '-' => (pc + 1, mp, write(mem, mp, sread(mem, mp) - 1))
   130         case '+' => compute2(pg, tb, pc + 1, mp, write(mem, mp, sread(mem, mp) + 1))
   146       case '.' => { print(sread(mem, mp).toChar); (pc + 1, mp, mem) }
   131         case '-' => compute2(pg, tb, pc + 1, mp, write(mem, mp, sread(mem, mp) - 1))
   147       case ',' => (pc + 1, mp, write(mem, mp, Console.in.read().toByte))
   132         case '.' => print(sread(mem, mp).toChar); compute2(pg, tb, pc + 1, mp, mem)
   148       case '['  => 
   133         case '[' => if (sread(mem, mp) == 0) compute2(pg, tb, tb(pc), mp, mem) else compute2(pg, tb, pc + 1, mp, mem)
   149 	if (sread(mem, mp) == 0) (tb(pc), mp, mem) else (pc + 1, mp, mem) 
   134         case ']' => if (sread(mem, mp) != 0) compute2(pg, tb, tb(pc), mp, mem) else compute2(pg, tb, pc + 1, mp, mem)
   150       case ']'  => 
   135         case '*' => compute2(pg, tb, pc + 1, mp, write(mem, mp, sread(mem, mp) * sread(mem, mp - 1)))
   151 	if (sread(mem, mp) != 0) (tb(pc), mp, mem) else (pc + 1, mp, mem) 
   136         case '@' => compute2(pg, tb, pc + 1, mp, write(mem, mem(mp), sread(mem, mp - 1)))
   152       case _ => (pc + 1, mp, mem)
   137         case '#' => print(sread(mem, mp)); compute2(pg, tb, pc + 1, mp, mem)
   153     }		     
   138         case _ => compute2(pg, tb, pc + 1, mp, mem)
   154     compute2(pg, tb, new_pc, new_mp, new_mem)	
   139       }
   155   }
   140     }
   156   else mem
   141     case _ => mem
   157 }
   142   }
   158 
   143 }
   159 
   144 
   160 def run2(pg: String, m: Mem = Map()) = 
   145 def run2(pg: String, m: Mem = Map()) = {
   161   compute2(pg, jtable(pg), 0, 0, m)
   146   compute2(pg, jtable(pg), 0, 0, m)
   162 
   147 }
   163 //time_needed(1, run2(load_bff("benchmark.bf")))
   148 
       
   149 
       
   150 // testcases
       
   151 // time_needed(1, run2(load_bff("./main5/benchmark.bf")))
       
   152 // time_needed(1, run2(load_bff("./main5/sierpinski.bf")))
   164 
   153 
   165 
   154 
   166 
   155 
   167 // (6) Write a function optimise which deletes "dead code" (everything
   156 // (6) Write a function optimise which deletes "dead code" (everything
   168 // that is not a bf-command) and also replaces substrings of the form
   157 // that is not a bf-command) and also replaces substrings of the form
   172 // that is write(mem, mp, 0). 
   161 // that is write(mem, mp, 0). 
   173 //
   162 //
   174 // The easiest way to modify a string in this way is to use the regular
   163 // The easiest way to modify a string in this way is to use the regular
   175 // expression """[^<>+-.,\[\]]""", which recognises everything that is 
   164 // expression """[^<>+-.,\[\]]""", which recognises everything that is 
   176 // not a bf-command and replace it by the empty string. Similarly the
   165 // not a bf-command and replace it by the empty string. Similarly the
   177 // regular expression """\[-\]""" finds all occurences of [-] and 
   166 // regular expression """\[-\]""" finds all occurrences of [-] and 
   178 // by using the Scala method .replaceAll you can repplace it with the 
   167 // by using the Scala method .replaceAll you can replace it with the 
   179 // string "0" standing for the new bf-command.
   168 // string "0" standing for the new bf-command.
   180 
   169 // load_bff("./main5/mandelbrot.bf").replaceAll("""[^<>+‐.\[\]@#*]""", "").replaceAll("""\[-\]""", "0")
   181 def optimise(s: String) : String = 
   170 
   182   s.replaceAll("""[^<>+-.,\[\]]""","").replaceAll("""\[-\]""", "0")
   171 // "Correct" regex
   183 
   172 // s.replaceAll("""[^<>+‐.\[\]@#*]""", "").replaceAll("""\[-\]""", "0")
       
   173 // s.replaceAll("""[^<>+-.,\[\]]""", "").replaceAll("""\[-\]""", "0")
       
   174 
       
   175 def optimise(s: String) : String = {
       
   176   //s.replaceAll("""[^<>+-.\[\]@#*]""","")
       
   177   // .replaceAll("""\[-\]""", "0")
       
   178   s.replaceAll("""[^<>+-.\[\]]""", "").replaceAll("""\[-\]""", "0")
       
   179 }
   184 
   180 
   185 def compute3(pg: String, tb: Map[Int, Int], pc: Int, mp: Int, mem: Mem) : Mem = {
   181 def compute3(pg: String, tb: Map[Int, Int], pc: Int, mp: Int, mem: Mem) : Mem = {
   186   if (0 <= pc && pc < pg.length) { 
   182   pc match {
   187     val (new_pc, new_mp, new_mem) = pg(pc) match {
   183     case pc: Int if (pc >= 0 && pc < pg.length) => {
   188       case '0' => (pc + 1, mp, write(mem, mp, 0))
   184       pg(pc) match {
   189       case '>' => (pc + 1, mp + 1, mem)
   185         case '>' => compute3(pg, tb, pc + 1, mp + 1, mem)
   190       case '<' => (pc + 1, mp - 1, mem)
   186         case '<' => compute3(pg, tb, pc + 1, mp - 1, mem)
   191       case '+' => (pc + 1, mp, write(mem, mp, sread(mem, mp) + 1))
   187         case '+' => compute3(pg, tb, pc + 1, mp, write(mem, mp, sread(mem, mp) + 1))
   192       case '-' => (pc + 1, mp, write(mem, mp, sread(mem, mp) - 1))
   188         case '-' => compute3(pg, tb, pc + 1, mp, write(mem, mp, sread(mem, mp) - 1))
   193       case '.' => { print(sread(mem, mp).toChar); (pc + 1, mp, mem) }
   189         case '.' => print(sread(mem, mp).toChar); compute3(pg, tb, pc + 1, mp, mem)
   194       case ',' => (pc + 1, mp, write(mem, mp, Console.in.read().toByte))
   190         case '[' => if (sread(mem, mp) == 0) compute3(pg, tb, tb(pc), mp, mem) else compute3(pg, tb, pc + 1, mp, mem)
   195       case '['  => 
   191         case ']' => if (sread(mem, mp) != 0) compute3(pg, tb, tb(pc), mp, mem) else compute3(pg, tb, pc + 1, mp, mem)
   196 	if (sread(mem, mp) == 0) (tb(pc), mp, mem) else (pc + 1, mp, mem) 
   192         case '*' => compute3(pg, tb, pc + 1, mp, write(mem, mp, sread(mem, mp) * sread(mem, mp - 1)))
   197       case ']'  => 
   193         case '@' => compute3(pg, tb, pc + 1, mp, write(mem, mem(mp), sread(mem, mp - 1)))
   198 	if (sread(mem, mp) != 0) (tb(pc), mp, mem) else (pc + 1, mp, mem) 
   194         case '#' => print(sread(mem, mp)); compute3(pg, tb, pc + 1, mp, mem)
   199       case _ => (pc + 1, mp, mem)
   195         case '0' => compute3(pg, tb, pc + 1, mp, write(mem, mp, 0))
   200     }		     
   196         case _ => compute3(pg, tb, pc + 1, mp, mem)
   201     compute3(pg, tb, new_pc, new_mp, new_mem)	
   197       }
   202   }
   198     }
   203   else mem
   199     case _ => mem
   204 }
   200   }
   205 
   201 }
   206 def run3(pg: String, m: Mem = Map()) = { 
   202 
   207   val pg_opt = optimise(pg)
   203 def run3(pg: String, m: Mem = Map()) = {
   208   compute3(pg_opt, jtable(pg_opt), 0, 0, m)
   204   val optimised = optimise(pg)
       
   205   compute3(optimised, jtable(optimised), 0, 0, m)
   209 }
   206 }
   210 
   207 
   211 
   208 
   212 // testcases
   209 // testcases
   213 
   210 //
   214 //optimise(load_bff("benchmark.bf"))          // should have inserted 0's
   211 // optimise(load_bff("./main5/benchmark.bf"))          // should have inserted 0's
   215 //optimise(load_bff("benchmark.bf")).length   // => 181  
   212 // optimise(load_bff("./main5/mandelbrot.bf")).length  // => 11205
   216 //optimise(load_bff("mandelbrot.bf")).length  // => 11203
   213 // 
   217  
   214 // time_needed(1, run3(load_bff("./main5/benchmark.bf")))
   218 //time_needed(1, run3(load_bff("benchmark.bf")))
   215 // time_needed(1, run3(load_bff("./main5/mandelbrot.bf")))
   219 
   216 
   220 
   217 
   221 
   218 
   222 // (7)  Write a function combine which replaces sequences
   219 // (7)  Write a function combine which replaces sequences
   223 // of repated increment and decrement commands by appropriate
   220 // of repeated increment and decrement commands by appropriate
   224 // two-character commands. For example for sequences of +
   221 // two-character commands. For example for sequences of +
   225 //
   222 //
   226 //              orig bf-cmds  | replacement
   223 //              orig bf-cmds  | replacement
   227 //            ------------------------------
   224 //            ------------------------------
   228 //              +             | +A 
   225 //              +             | +A 
   238 //  be unaffected by this change.
   235 //  be unaffected by this change.
   239 //
   236 //
   240 //  Adapt the compute4 and run4 functions such that they can deal
   237 //  Adapt the compute4 and run4 functions such that they can deal
   241 //  appropriately with such two-character commands.
   238 //  appropriately with such two-character commands.
   242 
   239 
   243 def splice(cs: List[Char], acc: List[(Char, Int)]) : List[(Char, Int)] = (cs, acc) match {
   240 // val alphabet = "АБВГДЕЁЖЗИЙКЛМНОПРСТУФХЦЧШЩЪЫЬЭЮЯ"
   244   case (Nil, acc) => acc  
   241 val alphabet = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
   245   case ('[' :: cs, acc) => splice(cs, ('[', 1) :: acc)
   242 
   246   case (']' :: cs, acc) => splice(cs, (']', 1) :: acc)
   243 // Try any alphabet, it will work as long as the character is recognised and the characters are unique
   247   case ('.' :: cs, acc) => splice(cs, ('.', 1) :: acc)
   244 
   248   case (',' :: cs, acc) => splice(cs, (',', 1) :: acc)
   245 def get_number_from_character(char: Char) : Int = {
   249   case ('0' :: cs, acc) => splice(cs, ('0', 1) :: acc)
   246   alphabet.indexOf(char) + 1
   250   case (c :: cs, Nil) => splice(cs, List((c, 1)))
   247 }
   251   case (c :: cs, (d, n) :: acc) => 
   248 
   252     if (c == d && n < 26) splice(cs, (c, n + 1) :: acc)
   249 def get_character_from_number(int: Int) : Char = {
   253     else splice(cs, (c, 1) :: (d, n) :: acc)
   250   alphabet(int - 1)
   254 }
   251 }
   255 
   252 
   256 def spl(s: String) = splice(s.toList, Nil).reverse
   253 @annotation.tailrec 
   257 
   254 def split_by_repetition(string : String, list : List[String] = Nil) : List[String] = {
   258 //spl(load_bff("benchmark.bf"))
   255     if(string.size == 0) list.reverse 
       
   256     else {
       
   257         val (left_substring, right_substring) = string.span(_ == string(0))
       
   258         split_by_repetition(right_substring, left_substring :: list)
       
   259     }
       
   260 }
   259 
   261 
   260 def combine(s: String) : String = {
   262 def combine(s: String) : String = {
   261   (for ((c, n) <- spl(s)) yield c match {
   263   val split_strings = split_by_repetition(s)
   262     case '>' => List('>', (n + '@').toChar)
   264   val lists = for (string <- split_strings) yield {
   263     case '<' => List('<', (n + '@').toChar)
   265     if (List("+"(0), "-"(0), "<"(0), ">"(0)).contains(string.head)) {
   264     case '+' => List('+', (n + '@').toChar)
   266       val long_repeat = s"${string.head}${alphabet.last}" * (string.size / alphabet.length)
   265     case '-' => List('-', (n + '@').toChar)
   267       val short_repeat = if ((string.size % alphabet.length) != 0) s"${string.head}${get_character_from_number(string.size % alphabet.length)}" else ""
   266     case _ => List(c)
   268       long_repeat + short_repeat
   267   }).flatten.mkString
   269     } else string
   268 }
   270   }
   269 
   271   lists.mkString("")
   270 
   272 }
   271 //combine(load_bff("benchmark.bf"))
   273 
       
   274 // testcase
       
   275 // combine(load_bff("./main5/benchmark.bf"))
       
   276 
   272 
   277 
   273 def compute4(pg: String, tb: Map[Int, Int], pc: Int, mp: Int, mem: Mem) : Mem = {
   278 def compute4(pg: String, tb: Map[Int, Int], pc: Int, mp: Int, mem: Mem) : Mem = {
   274   if (0 <= pc && pc < pg.length) { 
   279   pc match {
   275     val (new_pc, new_mp, new_mem) = pg(pc) match {
   280     case pc: Int if (pc >= 0 && pc < pg.length) => {
   276       case '0' => (pc + 1, mp, write(mem, mp, 0))
   281       pg(pc) match {
   277       case '>' => (pc + 2, mp + (pg(pc + 1) - '@'), mem)
   282         case '>' => val number = get_number_from_character(pg(pc + 1)); compute4(pg, tb, pc + 2, mp + number, mem)
   278       case '<' => (pc + 2, mp - (pg(pc + 1) - '@'), mem)
   283         case '<' => val number = get_number_from_character(pg(pc + 1)); compute4(pg, tb, pc + 2, mp - number, mem)
   279       case '+' => (pc + 2, mp, write(mem, mp, sread(mem, mp) + (pg(pc + 1) - '@')))
   284         case '+' => val number = get_number_from_character(pg(pc + 1)); compute4(pg, tb, pc + 2, mp, write(mem, mp, sread(mem, mp) + number))
   280       case '-' => (pc + 2, mp, write(mem, mp, sread(mem, mp) - (pg(pc + 1) - '@')))
   285         case '-' => val number = get_number_from_character(pg(pc + 1)); compute4(pg, tb, pc + 2, mp, write(mem, mp, sread(mem, mp) - number))
   281       case '.' => { print(sread(mem, mp).toChar); (pc + 1, mp, mem) }
   286         case '.' => print(sread(mem, mp).toChar); compute4(pg, tb, pc + 1, mp, mem)
   282       case ',' => (pc + 1, mp, write(mem, mp, Console.in.read().toByte))
   287         case '[' => if (sread(mem, mp) == 0) compute4(pg, tb, tb(pc), mp, mem) else compute4(pg, tb, pc + 1, mp, mem)
   283       case '['  => 
   288         case ']' => if (sread(mem, mp) != 0) compute4(pg, tb, tb(pc), mp, mem) else compute4(pg, tb, pc + 1, mp, mem)
   284 	if (sread(mem, mp) == 0) (tb(pc), mp, mem) else (pc + 1, mp, mem) 
   289         case '*' => compute4(pg, tb, pc + 1, mp, write(mem, mp, sread(mem, mp) * sread(mem, mp - 1)))
   285       case ']'  => 
   290         case '@' => compute4(pg, tb, pc + 1, mp, write(mem, mem(mp), sread(mem, mp - 1)))
   286 	if (sread(mem, mp) != 0) (tb(pc), mp, mem) else (pc + 1, mp, mem) 
   291         case '#' => print(sread(mem, mp)); compute4(pg, tb, pc + 1, mp, mem)
   287       case _ => (pc + 1, mp, mem)
   292         case '0' => compute4(pg, tb, pc + 1, mp, write(mem, mp, 0))
   288     }		     
   293         case _ => compute4(pg, tb, pc + 1, mp, mem)
   289     compute4(pg, tb, new_pc, new_mp, new_mem)	
   294       }
   290   }
   295     }
   291   else mem
   296     case _ => mem
   292 }
   297   }
   293 
   298 }
   294 def run4(pg: String, m: Mem = Map()) = { 
   299 
   295   val pg_opt = combine(optimise(pg))
   300 
   296   compute4(pg_opt, jtable(pg_opt), 0, 0, m)
   301 // should call first optimise and then combine on the input string
   297 }
   302 //
       
   303 def run4(pg: String, m: Mem = Map()) = {
       
   304   val processed_prog = combine(optimise(pg))
       
   305   compute4(processed_prog, jtable(processed_prog), 0, 0, m)
       
   306 }
       
   307 
   298 
   308 
   299 // testcases
   309 // testcases
   300 //combine(optimise(load_bff("benchmark.bf"))) // => """>A+B[<A+M>A-A]<A[[....."""
   310 // combine(optimise(load_bff("./main5/benchmark.bf"))) // => """>A+B[<A+M>A-A]<A[[....."""
   301 //combine(optimise(load_bff("benchmark.bf"))).length // => 134
   311 
   302 //combine(optimise(load_bff("mandelbrot.bf"))).length // => 6509
   312 // testcases (they should now run much faster)
   303 
   313 // time_needed(1, run4(load_bff("./main5/benchmark.bf")))
   304 //time_needed(1, run4(load_bff("benchmark.bf")))
   314 // time_needed(1, run4(load_bff("./main5/sierpinski.bf"))) 
   305 
   315 // time_needed(1, run4(load_bff("./main5/mandelbrot.bf")))
   306 //time_needed(1, run(load_bff("sierpinski.bf"))) 
   316 
   307 //time_needed(1, run4(load_bff("sierpinski.bf"))) 
   317 
   308 
   318 }
   309 //time_needed(1, run4(load_bff("mandelbrot.bf")))
       
   310 
       
   311 
       
   312 }