| 864 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |      1 | // A Small LLVM Compiler for a Simple Functional Language
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |      2 | // (includes an external lexer and parser)
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |      3 | //
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |      4 | //
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |      5 | // call with                 -- prints out llvm code
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |      6 | //
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |      7 | //     amm fun_llvm.sc main fact.fun
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |      8 | //     amm fun_llvm.sc main defs.fun
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |      9 | //
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |     10 | // or                        -- writes llvm code to disk
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |     11 | //
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |     12 | //     amm fun_llvm.sc write fact.fun
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |     13 | //     amm fun_llvm.sc write defs.fun
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |     14 | //
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |     15 | //       this will generate an .ll file. 
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |     16 | //
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |     17 | // or                       -- runs the generated llvm code via lli
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |     18 | //
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |     19 | //     amm fun_llvm.sc run fact.fun
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |     20 | //     amm fun_llvm.sc run defs.fun
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |     21 | //
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |     22 | //
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |     23 | // You can interpret an .ll file using lli, for example
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |     24 | //
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |     25 | //      lli fact.ll
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |     26 | //
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |     27 | // The optimiser can be invoked as
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |     28 | //
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |     29 | //      opt -O1 -S in_file.ll > out_file.ll
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |     30 | //      opt -O3 -S in_file.ll > out_file.ll
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |     31 | //
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |     32 | // The code produced for the various architectures can be obtain with
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |     33 | //   
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |     34 | //   llc -march=x86 -filetype=asm in_file.ll -o -
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |     35 | //   llc -march=arm -filetype=asm in_file.ll -o -  
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |     36 | //
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |     37 | // Producing an executable can be achieved by
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |     38 | //
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |     39 | //    llc -filetype=obj in_file.ll
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |     40 | //    gcc in_file.o -o a.out
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |     41 | //    ./a.out
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |     42 | 
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |     43 | 
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |     44 | import $file.fun_tokens, fun_tokens._
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |     45 | import $file.fun_parser, fun_parser._ 
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |     46 | 
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |     47 | 
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |     48 | // for generating new labels
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |     49 | var counter = -1
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |     50 | 
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |     51 | def Fresh(x: String) = {
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |     52 |   counter += 1
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |     53 |   x ++ "_" ++ counter.toString()
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |     54 | }
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |     55 | 
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |     56 | // Internal CPS language for FUN
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |     57 | abstract class KExp
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |     58 | abstract class KVal
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |     59 | 
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |     60 | type Ty = String
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |     61 | type TyEnv = Map[String, Ty]
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |     62 | 
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |     63 | case class KVar(s: String, ty: Ty = "UNDEF") extends KVal
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |     64 | case class KLoad(v: KVal) extends KVal
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |     65 | case class KNum(i: Int) extends KVal
 | 
| 868 |     66 | case class KFNum(i: Double) extends KVal
 | 
