136 } |
136 } |
137 case Bop(op, a1, a2) => |
137 case Bop(op, a1, a2) => |
138 compile_aexp(a1, env) ++ compile_aexp(a2, env) ++ i"${compile_bop(op)} $jmp" |
138 compile_aexp(a1, env) ++ compile_aexp(a2, env) ++ i"${compile_bop(op)} $jmp" |
139 } |
139 } |
140 |
140 |
141 def compile_stmt(s: Stmt, env: Env) : (String, Env) = s match { |
141 def compile_stmt(s: Stmt, env: Env, break: String) : (String, Env) = s match { |
142 case Skip => ("", env) |
142 case Skip => ("", env) |
143 case Assign(x, a) => { |
143 case Assign(x, a) => { |
144 val index = env.getOrElse(x, env.keys.size) |
144 val index = env.getOrElse(x, env.keys.size) |
145 (compile_aexp(a, env) ++ i"istore $index \t\t; $x", env + (x -> index)) |
145 (compile_aexp(a, env) ++ i"istore $index \t\t; $x", env + (x -> index)) |
146 } |
146 } |
147 case If(b, bl1, bl2) => { |
147 case If(b, bl1, bl2) => { |
148 val if_else = Fresh("If_else") |
148 val if_else = Fresh("If_else") |
149 val if_end = Fresh("If_end") |
149 val if_end = Fresh("If_end") |
150 val (instrs1, env1) = compile_block(bl1, env) |
150 val (instrs1, env1) = compile_block(bl1, env, break) |
151 val (instrs2, env2) = compile_block(bl2, env1) |
151 val (instrs2, env2) = compile_block(bl2, env1, break) |
152 (compile_bexp(b, env, if_else) ++ |
152 (compile_bexp(b, env, if_else) ++ |
153 instrs1 ++ |
153 instrs1 ++ |
154 i"goto $if_end" ++ |
154 i"goto $if_end" ++ |
155 l"$if_else" ++ |
155 l"$if_else" ++ |
156 instrs2 ++ |
156 instrs2 ++ |
157 l"$if_end", env2) |
157 l"$if_end", env2) |
158 } |
158 } |
159 case While(b, bl) => { |
159 case While(b, bl) => { |
160 val loop_begin = Fresh("Loop_begin") |
160 val loop_begin = Fresh("Loop_begin") |
161 val loop_end = Fresh("Loop_end") |
161 val loop_end = Fresh("Loop_end") |
162 val (instrs1, env1) = compile_block(bl, env) |
162 val (instrs1, env1) = compile_block(bl, env, break) |
163 (l"$loop_begin" ++ |
163 (l"$loop_begin" ++ |
164 compile_bexp(b, env, loop_end) ++ |
164 compile_bexp(b, env, loop_end) ++ |
165 instrs1 ++ |
165 instrs1 ++ |
166 i"goto $loop_begin" ++ |
166 i"goto $loop_begin" ++ |
167 l"$loop_end", env1) |
167 l"$loop_end", env1) |
168 } |
168 } |
169 case For(id, lower, upper, code) => { |
169 case For(id, lower, upper, code) => { |
170 val (assignment_code, env1) = compile_stmt(Assign(id, lower), env) // id := lower; |
170 val (assignment_code, env1) = compile_stmt(Assign(id, lower), env, break) // id := lower; |
171 val while_equivalent = While( |
171 val while_equivalent = While( |
172 Or(Bop("<", Var(id), upper), Bop("==", Var(id), upper)), // while id <= upper do { |
172 Or(Bop("<", Var(id), upper), Bop("==", Var(id), upper)), // while id <= upper do { |
173 code ++ // code |
173 code ++ // code |
174 List( |
174 List( |
175 Assign(id, Aop("+", Var(id), Num(1))) // id := id + 1 |
175 Assign(id, Aop("+", Var(id), Num(1))) // id := id + 1 |
176 )) // }; |
176 )) // }; |
177 |
177 val new_break = Fresh("for_break") |
178 val (while_code, env2) = compile_stmt(while_equivalent, env1) |
178 val (while_code, env2) = compile_stmt(while_equivalent, env1, new_break) |
179 (assignment_code ++ while_code, env2) |
179 (assignment_code ++ while_code ++ l"$new_break", env2) |
180 } |
180 } |
|
181 case Break => (i"goto $break", env) |
181 case WriteId(x) => (i"iload ${env(x)} \t\t; $x" ++ |
182 case WriteId(x) => (i"iload ${env(x)} \t\t; $x" ++ |
182 i"invokestatic XXX/XXX/write(I)V", env) |
183 i"invokestatic XXX/XXX/write(I)V", env) |
183 case WriteString(x) => (s" ldc ${x}\n" ++ |
184 case WriteString(x) => (s" ldc ${x}\n" ++ |
184 i"invokestatic XXX/XXX/writes(Ljava/lang/String;)V", env) |
185 i"invokestatic XXX/XXX/writes(Ljava/lang/String;)V", env) |
185 case Read(x) => { |
186 case Read(x) => { |
187 (i"invokestatic XXX/XXX/read()I" ++ |
188 (i"invokestatic XXX/XXX/read()I" ++ |
188 i"istore $index \t\t; $x", env + (x -> index)) |
189 i"istore $index \t\t; $x", env + (x -> index)) |
189 } |
190 } |
190 } |
191 } |
191 |
192 |
192 def compile_block(bl: Block, env: Env) : (String, Env) = bl match { |
193 def compile_block(bl: Block, env: Env, break: String) : (String, Env) = bl match { |
193 case Nil => ("", env) |
194 case Nil => ("", env) |
194 case s::bl => { |
195 case s::bl => { |
195 val (instrs1, env1) = compile_stmt(s, env) |
196 val (instrs1, env1) = compile_stmt(s, env, break) |
196 val (instrs2, env2) = compile_block(bl, env1) |
197 val (instrs2, env2) = compile_block(bl, env1, break) |
197 (instrs1 ++ instrs2, env2) |
198 (instrs1 ++ instrs2, env2) |
198 } |
199 } |
199 } |
200 } |
200 |
201 |
201 def compile(bl: Block, class_name: String) : String = { |
202 def compile(bl: Block, class_name: String) : String = { |
202 val instructions = compile_block(bl, Map.empty)._1 |
203 val prog_end = Fresh("Prog_end") |
203 (beginning ++ instructions ++ ending).replaceAllLiterally("XXX", class_name) |
204 val instructions = compile_block(bl, Map.empty, prog_end)._1 |
|
205 (beginning ++ instructions ++ l"$prog_end" ++ ending).replaceAllLiterally("XXX", class_name) |
204 } |
206 } |
205 |
207 |
206 // Compiling and running |
208 // Compiling and running |
207 |
209 |
208 import scala.util._ |
210 |
209 import scala.sys.process._ |
211 def compile_to_file(bl: Block, class_name: String) : Unit = |
210 import scala.io |
212 os.write.over(os.pwd / s"$class_name.j", compile(bl, class_name)) |
211 |
|
212 def compile_tofile(bl: Block, class_name: String) = { |
|
213 val output = compile(bl, class_name) |
|
214 val fw = new java.io.FileWriter(class_name + ".j") |
|
215 fw.write(output) |
|
216 fw.close() |
|
217 } |
|
218 |
213 |
219 def compile_all(bl: Block, class_name: String) : Unit = { |
214 def compile_all(bl: Block, class_name: String) : Unit = { |
220 compile_tofile(bl, class_name) |
215 println(s"Start of compilation") |
221 println("compiled ") |
216 compile_to_file(bl, class_name) |
222 val test = ("java -jar jasmin.jar " + class_name + ".j").!! |
217 println(s"generated $class_name.j file") |
223 println("assembled ") |
218 os.proc("java", "-jar", "jasmin.jar", s"$class_name.j").call() |
|
219 println(s"generated $class_name.class file ") |
224 } |
220 } |
225 |
221 |
226 def time_needed[T](i: Int, code: => T) = { |
222 def time_needed[T](i: Int, code: => T) = { |
227 val start = System.nanoTime() |
223 val start = System.nanoTime() |
228 for (j <- 1 to i) code |
224 for (j <- 1 to i) code |
229 val end = System.nanoTime() |
225 val end = System.nanoTime() |
230 (end - start)/(i * 1.0e9) |
226 (end - start)/(i * 1.0e9) |
231 } |
227 } |
232 |
228 |
233 def compile_run(bl: Block, class_name: String) : Unit = { |
229 def compile_run(bl: Block, class_name: String) : Unit = { |
234 println("Start compilation") |
|
235 compile_all(bl, class_name) |
230 compile_all(bl, class_name) |
236 println("running") |
231 println("running") |
237 println("Time: " + time_needed(1, ("java " + class_name + "/" + class_name).!)) |
232 os.proc("java", s"${class_name}/${class_name}").call(stdout = os.Inherit) |
|
233 println(s"done.") |
238 } |
234 } |
239 |
235 |
240 // ---- Q1 |
236 // ---- Q1 |
241 |
237 |
242 // Fibonacci |
238 // Fibonacci |