scala/abacus.scala
author Christian Urban <christian dot urban at kcl dot ac dot uk>
Tue, 26 Feb 2013 17:39:47 +0000
changeset 200 8dde2e46c69d
parent 195 f06aa4e1c25b
child 208 3267acc1f97f
permissions -rw-r--r--
added all recursive functions needed for the UF

package object abacus {

import lib._

// Abacus instructions
sealed abstract class AInst 
case class Inc(n: Int) extends AInst
case class Dec(n: Int, l: Int) extends AInst
case class Goto(l: Int) extends AInst

type AProg = List[AInst]
type Regs = Map[Int, Int]

// Abacus configurations
case class AConfig(s: Int, regs: Regs)  

// Abacus machines
case class Abacus(p: AProg) {

  //simple composition
  def ++ (that: Abacus) = Abacus(p ::: that.p)

  def :+ (that: Abacus) = this ++ that.shift(p.length, -1)

  def shift(offset: Int, jump: Int) = Abacus(p.map(_ match {
    case Inc(n) => Inc(n)
    case Dec(n, l) => if (l == jump) Dec(n, l) else Dec(n, l + offset)
    case Goto(l) => if (l == jump) Goto(l) else Goto(l + offset)
  }))
      
  def adjust(old_jump: Int, jump: Int) = Abacus(p.map(_ match {
    case Inc(n) => Inc(n)
    case Dec(n, l) => if (l == old_jump) Dec(n, jump) else Dec(n, l)
    case Goto(l) => if (l == old_jump) Goto(jump) else Goto(l)
  }))

  def step(cf: AConfig) : AConfig = (nth_of(p, cf.s), cf.s) match {
    case (None, _) => cf
    case (Some(Inc(n)), s) => AConfig(s + 1, cf.regs + (n -> (dget(cf.regs, n) + 1)))
    case (Some(Dec(n, l)), s) => {
      if (dget(cf.regs, n) == 0) AConfig(l, cf.regs)
      else AConfig(s + 1, cf.regs + (n -> (dget(cf.regs, n) - 1)))
    }
    case (Some(Goto(l)), _) => AConfig(l, cf.regs)
  }  

  def steps(cf: AConfig, n: Int) : AConfig = n match {
    case 0 => cf
    case n => steps(step(cf), n - 1)
  } 

  def steps(regs: Regs, n: Int) : AConfig = steps(AConfig(0, regs), n)

  def run(cf: AConfig) : AConfig = {
    if (cf.s >= p.length || cf.s < 0) cf else run(step(cf))
  }
 
  def run(regs: Regs): Regs = run(AConfig(0, regs)).regs
}

// some syntactical convenience
object Abacus {
  def apply(is: AInst*) : Abacus = Abacus(is.toList)
}


}