| 864 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |     67 | case class KChr(c: Int) extends KVal
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |     68 | case class Kop(o: String, v1: KVal, v2: KVal, ty: Ty = "UNDEF") extends KVal
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |     69 | case class KCall(o: String, vrs: List[KVal], ty: Ty = "UNDEF") extends KVal
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |     70 | 
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |     71 | case class KIf(x1: String, e1: KExp, e2: KExp) extends KExp {
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |     72 |   override def toString = s"KIf $x1\nIF\n$e1\nELSE\n$e2"
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |     73 | }
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |     74 | case class KLet(x: String, e1: KVal, e2: KExp) extends KExp {
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |     75 |   override def toString = s"let $x = $e1 in \n$e2" 
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |     76 | }
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |     77 | case class KReturn(v: KVal) extends KExp
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |     78 | 
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |     79 | // typing K values
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |     80 | def typ_val(v: KVal, ts: TyEnv) : (KVal, Ty) = v match {
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |     81 |   case KVar(s, _) => {
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |     82 |     val ty = ts.getOrElse(s, "TUNDEF")
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |     83 |     (KVar(s, ty), ty)  
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |     84 |   }
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |     85 |   case Kop(op, v1, v2, _) => {
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |     86 |     val (tv1, ty1) = typ_val(v1, ts)
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |     87 |     val (tv2, ty2) = typ_val(v2, ts)
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |     88 |     if (ty1 == ty2) (Kop(op, tv1, tv2, ty1), ty1) else (Kop(op, tv1, tv2, "TMISMATCH"), "TMISMATCH") 
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |     89 |   }
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |     90 |   case KCall(fname, args, _) => {
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |     91 |     val ty = ts.getOrElse(fname, "TCALLUNDEF" ++ fname)
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |     92 |     (KCall(fname, args.map(typ_val(_, ts)._1), ty), ty)
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |     93 |   }  
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |     94 |   case KLoad(v) => {
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |     95 |     val (tv, ty) = typ_val(v, ts)
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |     96 |     (KLoad(tv), ty)
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |     97 |   }
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |     98 |   case KNum(i) => (KNum(i), "Int")
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |     99 |   case KFNum(i) => (KFNum(i), "Double")
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    100 |   case KChr(c) => (KChr(c), "Int")
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    101 | }
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    102 | 
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    103 | def typ_exp(a: KExp, ts: TyEnv) : KExp = a match {
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    104 |   case KReturn(v) => KReturn(typ_val(v, ts)._1)
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    105 |   case KLet(x: String, v: KVal, e: KExp) => {
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    106 |     val (tv, ty) = typ_val(v, ts)
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    107 |     KLet(x, tv, typ_exp(e, ts + (x -> ty)))
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    108 |   }
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    109 |   case KIf(b, e1, e2) => KIf(b, typ_exp(e1, ts), typ_exp(e2, ts))
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    110 | }
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    111 | 
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    112 | 
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    113 | 
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    114 | 
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    115 | // CPS translation from Exps to KExps using a
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    116 | // continuation k.
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    117 | def CPS(e: Exp)(k: KVal => KExp) : KExp = e match {
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    118 |   case Var(s) if (s.head.isUpper) => {
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    119 |       val z = Fresh("tmp")
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    120 |       KLet(z, KLoad(KVar(s)), k(KVar(z)))
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    121 |   }
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    122 |   case Var(s) => k(KVar(s))
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    123 |   case Num(i) => k(KNum(i))
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    124 |   case ChConst(c) => k(KChr(c))
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    125 |   case FNum(i) => k(KFNum(i))
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    126 |   case Aop(o, e1, e2) => {
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    127 |     val z = Fresh("tmp")
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    128 |     CPS(e1)(y1 => 
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    129 |       CPS(e2)(y2 => KLet(z, Kop(o, y1, y2), k(KVar(z)))))
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    130 |   }
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    131 |   case If(Bop(o, b1, b2), e1, e2) => {
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    132 |     val z = Fresh("tmp")
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    133 |     CPS(b1)(y1 => 
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    134 |       CPS(b2)(y2 => 
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    135 |         KLet(z, Kop(o, y1, y2), KIf(z, CPS(e1)(k), CPS(e2)(k)))))
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    136 |   }
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    137 |   case Call(name, args) => {
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    138 |     def aux(args: List[Exp], vs: List[KVal]) : KExp = args match {
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    139 |       case Nil => {
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    140 |           val z = Fresh("tmp")
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    141 |           KLet(z, KCall(name, vs), k(KVar(z)))
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    142 |       }
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    143 |       case e::es => CPS(e)(y => aux(es, vs ::: List(y)))
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    144 |     }
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    145 |     aux(args, Nil)
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    146 |   }
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    147 |   case Sequence(e1, e2) => 
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    148 |     CPS(e1)(_ => CPS(e2)(y2 => k(y2)))
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    149 | }   
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    150 | 
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    151 | //initial continuation
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    152 | def CPSi(e: Exp) = CPS(e)(KReturn)
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    153 | 
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    154 | // some testcases
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    155 | val e1 = Aop("*", Var("a"), Num(3))
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    156 | CPSi(e1)
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    157 | 
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    158 | val e2 = Aop("+", Aop("*", Var("a"), Num(3)), Num(4))
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    159 | CPSi(e2)
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    160 | 
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    161 | val e3 = Aop("+", Num(2), Aop("*", Var("a"), Num(3)))
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    162 | CPSi(e3)
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    163 | 
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    164 | val e4 = Aop("+", Aop("-", Num(1), Num(2)), Aop("*", Var("a"), Num(3)))
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    165 | CPSi(e4)
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    166 | 
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    167 | val e5 = If(Bop("==", Num(1), Num(1)), Num(3), Num(4))
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    168 | CPSi(e5)
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    169 | 
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    170 | val e6 = If(Bop("!=", Num(10), Num(10)), e5, Num(40))
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    171 | CPSi(e6)
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    172 | 
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    173 | val e7 = Call("foo", List(Num(3)))
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    174 | CPSi(e7)
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    175 | 
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    176 | val e8 = Call("foo", List(Aop("*", Num(3), Num(1)), Num(4), Aop("+", Num(5), Num(6))))
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    177 | CPSi(e8)
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    178 | 
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    179 | val e9 = Sequence(Aop("*", Var("a"), Num(3)), Aop("+", Var("b"), Num(6)))
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    180 | CPSi(e9)
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    181 | 
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    182 | val e = Aop("*", Aop("+", Num(1), Call("foo", List(Var("a"), Num(3)))), Num(4))
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    183 | CPSi(e)
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    184 | 
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    185 | 
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    186 | 
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    187 | 
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    188 | // convenient string interpolations 
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    189 | // for instructions, labels and methods
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    190 | import scala.language.implicitConversions
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    191 | import scala.language.reflectiveCalls
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    192 | 
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    193 | 
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    194 | 
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    195 | 
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    196 | implicit def sring_inters(sc: StringContext) = new {
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    197 |     def i(args: Any*): String = "   " ++ sc.s(args:_*) ++ "\n"
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    198 |     def l(args: Any*): String = sc.s(args:_*) ++ ":\n"
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    199 |     def m(args: Any*): String = sc.s(args:_*) ++ "\n"
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    200 | }
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    201 | 
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    202 | def get_ty(s: String) = s match {
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    203 |   case "Double" => "double"
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    204 |   case "Void" => "void"
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    205 |   case "Int" => "i32"
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    206 |   case "Bool" => "i2"
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    207 |   case _ => s
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    208 | }
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    209 | 
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    210 | def compile_call_arg(a: KVal) = a match {
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    211 |   case KNum(i) => s"i32 $i"
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    212 |   case KFNum(i) => s"double $i"
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    213 |   case KChr(c) => s"i32 $c"
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    214 |   case KVar(s, ty) => s"${get_ty(ty)} %$s" 
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    215 | }
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    216 | 
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    217 | def compile_arg(s: (String, String)) = s"${get_ty(s._2)} %${s._1}" 
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    218 | 
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    219 | 
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    220 | // mathematical and boolean operations
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    221 | def compile_op(op: String) = op match {
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    222 |   case "+" => "add i32 "
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    223 |   case "*" => "mul i32 "
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    224 |   case "-" => "sub i32 "
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    225 |   case "/" => "sdiv i32 "
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    226 |   case "%" => "srem i32 "
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    227 |   case "==" => "icmp eq i32 "
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    228 |   case "!=" => "icmp ne i32 "      // not equal 
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    229 |   case "<=" => "icmp sle i32 "     // signed less or equal
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    230 |   case "<"  => "icmp slt i32 "     // signed less than
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    231 | }
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    232 | 
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    233 | def compile_dop(op: String) = op match {
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    234 |   case "+" => "fadd double "
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    235 |   case "*" => "fmul double "
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    236 |   case "-" => "fsub double "
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    237 |   case "==" => "fcmp oeq double "
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    238 |   case "<=" => "fcmp ole double "   
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    239 |   case "<"  => "fcmp olt double "   
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    240 | }
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    241 | 
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    242 | // compile K values
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    243 | def compile_val(v: KVal) : String = v match {
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    244 |   case KNum(i) => s"$i"
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    245 |   case KFNum(i) => s"$i"
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    246 |   case KChr(c) => s"$c"
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    247 |   case KVar(s, ty) => s"%$s" 
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    248 |   case KLoad(KVar(s, ty)) => s"load ${get_ty(ty)}, ${get_ty(ty)}* @$s"
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    249 |   case Kop(op, x1, x2, ty) => ty match { 
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    250 |     case "Int" => s"${compile_op(op)} ${compile_val(x1)}, ${compile_val(x2)}"
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    251 |     case "Double" => s"${compile_dop(op)} ${compile_val(x1)}, ${compile_val(x2)}"
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    252 |     case _ => Kop(op, x1, x2, ty).toString
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    253 |   }
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    254 |   case KCall(fname, args, ty) => 
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    255 |     s"call ${get_ty(ty)} @$fname (${args.map(compile_call_arg).mkString(", ")})"
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    256 | }
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    257 | 
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    258 | // compile K expressions
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    259 | def compile_exp(a: KExp) : String = a match {
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    260 |   case KReturn(KVar("void", _)) =>
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    261 |     i"ret void"
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    262 |   case KReturn(KVar(x, ty)) =>
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    263 |     i"ret ${get_ty(ty)} %$x"
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    264 |   case KReturn(KNum(i)) =>
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    265 |     i"ret i32 $i"
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    266 |   case KLet(x: String, KCall(o: String, vrs: List[KVal], "Void"), e: KExp) => 
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    267 |     i"${compile_val(KCall(o: String, vrs: List[KVal], "Void"))}" ++ compile_exp(e)
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    268 |   case KLet(x: String, v: KVal, e: KExp) => 
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    269 |     i"%$x = ${compile_val(v)}" ++ compile_exp(e)
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    270 |   case KIf(x, e1, e2) => {
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    271 |     val if_br = Fresh("if_branch")
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    272 |     val else_br = Fresh("else_branch")
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    273 |     i"br i1 %$x, label %$if_br, label %$else_br" ++
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    274 |     l"\n$if_br" ++
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    275 |     compile_exp(e1) ++
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    276 |     l"\n$else_br" ++ 
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    277 |     compile_exp(e2)
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    278 |   }
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    279 | }
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    280 | 
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    281 | 
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    282 | val prelude = """
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    283 | declare i32 @printf(i8*, ...)
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    284 | 
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    285 | @.str_nl = private constant [2 x i8] c"\0A\00"
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    286 | @.str_star = private constant [2 x i8] c"*\00"
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    287 | @.str_space = private constant [2 x i8] c" \00"
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    288 | 
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    289 | define void @new_line() #0 {
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    290 |   %t0 = getelementptr [2 x i8], [2 x i8]* @.str_nl, i32 0, i32 0
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    291 |   %1 = call i32 (i8*, ...) @printf(i8* %t0)
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    292 |   ret void
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    293 | }
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    294 | 
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    295 | define void @print_star() #0 {
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    296 |   %t0 = getelementptr [2 x i8], [2 x i8]* @.str_star, i32 0, i32 0
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    297 |   %1 = call i32 (i8*, ...) @printf(i8* %t0)
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    298 |   ret void
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    299 | }
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    300 | 
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    301 | define void @print_space() #0 {
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    302 |   %t0 = getelementptr [2 x i8], [2 x i8]* @.str_space, i32 0, i32 0
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    303 |   %1 = call i32 (i8*, ...) @printf(i8* %t0)
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    304 |   ret void
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    305 | }
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    306 | 
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    307 | define void @skip() #0 {
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    308 |   ret void
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    309 | }
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    310 | 
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    311 | @.str_int = private constant [3 x i8] c"%d\00"
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    312 | 
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    313 | define void @print_int(i32 %x) {
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    314 |    %t0 = getelementptr [3 x i8], [3 x i8]* @.str_int, i32 0, i32 0
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    315 |    call i32 (i8*, ...) @printf(i8* %t0, i32 %x) 
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    316 |    ret void
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    317 | }
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    318 | 
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    319 | @.str_char = private constant [3 x i8] c"%c\00"
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    320 | 
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    321 | define void @print_char(i32 %x) {
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    322 |    %t0 = getelementptr [3 x i8], [3 x i8]* @.str_char, i32 0, i32 0
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    323 |    call i32 (i8*, ...) @printf(i8* %t0, i32 %x) 
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    324 |    ret void
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    325 | }
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    326 | 
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    327 | ; END OF BUILD-IN FUNCTIONS (prelude)
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    328 | 
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    329 | """
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    330 | 
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    331 | def get_cont(ty: Ty) = ty match {
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    332 |   case "Int" =>    KReturn
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    333 |   case "Double" => KReturn
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    334 |   case "Void" =>   { (_: KVal) => KReturn(KVar("void", "Void")) }
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    335 | } 
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    336 | 
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    337 | // compile function for declarations and main
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    338 | def compile_decl(d: Decl, ts: TyEnv) : (String, TyEnv) = d match {
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    339 |   case Def(name, args, ty, body) => { 
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    340 |     val ts2 = ts + (name -> ty)
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    341 |     val tkbody = typ_exp(CPS(body)(get_cont(ty)), ts2 ++ args.toMap)
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    342 |     (m"define ${get_ty(ty)} @$name (${args.map(compile_arg).mkString(",")}) {" ++
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    343 |      compile_exp(tkbody) ++
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    344 |      m"}\n", ts2)
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    345 |   }
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    346 |   case Main(body) => {
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    347 |     val tbody = typ_exp(CPS(body)(_ => KReturn(KNum(0))), ts)
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    348 |     (m"define i32 @main() {" ++
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    349 |      compile_exp(tbody) ++
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    350 |      m"}\n", ts)
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    351 |   }
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    352 |   case Const(name, n) => {
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    353 |     (m"@$name = global i32 $n\n", ts + (name -> "Int"))
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    354 |   }
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    355 |   case FConst(name, x) => {
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    356 |     (m"@$name = global double $x\n", ts + (name -> "Double"))
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    357 |   }
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    358 | }
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    359 | 
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    360 | def compile_prog(prog: List[Decl], ty: TyEnv) : String = prog match {
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    361 |   case Nil => ""
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    362 |   case d::ds => {
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    363 |     val (s2, ty2) = compile_decl(d, ty)
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    364 |     s2 ++ compile_prog(ds, ty2)
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    365 |   }
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    366 | }
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    367 | // main compiler functions
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    368 | def compile(prog: List[Decl]) : String = 
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    369 |   prelude ++ compile_prog(prog, Map("new_line" -> "Void", "skip" -> "Void", 
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    370 | 				    "print_star" -> "Void", "print_space" -> "Void",
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    371 |                                     "print_int" -> "Void", "print_char" -> "Void"))
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    372 | 
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    373 | 
 | 
