progs/fun/funt.sc
changeset 789 f0696713177b
parent 734 5d860ff01938
child 813 059f970287d1
equal deleted inserted replaced
788:3b1136fb6bee 789:f0696713177b
       
     1 // A Small Compiler for a Simple Functional Language
       
     2 // (includes a lexer and a parser)
       
     3 
       
     4 import $file.fun_tokens, fun_tokens._
       
     5 import $file.fun_parser, fun_parser._ 
       
     6 
       
     7 // compiler - built-in functions 
       
     8 // copied from http://www.ceng.metu.edu.tr/courses/ceng444/link/jvm-cpm.html
       
     9 //
       
    10 
       
    11 val library = """
       
    12 .class public XXX.XXX
       
    13 .super java/lang/Object
       
    14 
       
    15 .method public static write(I)V 
       
    16         .limit locals 1 
       
    17         .limit stack 2 
       
    18         getstatic java/lang/System/out Ljava/io/PrintStream; 
       
    19         iload 0
       
    20         invokevirtual java/io/PrintStream/println(I)V 
       
    21         return 
       
    22 .end method
       
    23 
       
    24 """
       
    25 
       
    26 // calculating the maximal needed stack size
       
    27 def max_stack_exp(e: Exp): Int = e match {
       
    28   case Call(_, args) => args.map(max_stack_exp).sum
       
    29   case If(a, e1, e2) => max_stack_bexp(a) + (List(max_stack_exp(e1), max_stack_exp(e2)).max)
       
    30   case Write(e) => max_stack_exp(e) + 1
       
    31   case Var(_) => 1
       
    32   case Num(_) => 1
       
    33   case Aop(_, a1, a2) => max_stack_exp(a1) + max_stack_exp(a2)
       
    34   case Sequence(e1, e2) => List(max_stack_exp(e1), max_stack_exp(e2)).max
       
    35 }
       
    36 
       
    37 def max_stack_bexp(e: BExp): Int = e match {
       
    38   case Bop(_, a1, a2) => max_stack_exp(a1) + max_stack_exp(a2)
       
    39 }
       
    40 
       
    41 
       
    42 // for generating new labels
       
    43 var counter = -1
       
    44 
       
    45 def Fresh(x: String) = {
       
    46   counter += 1
       
    47   x ++ "_" ++ counter.toString()
       
    48 }
       
    49 
       
    50 // convenient string interpolations 
       
    51 // for instructions, labels and methods
       
    52 import scala.language.implicitConversions
       
    53 import scala.language.reflectiveCalls
       
    54 
       
    55 implicit def sring_inters(sc: StringContext) = new {
       
    56     def i(args: Any*): String = "   " ++ sc.s(args:_*) ++ "\n"
       
    57     def l(args: Any*): String = sc.s(args:_*) ++ ":\n"
       
    58     def m(args: Any*): String = sc.s(args:_*) ++ "\n"
       
    59 }
       
    60 
       
    61 
       
    62 type Env = Map[String, Int]
       
    63 
       
    64 
       
    65 def compile_expT(a: Exp, env : Env, name: String) : String = a match {
       
    66   case Num(i) => i"ldc $i"
       
    67   case Var(s) => i"iload ${env(s)}"
       
    68   case Aop("+", a1, a2) => compile_expT(a1, env, "") ++ compile_expT(a2, env, "") ++ i"iadd"
       
    69   case Aop("-", a1, a2) => compile_expT(a1, env, "") ++ compile_expT(a2, env, "") ++ i"isub"
       
    70   case Aop("*", a1, a2) => compile_expT(a1, env, "") ++ compile_expT(a2, env, "") ++ i"imul"
       
    71   case Aop("/", a1, a2) => compile_expT(a1, env, "") ++ compile_expT(a2, env, "") ++ i"idiv"
       
    72   case Aop("%", a1, a2) => compile_expT(a1, env, "") ++ compile_expT(a2, env, "") ++ i"irem"
       
    73   case If(b, a1, a2) => {
       
    74     val if_else = Fresh("If_else")
       
    75     val if_end = Fresh("If_end")
       
    76     compile_bexpT(b, env, if_else) ++
       
    77     compile_expT(a1, env, name) ++
       
    78     i"goto $if_end" ++
       
    79     l"$if_else" ++
       
    80     compile_expT(a2, env, name) ++
       
    81     l"$if_end"
       
    82   }
       
    83   case Call(n, args) => if (name == n) { 
       
    84     val stores = args.zipWithIndex.map { case (x, y) => i"istore $y" } 
       
    85     args.map(a => compile_expT(a, env, "")).mkString ++
       
    86     stores.reverse.mkString ++ 
       
    87     i"goto ${n}_Start" 
       
    88   } else {
       
    89     val is = "I" * args.length
       
    90     args.map(a => compile_expT(a, env, "")).mkString ++
       
    91     i"invokestatic XXX/XXX/${n}(${is})I"
       
    92   }
       
    93   case Sequence(a1, a2) => {
       
    94     compile_expT(a1, env, "") ++ i"pop" ++ compile_expT(a2, env, name)
       
    95   }
       
    96   case Write(a1) => {
       
    97     compile_expT(a1, env, "") ++
       
    98     i"dup" ++
       
    99     i"invokestatic XXX/XXX/write(I)V"
       
   100   }
       
   101 }
       
   102 
       
   103 def compile_bexpT(b: BExp, env : Env, jmp: String) : String = b match {
       
   104   case Bop("==", a1, a2) => 
       
   105     compile_expT(a1, env, "") ++ compile_expT(a2, env, "") ++ i"if_icmpne $jmp"
       
   106   case Bop("!=", a1, a2) => 
       
   107     compile_expT(a1, env, "") ++ compile_expT(a2, env, "") ++ i"if_icmpeq $jmp"
       
   108   case Bop("<", a1, a2) => 
       
   109     compile_expT(a1, env, "") ++ compile_expT(a2, env, "") ++ i"if_icmpge $jmp"
       
   110   case Bop("<=", a1, a2) => 
       
   111     compile_expT(a1, env, "") ++ compile_expT(a2, env, "") ++ i"if_icmpgt $jmp"
       
   112 }
       
   113 
       
   114 
       
   115 def compile_decl(d: Decl) : String = d match {
       
   116   case Def(name, args, a) => { 
       
   117     val env = args.zipWithIndex.toMap
       
   118     val is = "I" * args.length
       
   119     m".method public static $name($is)I" ++
       
   120     m".limit locals ${args.length}" ++
       
   121     m".limit stack ${1 + max_stack_exp(a)}" ++
       
   122     l"${name}_Start" ++   
       
   123     compile_expT(a, env, name) ++
       
   124     i"ireturn" ++ 
       
   125     m".end method\n"
       
   126   }
       
   127   case Main(a) => {
       
   128     m".method public static main([Ljava/lang/String;)V" ++
       
   129     m".limit locals 200" ++
       
   130     m".limit stack 200" ++
       
   131     compile_expT(a, Map(), "") ++
       
   132     i"invokestatic XXX/XXX/write(I)V" ++
       
   133     i"return" ++
       
   134     m".end method"
       
   135   }
       
   136 }
       
   137 
       
   138 // main compiler functions
       
   139 def compile(prog: List[Decl], class_name: String) : String = {
       
   140   val instructions = prog.map(compile_decl).mkString
       
   141   (library + instructions).replaceAllLiterally("XXX", class_name)
       
   142 }
       
   143 
       
   144 
       
   145 @main
       
   146 def main(fname: String) = {
       
   147     val path = os.pwd / fname
       
   148     val class_name = fname.stripSuffix("." ++ path.ext)
       
   149     val tks = tokenise(os.read(path))
       
   150     val ast = parse_tks(tks)
       
   151     println(compile(ast, class_name))
       
   152 }
       
   153 
       
   154 /*
       
   155 
       
   156 import scala.sys.process._
       
   157 
       
   158 def compile_run(class_name: String) : Unit = {
       
   159   compile_file(class_name)
       
   160   (s"java -jar jvm/jasmin-2.4/jasmin.jar ${class_name}.j").!!
       
   161   println("Time: " + time_needed(2, (s"java ${class_name}/${class_name}").!))
       
   162 }
       
   163 
       
   164 
       
   165 //examples
       
   166 compile_run("defs")
       
   167 compile_run("fact")
       
   168 */