package object comp2 {
// Recusive function to Abacus translation
import lib._
import abacus._
import recs._
def AbacusAdd(m: Int, n: Int, p: Int) =
Abacus(Dec(m, 4), Inc(n), Inc(p), Goto(0), Dec(p, 7), Inc(m), Goto(4))
def MVReg(m: Int, n: Int) = Abacus(Dec(m, 3), Inc(n), Goto(0))
//move the registers ranging from i to i + n to range j to j + n
def MVRegs(i: Int, j: Int, n: Int) : Abacus = n match {
case 0 => Abacus()
case n => MVRegs(i, j, n - 1) :+ MVReg(i + n - 1, j + n - 1)
}
// clears the first n registers
def ClearRegs(n: Int) : Abacus = n match {
case 0 => Abacus()
case n => ClearRegs(n - 1) :+ Abacus(Dec(n - 1, 2), Goto(0))
}
def cn_merge_gs(x: List[(Abacus, Int)], n: Int, p: Int) : Abacus = x match {
case Nil => Abacus(Nil)
case (gprog, gn)::gs => gprog :+ MVReg(n, p) :+ cn_merge_gs(gs, n, p + 1)
}
// translation:
// second component is the arity of the recursive function,
// third componen is the maximum of registers used
def compile_rec(f: Rec) : (Abacus, Int) = f match {
case Z => (Abacus(Goto(1)), 2)
case S => (AbacusAdd(0, 1, 2) :+ Abacus(Inc(1)), 3)
case Id(i, j) => (AbacusAdd(j, i, i + 1), i + 2)
case Cn(n, f, gs) => {
val cied_gs = gs.map(compile_rec)
val (fprog, fn) = compile_rec(f)
val qstr = (fn :: (cied_gs.map(_._2))).max
(cn_merge_gs(cied_gs, n, qstr) :+
MVRegs(0, qstr + gs.length, n) :+
MVRegs(qstr, 0, gs.length) :+
fprog :+
MVReg(f.arity, qstr + gs.length + 1) :+
ClearRegs(gs.length) :+
MVRegs(qstr + gs.length , 0, n + 1), qstr + gs.length + n + 1)
}
case Pr(n, f, g) => {
val (fprog, fn) = compile_rec(f)
val (gprog, gn) = compile_rec(g)
val qstr = List(fn, gn).max
val e = gprog.p.length + 7
(MVReg(0, qstr) :+
MVRegs(1, 0, n) :+
fprog :+
MVReg(n, n + 1) :+
MVRegs(0, 2, n) :+
((Abacus(Dec(qstr, e)) :+ gprog :+ Abacus(Inc(0), Dec(n + 1, 3), Goto(1))) ++
Abacus(Dec(n + 2, 0), Inc (1), Goto (gprog.p.length + 4))), qstr + 1)
}
case Mn(n, f) => {
val (fprog, fn) = compile_rec(f)
val len = fprog.p.length
(MVRegs(0, 1, n) :+
(fprog ++ Abacus(Dec(n + 1, len + 5), Dec(n + 1, len + 3), Goto(len + 1), Inc(0), Goto(0))),
fn)
}
}
}