solutions/cw4/compiler.sc
changeset 920 7af2eea19646
parent 910 b655ce68983f
child 921 bb54e7aa1a3f
--- a/solutions/cw4/compiler.sc	Sun Sep 17 19:12:57 2023 +0100
+++ b/solutions/cw4/compiler.sc	Tue Sep 19 09:54:41 2023 +0100
@@ -92,7 +92,7 @@
   x ++ "_" ++ counter.toString()
 }
 
-implicit def string_interpolations(sc: StringContext) = new {
+extension (sc: StringContext) {
     def i(args: Any*): String = "   " ++ sc.s(args:_*) ++ "\n"
     def l(args: Any*): String = sc.s(args:_*) ++ ":\n"
 }
@@ -138,7 +138,7 @@
     compile_aexp(a1, env) ++ compile_aexp(a2, env) ++ i"${compile_bop(op)} $jmp"
 }
 
-def compile_stmt(s: Stmt, env: Env) : (String, Env) = s match {
+def compile_stmt(s: Stmt, env: Env, break: String) : (String, Env) = s match {
   case Skip => ("", env)
   case Assign(x, a) => {
     val index = env.getOrElse(x, env.keys.size)
@@ -147,8 +147,8 @@
   case If(b, bl1, bl2) => {
     val if_else = Fresh("If_else")
     val if_end = Fresh("If_end")
-    val (instrs1, env1) = compile_block(bl1, env)
-    val (instrs2, env2) = compile_block(bl2, env1)
+    val (instrs1, env1) = compile_block(bl1, env, break)
+    val (instrs2, env2) = compile_block(bl2, env1, break)
     (compile_bexp(b, env, if_else) ++
      instrs1 ++
      i"goto $if_end" ++
@@ -159,7 +159,7 @@
   case While(b, bl) => {
     val loop_begin = Fresh("Loop_begin")
     val loop_end = Fresh("Loop_end")
-    val (instrs1, env1) = compile_block(bl, env)
+    val (instrs1, env1) = compile_block(bl, env, break)
     (l"$loop_begin" ++
      compile_bexp(b, env, loop_end) ++
      instrs1 ++
@@ -167,17 +167,18 @@
      l"$loop_end", env1)
   }
   case For(id, lower, upper, code) => {
-      val (assignment_code, env1) = compile_stmt(Assign(id, lower), env)  // id := lower;
+      val (assignment_code, env1) = compile_stmt(Assign(id, lower), env, break)  // id := lower;
       val while_equivalent = While(
           Or(Bop("<", Var(id), upper), Bop("==", Var(id), upper)),    // while id <= upper do {
           code ++                                                     //    code  
           List(
             Assign(id, Aop("+", Var(id), Num(1)))                     //    id := id + 1
           ))                                                          // };
-
-      val (while_code, env2) = compile_stmt(while_equivalent, env1)
-      (assignment_code ++ while_code, env2)
+      val new_break = Fresh("for_break")
+      val (while_code, env2) = compile_stmt(while_equivalent, env1, new_break)
+      (assignment_code ++ while_code ++ l"$new_break", env2)
   }
+  case Break => (i"goto $break", env)
   case WriteId(x) => (i"iload ${env(x)} \t\t; $x" ++ 
      i"invokestatic XXX/XXX/write(I)V", env)
   case WriteString(x) => (s"   ldc ${x}\n" ++
@@ -189,38 +190,33 @@
   }
 }
 
-def compile_block(bl: Block, env: Env) : (String, Env) = bl match {
+def compile_block(bl: Block, env: Env, break: String) : (String, Env) = bl match {
   case Nil => ("", env)
   case s::bl => {
-    val (instrs1, env1) = compile_stmt(s, env)
-    val (instrs2, env2) = compile_block(bl, env1)
+    val (instrs1, env1) = compile_stmt(s, env, break)
+    val (instrs2, env2) = compile_block(bl, env1, break)
     (instrs1 ++ instrs2, env2)
   }
 }
 
 def compile(bl: Block, class_name: String) : String = {
-  val instructions = compile_block(bl, Map.empty)._1
-  (beginning ++ instructions ++ ending).replaceAllLiterally("XXX", class_name)
+  val prog_end = Fresh("Prog_end")
+  val instructions = compile_block(bl, Map.empty, prog_end)._1
+  (beginning ++ instructions ++ l"$prog_end" ++ ending).replaceAllLiterally("XXX", class_name)
 }
 
 // Compiling and running
 
-import scala.util._
-import scala.sys.process._
-import scala.io
 
-def compile_tofile(bl: Block, class_name: String) = {
-  val output = compile(bl, class_name)
-  val fw = new java.io.FileWriter(class_name + ".j") 
-  fw.write(output) 
-  fw.close()
-}
+def compile_to_file(bl: Block, class_name: String) : Unit = 
+  os.write.over(os.pwd / s"$class_name.j", compile(bl, class_name))  
 
 def compile_all(bl: Block, class_name: String) : Unit = {
-  compile_tofile(bl, class_name)
-  println("compiled ")
-  val test = ("java -jar jasmin.jar " + class_name + ".j").!!
-  println("assembled ")
+  println(s"Start of compilation")
+  compile_to_file(bl, class_name)
+  println(s"generated $class_name.j file")
+  os.proc("java", "-jar", "jasmin.jar", s"$class_name.j").call()
+  println(s"generated $class_name.class file ")
 }
 
 def time_needed[T](i: Int, code: => T) = {
@@ -231,10 +227,10 @@
 }
 
 def compile_run(bl: Block, class_name: String) : Unit = {
-  println("Start compilation")
   compile_all(bl, class_name)
   println("running")
-  println("Time: " + time_needed(1, ("java " + class_name + "/" + class_name).!))
+  os.proc("java", s"${class_name}/${class_name}").call(stdout = os.Inherit)
+  println(s"done.")
 }
 
 // ---- Q1
@@ -280,4 +276,8 @@
 }""")).head, "nestedloop") */
 
 
-compile_run(Stmts.parse_all(tokenise(os.read(os.pwd / "collatz2.while"))).head, "collatz2")
+//compile_run(Stmts.parse_all(tokenise(os.read(os.pwd / "collatz2.while"))).head, "collatz2")
+
+
+println(tokenise(os.read(os.pwd / "forloop.while")))
+compile_run(Stmts.parse_all(tokenise(os.read(os.pwd / "forloop.while"))).head, "forloop")
\ No newline at end of file