progs/fun/fun.sc
changeset 813 059f970287d1
parent 789 f0696713177b
child 814 1fbaa5f05516
--- a/progs/fun/fun.sc	Fri Nov 27 13:53:06 2020 +0000
+++ b/progs/fun/fun.sc	Tue Dec 01 05:41:12 2020 +0000
@@ -1,17 +1,25 @@
 // A Small Compiler for a Simple Functional Language
-// (it does not include a parser and lexer)
+// (includes a parser and lexer)
 //
 // call with
 //
+//    amm fun.sc test
+//
+//  or
+//
 //    amm fun.sc main defs.fun
-//
 //    amm fun.sc main fact.fun
 //
-// or
-//    amm fun.sc test
+//  or
+// 
+//    amm fun.sc run defs.fun
+//    amm fun.sc run fact.fun   
 //
-// the latter will print out the JVM instructions for two
+// the first prints out the JVM instructions for two
 // factorial functions
+//
+// the next compile/run fun files
+//
 
 import $file.fun_tokens, fun_tokens._
 import $file.fun_parser, fun_parser._ 
@@ -76,15 +84,21 @@
 // variable / index environments
 type Env = Map[String, Int]
 
+def compile_op(op: String) = op match {
+  case "+" => i"iadd"
+  case "-" => i"isub"
+  case "*" => i"imul"
+  case "/" => i"idiv"
+  case "%" => i"irem"
+}
+
+
 // compile expressions
-def compile_exp(a: Exp, env : Env) : String = a match {
+def compile_exp(a: Exp, env: Env) : String = a match {
   case Num(i) => i"ldc $i"
   case Var(s) => i"iload ${env(s)}"
-  case Aop("+", a1, a2) => compile_exp(a1, env) ++ compile_exp(a2, env) ++ i"iadd"
-  case Aop("-", a1, a2) => compile_exp(a1, env) ++ compile_exp(a2, env) ++ i"isub"
-  case Aop("*", a1, a2) => compile_exp(a1, env) ++ compile_exp(a2, env) ++ i"imul"
-  case Aop("/", a1, a2) => compile_exp(a1, env) ++ compile_exp(a2, env) ++ i"idiv"
-  case Aop("%", a1, a2) => compile_exp(a1, env) ++ compile_exp(a2, env) ++ i"irem"
+  case Aop(op, a1, a2) => 
+    compile_exp(a1, env) ++ compile_exp(a2, env) ++ compile_op(op)
   case If(b, a1, a2) => {
     val if_else = Fresh("If_else")
     val if_end = Fresh("If_end")
@@ -137,8 +151,8 @@
   }
   case Main(a) => {
     m".method public static main([Ljava/lang/String;)V" ++
-    m".limit locals 200" ++
-    m".limit stack 200" ++
+    m".limit locals 1" ++
+    m".limit stack ${1 + max_stack_exp(a)}" ++
     compile_exp(a, Map()) ++
     i"invokestatic XXX/XXX/write(I)V" ++
     i"return" ++
@@ -153,6 +167,21 @@
 }
 
 
+import ammonite.ops._
+
+def compile_to_file(prog: List[Decl], class_name: String) : Unit = 
+  write.over(pwd / s"$class_name.j", compile(prog, class_name))  
+
+def compile_and_run(prog: List[Decl], class_name: String) : Unit = {
+  println(s"Start of compilation")
+  compile_to_file(prog, class_name)
+  println(s"generated $class_name.j file")
+  os.proc("java", "-jar", "jasmin.jar", s"$class_name.j").call()
+  println(s"generated $class_name.class file")
+  println(s"Run program")
+  os.proc("java", s"${class_name}/${class_name}").call(stdout = os.Inherit)
+  println(s"done.")
+}
 
 
 // An example program (two versions of factorial)
@@ -181,9 +210,9 @@
                              Aop("*",Var("n"),Var("acc")))))),
 
        Main(Sequence(Write(Call("fact",List(Num(10)))),
-                 Write(Call("facT",List(Num(10), Num(1)))))))
+                     Write(Call("facT",List(Num(10), Num(1)))))))
 
-// prints out the JVM instructions
+// prints out the JVM instructions for the factorial example
 @main
 def test() = 
   println(compile(test_prog, "fact"))
@@ -197,3 +226,12 @@
     val ast = parse_tks(tks)
     println(compile(ast, class_name))
 }
+
+@main
+def run(fname: String) = {
+    val path = os.pwd / fname
+    val class_name = fname.stripSuffix("." ++ path.ext)
+    val tks = tokenise(os.read(path))
+    val ast = parse_tks(tks)
+    compile_and_run(ast, class_name)
+}