83   | 
    84   | 
    84 .method public static main([Ljava/lang/String;)V  | 
    85 .method public static main([Ljava/lang/String;)V  | 
    85    .limit locals 200  | 
    86    .limit locals 200  | 
    86    .limit stack 200  | 
    87    .limit stack 200  | 
    87   | 
    88   | 
         | 
    89 ; COMPILED CODE STARTS  | 
         | 
    90   | 
    88 """  | 
    91 """  | 
    89   | 
    92   | 
    90 val ending = """  | 
    93 val ending = """  | 
    91   | 
    94 ; COMPILED CODE ENDS  | 
    92    return  | 
    95    return  | 
    93   | 
    96   | 
    94 .end method  | 
    97 .end method  | 
    95 """  | 
    98 """  | 
    96   | 
    99   | 
    97 println("Start compilation") | 
   100 // Compiler functions  | 
    98   | 
   101   | 
    99   | 
   102   | 
   100 // for generating new labels  | 
   103 // for generating new labels  | 
   101 var counter = -1  | 
   104 var counter = -1  | 
   102   | 
   105   | 
   103 def Fresh(x: String) = { | 
   106 def Fresh(x: String) = { | 
   104   counter += 1  | 
   107   counter += 1  | 
   105   x ++ "_" ++ counter.toString()  | 
   108   x ++ "_" ++ counter.toString()  | 
   106 }  | 
   109 }  | 
   107   | 
   110   | 
   108 // environments and instructions  | 
   111 // convenient string interpolations   | 
         | 
   112 // for instructions and labels  | 
         | 
   113 import scala.language.implicitConversions  | 
         | 
   114 import scala.language.reflectiveCalls  | 
         | 
   115   | 
         | 
   116 implicit def sring_inters(sc: StringContext) = new { | 
         | 
   117     def i(args: Any*): String = "   " ++ sc.s(args:_*) ++ "\n"  | 
         | 
   118     def l(args: Any*): String = sc.s(args:_*) ++ ":\n"  | 
         | 
   119 }  | 
         | 
   120   | 
         | 
   121   | 
         | 
   122 // environments   | 
   109 type Env = Map[String, String]  | 
   123 type Env = Map[String, String]  | 
   110 type Instrs = List[String]  | 
         | 
   111   | 
   124   | 
   112 // arithmetic expression compilation  | 
   125 // arithmetic expression compilation  | 
   113 def compile_aexp(a: AExp, env : Env) : Instrs = a match { | 
   126 def compile_aexp(a: AExp, env : Env) : String = a match { | 
   114   case Num(i) => List("ldc " + i.toString + "\n") | 
   127   case Num(i) => i"ldc $i"  | 
   115   case Var(s) => List("iload " + env(s) + "\n") | 
   128   case Var(s) => i"iload ${env(s)}" | 
   116   case Aop("+", a1, a2) =>  | 
   129   case Aop("+", a1, a2) =>  | 
   117     compile_aexp(a1, env) ++   | 
   130     compile_aexp(a1, env) ++ compile_aexp(a2, env) ++ i"iadd"  | 
   118     compile_aexp(a2, env) ++ List("iadd\n") | 
         | 
   119   case Aop("-", a1, a2) =>  | 
   131   case Aop("-", a1, a2) =>  | 
   120     compile_aexp(a1, env) ++ compile_aexp(a2, env) ++ List("isub\n") | 
   132     compile_aexp(a1, env) ++ compile_aexp(a2, env) ++ i"isub"  | 
   121   case Aop("*", a1, a2) =>  | 
   133   case Aop("*", a1, a2) =>  | 
   122     compile_aexp(a1, env) ++ compile_aexp(a2, env) ++ List("imul\n") | 
   134     compile_aexp(a1, env) ++ compile_aexp(a2, env) ++ i"imul"  | 
   123 }  | 
   135 }  | 
   124   | 
   136   | 
   125 // boolean expression compilation  | 
   137 // boolean expression compilation  | 
   126 def compile_bexp(b: BExp, env : Env, jmp: String) : Instrs = b match { | 
   138 def compile_bexp(b: BExp, env : Env, jmp: String) : String = b match { | 
   127   case True => Nil  | 
   139   case True => ""  | 
   128   case False => List("goto " + jmp + "\n") | 
   140   case False => i"goto $jmp"  | 
   129   case Bop("=", a1, a2) =>  | 
   141   case Bop("=", a1, a2) =>  | 
   130     compile_aexp(a1, env) ++ compile_aexp(a2, env) ++   | 
   142     compile_aexp(a1, env) ++ compile_aexp(a2, env) ++ i"if_icmpne $jmp"  | 
   131     List("if_icmpne " + jmp + "\n") | 
         | 
   132   case Bop("!=", a1, a2) =>  | 
   143   case Bop("!=", a1, a2) =>  | 
   133     compile_aexp(a1, env) ++ compile_aexp(a2, env) ++   | 
   144     compile_aexp(a1, env) ++ compile_aexp(a2, env) ++ i"if_icmpeq $jmp"  | 
   134     List("if_icmpeq " + jmp + "\n") | 
         | 
   135   case Bop("<", a1, a2) =>  | 
   145   case Bop("<", a1, a2) =>  | 
   136     compile_aexp(a1, env) ++ compile_aexp(a2, env) ++   | 
   146     compile_aexp(a1, env) ++ compile_aexp(a2, env) ++ i"if_icmpge $jmp"  | 
   137     List("if_icmpge " + jmp + "\n") | 
         | 
   138 }  | 
   147 }  | 
   139   | 
   148   | 
   140 // statement compilation  | 
   149 // statement compilation  | 
   141 def compile_stmt(s: Stmt, env: Env) : (Instrs, Env) = s match { | 
   150 def compile_stmt(s: Stmt, env: Env) : (String, Env) = s match { | 
   142   case Skip => (Nil, env)  | 
   151   case Skip => ("", env) | 
   143   case Assign(x, a) => { | 
   152   case Assign(x, a) => { | 
   144     val index = if (env.isDefinedAt(x)) env(x) else   | 
   153     val index = if (env.isDefinedAt(x)) env(x) else   | 
   145                     env.keys.size.toString  | 
   154                     env.keys.size.toString  | 
   146     (compile_aexp(a, env) ++   | 
   155     (compile_aexp(a, env) ++ i"istore $index", env + (x -> index))  | 
   147      List("istore " + index + "\n"), env + (x -> index)) | 
         | 
   148   }   | 
   156   }   | 
   149   case If(b, bl1, bl2) => { | 
   157   case If(b, bl1, bl2) => { | 
   150     val if_else = Fresh("If_else") | 
   158     val if_else = Fresh("If_else") | 
   151     val if_end = Fresh("If_end") | 
   159     val if_end = Fresh("If_end") | 
   152     val (instrs1, env1) = compile_block(bl1, env)  | 
   160     val (instrs1, env1) = compile_block(bl1, env)  | 
   153     val (instrs2, env2) = compile_block(bl2, env1)  | 
   161     val (instrs2, env2) = compile_block(bl2, env1)  | 
   154     (compile_bexp(b, env, if_else) ++  | 
   162     (compile_bexp(b, env, if_else) ++  | 
   155      instrs1 ++  | 
   163      instrs1 ++  | 
   156      List("goto " + if_end + "\n") ++ | 
   164      i"goto $if_end" ++  | 
   157      List("\n" + if_else + ":\n\n") ++ | 
   165      l"$if_else" ++  | 
   158      instrs2 ++  | 
   166      instrs2 ++  | 
   159      List("\n" + if_end + ":\n\n"), env2) | 
   167      l"$if_end", env2)  | 
   160   }  | 
   168   }  | 
   161   case While(b, bl) => { | 
   169   case While(b, bl) => { | 
   162     val loop_begin = Fresh("Loop_begin") | 
   170     val loop_begin = Fresh("Loop_begin") | 
   163     val loop_end = Fresh("Loop_end") | 
   171     val loop_end = Fresh("Loop_end") | 
   164     val (instrs1, env1) = compile_block(bl, env)  | 
   172     val (instrs1, env1) = compile_block(bl, env)  | 
   165     (List("\n" + loop_begin + ":\n\n") ++ | 
   173     (l"$loop_begin" ++  | 
   166      compile_bexp(b, env, loop_end) ++  | 
   174      compile_bexp(b, env, loop_end) ++  | 
   167      instrs1 ++  | 
   175      instrs1 ++  | 
   168      List("goto " + loop_begin + "\n") ++ | 
   176      i"goto $loop_begin" ++  | 
   169      List("\n" + loop_end + ":\n\n"), env1) | 
   177      l"$loop_end", env1)  | 
   170   }  | 
   178   }  | 
   171   case Write(x) =>   | 
   179   case Write(x) =>   | 
   172     (List("iload " + env(x) + "\n" +  | 
   180     (i"iload ${env(x)}" ++  | 
   173            "invokestatic XXX/XXX/write(I)V\n"), env)  | 
   181      i"invokestatic XXX/XXX/write(I)V", env)  | 
   174   case Read(x) => { | 
   182   case Read(x) => { | 
   175     val index = if (env.isDefinedAt(x)) env(x) else   | 
   183     val index = if (env.isDefinedAt(x)) env(x) else   | 
   176                     env.keys.size.toString  | 
   184                     env.keys.size.toString  | 
   177     (List("invokestatic XXX/XXX/read()I\n" +  | 
   185     (i"invokestatic XXX/XXX/read()I" ++   | 
   178           "istore " + index + "\n"), env + (x -> index))  | 
   186      i"istore $index", env + (x -> index))  | 
   179   }  | 
   187   }  | 
   180 }  | 
   188 }  | 
   181   | 
   189   | 
   182 // compilation of a block (i.e. list of instructions)  | 
   190 // compilation of a block (i.e. list of instructions)  | 
   183 def compile_block(bl: Block, env: Env) : (Instrs, Env) = bl match { | 
   191 def compile_block(bl: Block, env: Env) : (String, Env) = bl match { | 
   184   case Nil => (Nil, env)  | 
   192   case Nil => ("", env) | 
   185   case s::bl => { | 
   193   case s::bl => { | 
   186     val (instrs1, env1) = compile_stmt(s, env)  | 
   194     val (instrs1, env1) = compile_stmt(s, env)  | 
   187     val (instrs2, env2) = compile_block(bl, env1)  | 
   195     val (instrs2, env2) = compile_block(bl, env1)  | 
   188     (instrs1 ++ instrs2, env2)  | 
   196     (instrs1 ++ instrs2, env2)  | 
   189   }  | 
   197   }  |