progs/compile.scala
changeset 624 8d0af38389bc
parent 609 e33545bb2eba
child 625 6709fa87410b
equal deleted inserted replaced
623:47a299e7010f 624:8d0af38389bc
     1 // A Small Compiler for the WHILE Language
     1 // A Small Compiler for the WHILE Language
     2 // (it does not use a parser and lexer)
     2 // (it does not use a parser and lexer)
       
     3 
     3 
     4 
     4 // the abstract syntax trees
     5 // the abstract syntax trees
     5 abstract class Stmt
     6 abstract class Stmt
     6 abstract class AExp
     7 abstract class AExp
     7 abstract class BExp 
     8 abstract class BExp 
    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   }
   235 
   243 
   236 
   244 
   237 def compile_run(bl: Block, class_name: String) : Unit = {
   245 def compile_run(bl: Block, class_name: String) : Unit = {
   238   println("Start compilation")
   246   println("Start compilation")
   239   compile_all(bl, class_name)
   247   compile_all(bl, class_name)
       
   248   println("running")
   240   println("Time: " + time_needed(1, ("java " + class_name + "/" + class_name).!))
   249   println("Time: " + time_needed(1, ("java " + class_name + "/" + class_name).!))
   241 }
   250 }
   242 
   251 
   243 
   252 
   244 // Fibonacci numbers as a test-case
   253 // Fibonacci numbers as a test-case