|
1 // Source language: arithmetic expressions with function calls |
|
2 enum Expr { |
|
3 case Num(n: Int) |
|
4 case Aop(op: String, e1: Expr, e2: Expr) |
|
5 case Call(fname: String, args: List[Expr]) |
|
6 } |
|
7 import Expr._ |
|
8 |
|
9 // Target language |
|
10 // "trivial" KValues |
|
11 enum KVal { |
|
12 case KVar(s: String) |
|
13 case KNum(n: Int) |
|
14 case KAop(op: String, v1: KVal, v2: KVal) |
|
15 case KCall(fname: String, args: List[KVal]) |
|
16 } |
|
17 import KVal._ |
|
18 |
|
19 // KExpressions |
|
20 enum KExp { |
|
21 case KReturn(v: KVal) |
|
22 case KLet(x: String, v: KVal, e: KExp) |
|
23 } |
|
24 import KExp._ |
|
25 |
|
26 var cnt = -1 |
|
27 def Fresh(s: String) = { |
|
28 cnt = cnt + 1 |
|
29 s"${s}_${cnt}" |
|
30 } |
|
31 |
|
32 def CPS(e: Expr)(k: KVal => KExp): KExp = e match { |
|
33 case Num(i) => k(KNum(i)) |
|
34 case Aop(op, l, r) => { |
|
35 val z = Fresh("z") |
|
36 CPS(l)(l => |
|
37 CPS(r)(r => KLet(z, KAop(op, l, r), k(KVar(z))))) |
|
38 } |
|
39 case Call(fname, args) => { |
|
40 def aux(args: List[Expr], vs: List[KVal]) : KExp = args match { |
|
41 case Nil => { |
|
42 val z = Fresh("tmp") |
|
43 KLet(z, KCall(fname, vs), k(KVar(z))) |
|
44 } |
|
45 case a::as => CPS(a)(r => aux(as, vs ::: List(r))) |
|
46 } |
|
47 aux(args, Nil) |
|
48 } |
|
49 } |
|
50 |
|
51 def CPSi(e: Expr) : KExp = CPS(e)(KReturn(_)) |
|
52 |
|
53 |
|
54 //1 + foo(bar(4 * -7), 3, id(12)) |
|
55 val etest = |
|
56 Aop("+", Num(1), |
|
57 Call("foo", |
|
58 List(Call("bar", |
|
59 List(Aop("*", Num(4), Num(-7)))), |
|
60 Num(3), |
|
61 Call("id", List(Num(12)))))) |
|
62 |
|
63 println(CPSi(etest)) |