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