solutions/cw4/compiler.sc
changeset 920 7af2eea19646
parent 910 b655ce68983f
child 921 bb54e7aa1a3f
equal deleted inserted replaced
919:53f08d873e09 920:7af2eea19646
    90 def Fresh(x: String) = {
    90 def Fresh(x: String) = {
    91   counter += 1
    91   counter += 1
    92   x ++ "_" ++ counter.toString()
    92   x ++ "_" ++ counter.toString()
    93 }
    93 }
    94 
    94 
    95 implicit def string_interpolations(sc: StringContext) = new {
    95 extension (sc: StringContext) {
    96     def i(args: Any*): String = "   " ++ sc.s(args:_*) ++ "\n"
    96     def i(args: Any*): String = "   " ++ sc.s(args:_*) ++ "\n"
    97     def l(args: Any*): String = sc.s(args:_*) ++ ":\n"
    97     def l(args: Any*): String = sc.s(args:_*) ++ ":\n"
    98 }
    98 }
    99 
    99 
   100 type Env = Map[String, Int]
   100 type Env = Map[String, Int]
   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
   278     write i
   274     write i
   279   }
   275   }
   280 }""")).head, "nestedloop") */
   276 }""")).head, "nestedloop") */
   281 
   277 
   282 
   278 
   283 compile_run(Stmts.parse_all(tokenise(os.read(os.pwd / "collatz2.while"))).head, "collatz2")
   279 //compile_run(Stmts.parse_all(tokenise(os.read(os.pwd / "collatz2.while"))).head, "collatz2")
       
   280 
       
   281 
       
   282 println(tokenise(os.read(os.pwd / "forloop.while")))
       
   283 compile_run(Stmts.parse_all(tokenise(os.read(os.pwd / "forloop.while"))).head, "forloop")