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