diff -r b048f99cd483 -r 553cd0c5e983 progs/fun/funt.sc --- 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") -*/