updated
authorChristian Urban <urbanc@in.tum.de>
Mon, 14 Oct 2019 00:02:24 +0100
changeset 655 3d04ee04966d
parent 654 fb6192488b91
child 656 cfc0e730bcda
updated
progs/fact.fun
progs/fun_llvm.scala
progs/fun_parser.scala
progs/fun_tokens.scala
--- 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))
+
--- 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
--- 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
--- 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
+}