| 867 |    374 | //import ammonite.ops._
 | 
| 864 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    375 | 
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    376 | 
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    377 | @main
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    378 | def main(fname: String) = {
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    379 |     val path = os.pwd / fname
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    380 |     val file = fname.stripSuffix("." ++ path.ext)
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    381 |     val tks = tokenise(os.read(path))
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    382 |     val ast = parse_tks(tks)
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    383 |     val code = compile(ast)
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    384 |     println(code)
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    385 | }
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    386 | 
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    387 | @main
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    388 | def write(fname: String) = {
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    389 |     val path = os.pwd / fname
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    390 |     val file = fname.stripSuffix("." ++ path.ext)
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    391 |     val tks = tokenise(os.read(path))
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    392 |     val ast = parse_tks(tks)
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    393 |     val code = compile(ast)
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    394 |     //println(code)
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    395 |     os.write.over(os.pwd / (file ++ ".ll"), code)
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    396 | }
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    397 | 
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    398 | @main
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    399 | def run(fname: String) = {
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    400 |     val path = os.pwd / fname
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    401 |     val file = fname.stripSuffix("." ++ path.ext)
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    402 |     write(fname)  
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    403 |     os.proc("llc", "-filetype=obj", file ++ ".ll").call()
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    404 |     os.proc("gcc", file ++ ".o", "-o", file ++ ".bin").call()
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    405 |     os.proc(os.pwd / (file ++ ".bin")).call(stdout = os.Inherit)
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    406 |     println(s"done.")
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    407 | }
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    408 | 
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    409 | 
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    410 | 
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    411 | 
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    412 | 
 |