--- a/progs/fun/funt.sc Fri Nov 27 13:53:06 2020 +0000
+++ b/progs/fun/funt.sc Tue Dec 01 05:41:12 2020 +0000
@@ -1,5 +1,20 @@
// A Small Compiler for a Simple Functional Language
-// (includes a lexer and a parser)
+// - includes a lexer and a parser
+// - performs tail-call optimisations
+//
+// call with
+//
+// amm fun.sc main defs.fun
+// amm fun.sc main fact.fun
+//
+// or
+//
+// amm fun.sc run defs.fun
+// amm fun.sc run fact.fun
+//
+// the first prints out the JVM instructions
+// the second runs the generated class files
+
import $file.fun_tokens, fun_tokens._
import $file.fun_parser, fun_parser._
@@ -26,7 +41,8 @@
// calculating the maximal needed stack size
def max_stack_exp(e: Exp): Int = e match {
case Call(_, args) => args.map(max_stack_exp).sum
- case If(a, e1, e2) => max_stack_bexp(a) + (List(max_stack_exp(e1), max_stack_exp(e2)).max)
+ case If(a, e1, e2) =>
+ max_stack_bexp(a) + (List(max_stack_exp(e1), max_stack_exp(e2)).max)
case Write(e) => max_stack_exp(e) + 1
case Var(_) => 1
case Num(_) => 1
@@ -61,15 +77,19 @@
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"
+}
def compile_expT(a: Exp, env : Env, name: String) : String = a match {
case Num(i) => i"ldc $i"
case Var(s) => i"iload ${env(s)}"
- case Aop("+", a1, a2) => compile_expT(a1, env, "") ++ compile_expT(a2, env, "") ++ i"iadd"
- case Aop("-", a1, a2) => compile_expT(a1, env, "") ++ compile_expT(a2, env, "") ++ i"isub"
- case Aop("*", a1, a2) => compile_expT(a1, env, "") ++ compile_expT(a2, env, "") ++ i"imul"
- case Aop("/", a1, a2) => compile_expT(a1, env, "") ++ compile_expT(a2, env, "") ++ i"idiv"
- case Aop("%", a1, a2) => compile_expT(a1, env, "") ++ compile_expT(a2, env, "") ++ i"irem"
+ case Aop(op, a1, a2) =>
+ compile_expT(a1, env, "") ++ compile_expT(a2, env, "") ++ compile_op(op)
case If(b, a1, a2) => {
val if_else = Fresh("If_else")
val if_end = Fresh("If_end")
@@ -141,6 +161,22 @@
(library + instructions).replaceAllLiterally("XXX", class_name)
}
+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.")
+}
+
@main
def main(fname: String) = {
@@ -151,18 +187,11 @@
println(compile(ast, class_name))
}
-/*
-
-import scala.sys.process._
-
-def compile_run(class_name: String) : Unit = {
- compile_file(class_name)
- (s"java -jar jvm/jasmin-2.4/jasmin.jar ${class_name}.j").!!
- println("Time: " + time_needed(2, (s"java ${class_name}/${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)
}
-
-
-//examples
-compile_run("defs")
-compile_run("fact")
-*/