progs/fun/fun.sc
changeset 813 059f970287d1
parent 789 f0696713177b
child 814 1fbaa5f05516
equal deleted inserted replaced
812:2f9a0dcf61ae 813:059f970287d1
     1 // A Small Compiler for a Simple Functional Language
     1 // A Small Compiler for a Simple Functional Language
     2 // (it does not include a parser and lexer)
     2 // (includes a parser and lexer)
     3 //
     3 //
     4 // call with
     4 // call with
     5 //
     5 //
       
     6 //    amm fun.sc test
       
     7 //
       
     8 //  or
       
     9 //
     6 //    amm fun.sc main defs.fun
    10 //    amm fun.sc main defs.fun
     7 //
       
     8 //    amm fun.sc main fact.fun
    11 //    amm fun.sc main fact.fun
     9 //
    12 //
    10 // or
    13 //  or
    11 //    amm fun.sc test
    14 // 
    12 //
    15 //    amm fun.sc run defs.fun
    13 // the latter will print out the JVM instructions for two
    16 //    amm fun.sc run fact.fun   
       
    17 //
       
    18 // the first prints out the JVM instructions for two
    14 // factorial functions
    19 // factorial functions
       
    20 //
       
    21 // the next compile/run fun files
       
    22 //
    15 
    23 
    16 import $file.fun_tokens, fun_tokens._
    24 import $file.fun_tokens, fun_tokens._
    17 import $file.fun_parser, fun_parser._ 
    25 import $file.fun_parser, fun_parser._ 
    18 
    26 
    19 
    27 
    74 }
    82 }
    75 
    83 
    76 // variable / index environments
    84 // variable / index environments
    77 type Env = Map[String, Int]
    85 type Env = Map[String, Int]
    78 
    86 
       
    87 def compile_op(op: String) = op match {
       
    88   case "+" => i"iadd"
       
    89   case "-" => i"isub"
       
    90   case "*" => i"imul"
       
    91   case "/" => i"idiv"
       
    92   case "%" => i"irem"
       
    93 }
       
    94 
       
    95 
    79 // compile expressions
    96 // compile expressions
    80 def compile_exp(a: Exp, env : Env) : String = a match {
    97 def compile_exp(a: Exp, env: Env) : String = a match {
    81   case Num(i) => i"ldc $i"
    98   case Num(i) => i"ldc $i"
    82   case Var(s) => i"iload ${env(s)}"
    99   case Var(s) => i"iload ${env(s)}"
    83   case Aop("+", a1, a2) => compile_exp(a1, env) ++ compile_exp(a2, env) ++ i"iadd"
   100   case Aop(op, a1, a2) => 
    84   case Aop("-", a1, a2) => compile_exp(a1, env) ++ compile_exp(a2, env) ++ i"isub"
   101     compile_exp(a1, env) ++ compile_exp(a2, env) ++ compile_op(op)
    85   case Aop("*", a1, a2) => compile_exp(a1, env) ++ compile_exp(a2, env) ++ i"imul"
       
    86   case Aop("/", a1, a2) => compile_exp(a1, env) ++ compile_exp(a2, env) ++ i"idiv"
       
    87   case Aop("%", a1, a2) => compile_exp(a1, env) ++ compile_exp(a2, env) ++ i"irem"
       
    88   case If(b, a1, a2) => {
   102   case If(b, a1, a2) => {
    89     val if_else = Fresh("If_else")
   103     val if_else = Fresh("If_else")
    90     val if_end = Fresh("If_end")
   104     val if_end = Fresh("If_end")
    91     compile_bexp(b, env, if_else) ++
   105     compile_bexp(b, env, if_else) ++
    92     compile_exp(a1, env) ++
   106     compile_exp(a1, env) ++
   135     i"ireturn" ++
   149     i"ireturn" ++
   136     m".end method\n"
   150     m".end method\n"
   137   }
   151   }
   138   case Main(a) => {
   152   case Main(a) => {
   139     m".method public static main([Ljava/lang/String;)V" ++
   153     m".method public static main([Ljava/lang/String;)V" ++
   140     m".limit locals 200" ++
   154     m".limit locals 1" ++
   141     m".limit stack 200" ++
   155     m".limit stack ${1 + max_stack_exp(a)}" ++
   142     compile_exp(a, Map()) ++
   156     compile_exp(a, Map()) ++
   143     i"invokestatic XXX/XXX/write(I)V" ++
   157     i"invokestatic XXX/XXX/write(I)V" ++
   144     i"return" ++
   158     i"return" ++
   145     m".end method\n"
   159     m".end method\n"
   146   }
   160   }
   151   val instructions = prog.map(compile_decl).mkString
   165   val instructions = prog.map(compile_decl).mkString
   152   (library + instructions).replaceAllLiterally("XXX", class_name)
   166   (library + instructions).replaceAllLiterally("XXX", class_name)
   153 }
   167 }
   154 
   168 
   155 
   169 
       
   170 import ammonite.ops._
       
   171 
       
   172 def compile_to_file(prog: List[Decl], class_name: String) : Unit = 
       
   173   write.over(pwd / s"$class_name.j", compile(prog, class_name))  
       
   174 
       
   175 def compile_and_run(prog: List[Decl], class_name: String) : Unit = {
       
   176   println(s"Start of compilation")
       
   177   compile_to_file(prog, class_name)
       
   178   println(s"generated $class_name.j file")
       
   179   os.proc("java", "-jar", "jasmin.jar", s"$class_name.j").call()
       
   180   println(s"generated $class_name.class file")
       
   181   println(s"Run program")
       
   182   os.proc("java", s"${class_name}/${class_name}").call(stdout = os.Inherit)
       
   183   println(s"done.")
       
   184 }
   156 
   185 
   157 
   186 
   158 // An example program (two versions of factorial)
   187 // An example program (two versions of factorial)
   159 //
   188 //
   160 // def fact(n) = 
   189 // def fact(n) = 
   179             Var("acc"),
   208             Var("acc"),
   180             Call("facT",List(Aop("-",Var("n"),Num(1)), 
   209             Call("facT",List(Aop("-",Var("n"),Num(1)), 
   181                              Aop("*",Var("n"),Var("acc")))))),
   210                              Aop("*",Var("n"),Var("acc")))))),
   182 
   211 
   183        Main(Sequence(Write(Call("fact",List(Num(10)))),
   212        Main(Sequence(Write(Call("fact",List(Num(10)))),
   184                  Write(Call("facT",List(Num(10), Num(1)))))))
   213                      Write(Call("facT",List(Num(10), Num(1)))))))
   185 
   214 
   186 // prints out the JVM instructions
   215 // prints out the JVM instructions for the factorial example
   187 @main
   216 @main
   188 def test() = 
   217 def test() = 
   189   println(compile(test_prog, "fact"))
   218   println(compile(test_prog, "fact"))
   190 
   219 
   191 
   220 
   195     val class_name = fname.stripSuffix("." ++ path.ext)
   224     val class_name = fname.stripSuffix("." ++ path.ext)
   196     val tks = tokenise(os.read(path))
   225     val tks = tokenise(os.read(path))
   197     val ast = parse_tks(tks)
   226     val ast = parse_tks(tks)
   198     println(compile(ast, class_name))
   227     println(compile(ast, class_name))
   199 }
   228 }
       
   229 
       
   230 @main
       
   231 def run(fname: String) = {
       
   232     val path = os.pwd / fname
       
   233     val class_name = fname.stripSuffix("." ++ path.ext)
       
   234     val tks = tokenise(os.read(path))
       
   235     val ast = parse_tks(tks)
       
   236     compile_and_run(ast, class_name)
       
   237 }