# HG changeset patch # User Christian Urban # Date 1571007744 -3600 # Node ID 3d04ee04966d80a96b13e8ea3e87f22fd100be67 # Parent fb6192488b911c74934be1215eaf9d17076eba9f updated diff -r fb6192488b91 -r 3d04ee04966d progs/fact.fun --- a/progs/fact.fun Sun Oct 13 00:53:20 2019 +0100 +++ b/progs/fact.fun Mon Oct 14 00:02:24 2019 +0100 @@ -1,8 +1,17 @@ -def fact(n) = if n == 0 then 1 else n * fact(n - 1); +// a simple factorial program +// (including a tail recursive version) -def facT(n, acc) = if n == 0 then acc else facT(n - 1, n * acc); + +def fact(n) = + if n == 0 then 1 else n * fact(n - 1); -facT(15, 1) +def facT(n, acc) = + if n == 0 then acc else facT(n - 1, n * acc); + +def facTi(n) = facT(n, 1); -//fact(15) +//fact(10) +//facTi(10) +write(facTi(5 + 5)) + diff -r fb6192488b91 -r 3d04ee04966d progs/fun_llvm.scala --- a/progs/fun_llvm.scala Sun Oct 13 00:53:20 2019 +0100 +++ b/progs/fun_llvm.scala Mon Oct 14 00:02:24 2019 +0100 @@ -7,7 +7,25 @@ // // scala fun_llvm.scala defs // -// this will generate a .ll file +// this will generate a .ll file. You can interpret this file +// using lli. +// +// The optimiser can be invoked as +// +// opt -O1 -S in_file.ll > out_file.ll +// opt -O3 -S in_file.ll > out_file.ll +// +// The code produced for the various architectures can be obtains with +// +// llc -march=x86 -filetype=asm in_file.ll -o - +// llc -march=arm -filetype=asm in_file.ll -o - +// +// Producing an executable can be achieved by +// +// llc -filetype=obj in_file.ll +// gcc in_file.o -o a.out +// ./a.out + object Compiler { @@ -34,11 +52,6 @@ case class Bop(o: String, a1: Exp, a2: Exp) extends BExp -// compiler - built-in functions -// copied from http://www.ceng.metu.edu.tr/courses/ceng444/link/jvm-cpm.html -// - - // for generating new labels var counter = -1 @@ -56,6 +69,7 @@ case class KAop(o: String, v1: KVal, v2: KVal) extends KVal case class KBop(o: String, v1: KVal, v2: KVal) extends KVal case class KCall(o: String, vrs: List[KVal]) extends KVal +case class KWrite(v: KVal) extends KVal case class KIf(x1: String, e1: KExp, e2: KExp) extends KExp { override def toString = s"KIf $x1\nIF\n$e1\nELSE\n$e2" @@ -66,7 +80,7 @@ case class KReturn(v: KVal) extends KExp -// CPS translation from Exp's to KExp's using a +// CPS translation from Exps to KExps using a // continuation k. def CPS(e: Exp)(k: KVal => KExp) : KExp = e match { case Var(s) => k(KVar(s)) @@ -79,7 +93,8 @@ case If(Bop(o, b1, b2), e1, e2) => { val z = Fresh("tmp") CPS(b1)(y1 => - CPS(b2)(y2 => KLet(z, KBop(o, y1, y2), KIf(z, CPS(e1)(k), CPS(e2)(k))))) + CPS(b2)(y2 => + KLet(z, KBop(o, y1, y2), KIf(z, CPS(e1)(k), CPS(e2)(k))))) } case Call(name, args) => { def aux(args: List[Exp], vs: List[KVal]) : KExp = args match { @@ -96,6 +111,10 @@ CPS(e1)(y1 => CPS(e2)(y2 => KLet("_", y1, KLet(z, y2, k(KVar(z)))))) } + case Write(e) => { + val z = Fresh("tmp") + CPS(e)(y => KLet(z, KWrite(y), k(KVar(z)))) + } } def CPSi(e: Exp) = CPS(e)(KReturn) @@ -161,6 +180,8 @@ s"${compile_op(op)} ${compile_val(x1)}, ${compile_val(x2)}" case KCall(x1, args) => s"call i32 @$x1 (${args.map(compile_val).mkString("i32 ", ", i32 ", "")})" + case KWrite(x1) => + s"call i32 @printInt (i32 ${compile_val(x1)})" } // compile K expressions @@ -180,13 +201,19 @@ } } -/* case Write(a1) => { - compile_exp(a1, env) ++ - i"dup" ++ - i"invokestatic XXX/XXX/write(I)V" - } -*/ + +val prelude = """ +@.str = private constant [4 x i8] c"%d\0A\00" + +declare i32 @printf(i8*, ...) +define i32 @printInt(i32 %x) { + %t0 = getelementptr [4 x i8], [4 x i8]* @.str, i32 0, i32 0 + call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([4 x i8], [4 x i8]* @.str, i64 0, i64 0), i32 %x) + ret i32 %x +} + +""" // compile function for declarations and main @@ -219,23 +246,22 @@ } } -def compile(class_name: String) : String = { - val ast = deserialise[List[Decl]](class_name ++ ".prs").getOrElse(Nil) - ast.map(compile_decl).mkString +def compile(fname: String) : String = { + val ast = deserialise[List[Decl]](fname ++ ".prs").getOrElse(Nil) + prelude ++ (ast.map(compile_decl).mkString) } -/* -def compile_to_file(class_name: String) = { - val output = compile(class_name) - scala.tools.nsc.io.File(s"${class_name}.j").writeAll(output) +def compile_to_file(fname: String) = { + val output = compile(fname) + scala.tools.nsc.io.File(s"${fname}.ll").writeAll(output) } -def compile_and_run(class_name: String) : Unit = { - compile_to_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}").!)) +def compile_and_run(fname: String) : Unit = { + compile_to_file(fname) + (s"llc -filetype=obj ${fname}.ll").!! + (s"gcc ${fname}.o -o a.out").!! + println("Time: " + time_needed(2, (s"./a.out").!)) } -*/ // some examples of .fun files //compile_to_file("fact") @@ -244,7 +270,7 @@ def main(args: Array[String]) : Unit = - println(compile(args(0))) - + //println(compile(args(0))) + compile_and_run(args(0)) } \ No newline at end of file diff -r fb6192488b91 -r 3d04ee04966d progs/fun_parser.scala --- a/progs/fun_parser.scala Sun Oct 13 00:53:20 2019 +0100 +++ b/progs/fun_parser.scala Mon Oct 14 00:02:24 2019 +0100 @@ -34,13 +34,12 @@ abstract class Parser[I, T](implicit ev: I => Seq[_]) { def parse(ts: I): Set[(T, I)] - def parse_all(ts: I) : Set[T] = - for ((head, tail) <- parse(ts); if (tail.isEmpty)) yield head - - def parse_single(ts: I) : T = parse_all(ts).toList match { - case List(t) => t - case _ => { println ("Parse Error\n") ; sys.exit(-1) } - } + def parse_single(ts: I) : T = + parse(ts).partition(_._2.isEmpty) match { + case (good, _) if !good.isEmpty => good.head._1 + case (_, err) => { + println (s"Parse Error\n${err.minBy(_._2.length)}") ; sys.exit(-1) } + } } // convenience for writing grammar rules diff -r fb6192488b91 -r 3d04ee04966d progs/fun_tokens.scala --- a/progs/fun_tokens.scala Sun Oct 13 00:53:20 2019 +0100 +++ b/progs/fun_tokens.scala Mon Oct 14 00:02:24 2019 +0100 @@ -249,8 +249,11 @@ } -def tokenise(s: String) : List[Token] = - lexing_simp(FUN_REGS, s).collect(token) +def tokenise(s: String) : List[Token] = { + val tks = lexing_simp(FUN_REGS, s).collect(token) + if (tks.length != 0) tks + else { println (s"Tokenise Error") ; sys.exit(-1) } +} def serialise[T](fname: String, data: T) = { import scala.util.Using @@ -267,4 +270,4 @@ } -} \ No newline at end of file +}