| author | Christian Urban <christian dot urban at kcl dot ac dot uk> | 
| Fri, 24 Jul 2020 12:58:19 +0100 | |
| changeset 738 | 03f46065ef04 | 
| parent 737 | 826c2bec403b | 
| child 742 | 155426396b5f | 
| permissions | -rw-r--r-- | 
| 737 
826c2bec403b
updated
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: 
736diff
changeset | 1 | // A simple Interpreter for BF*** Programs | 
| 
826c2bec403b
updated
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: 
736diff
changeset | 2 | //========================================= | 
| 
826c2bec403b
updated
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: 
736diff
changeset | 3 | // | 
| 738 
03f46065ef04
updated
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: 
737diff
changeset | 4 | // Call with | 
| 737 
826c2bec403b
updated
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: 
736diff
changeset | 5 | // | 
| 
826c2bec403b
updated
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: 
736diff
changeset | 6 | // amm bfi.sc <<bf_program.bf>> | 
| 738 
03f46065ef04
updated
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: 
737diff
changeset | 7 | // | 
| 632 | 8 | |
| 737 
826c2bec403b
updated
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: 
736diff
changeset | 9 | |
| 632 | 10 | import scala.util._ | 
| 11 | ||
| 636 | 12 | // BF memory as a map | 
| 632 | 13 | type Mem = Map[Int, Int] | 
| 14 | ||
| 15 | // reading and writing BF memory | |
| 16 | def sread(mem: Mem, mp: Int) : Int = | |
| 17 | mem.getOrElse(mp, 0) | |
| 18 | ||
| 19 | def write(mem: Mem, mp: Int, v: Int) : Mem = | |
| 20 | mem.updated(mp, v) | |
| 21 | ||
| 22 | // Right and Left Jumps in BF loops | |
| 23 | def jumpRight(prog: String, pc: Int, level: Int) : Int = {
 | |
| 24 | if (prog.length <= pc) pc | |
| 25 |   else (prog(pc), level) match {
 | |
| 26 |     case (']', 0) => pc + 1
 | |
| 27 |     case (']', l) => jumpRight(prog, pc + 1, l - 1)
 | |
| 28 |     case ('[', l) => jumpRight(prog, pc + 1, l + 1)
 | |
| 29 | case (_, l) => jumpRight(prog, pc + 1, l) | |
| 30 | } | |
| 31 | } | |
| 32 | ||
| 33 | def jumpLeft(prog: String, pc: Int, level: Int) : Int = {
 | |
| 34 | if (pc < 0) pc | |
| 35 |   else (prog(pc), level) match {
 | |
| 36 |     case ('[', 0) => pc + 1
 | |
| 37 |     case ('[', l) => jumpLeft(prog, pc - 1, l - 1)
 | |
| 38 |     case (']', l) => jumpLeft(prog, pc - 1, l + 1)
 | |
| 39 | case (_, l) => jumpLeft(prog, pc - 1, l) | |
| 40 | } | |
| 41 | } | |
| 42 | ||
| 636 | 43 | // main interpreter loop | 
| 632 | 44 | def compute(prog: String, pc: Int, mp: Int, mem: Mem) : Mem = {
 | 
| 45 |   if (0 <= pc && pc < prog.length) { 
 | |
| 46 |     val (new_pc, new_mp, new_mem) = prog(pc) match {
 | |
| 47 | case '>' => (pc + 1, mp + 1, mem) | |
| 48 | case '<' => (pc + 1, mp - 1, mem) | |
| 49 | case '+' => (pc + 1, mp, write(mem, mp, sread(mem, mp) + 1)) | |
| 50 | case '-' => (pc + 1, mp, write(mem, mp, sread(mem, mp) - 1)) | |
| 51 |       case '.' => { print(sread(mem, mp).toChar); (pc + 1, mp, mem) }
 | |
| 52 | case ',' => (pc + 1, mp, write(mem, mp, Console.in.read().toByte)) | |
| 53 | case '[' => if (sread(mem, mp) == 0) | |
| 54 | (jumpRight(prog, pc + 1, 0), mp, mem) | |
| 55 | else (pc + 1, mp, mem) | |
| 56 | case ']' => if (sread(mem, mp) != 0) | |
| 57 | (jumpLeft(prog, pc - 1, 0), mp, mem) | |
| 58 | else (pc + 1, mp, mem) | |
| 59 | case _ => (pc + 1, mp, mem) | |
| 60 | } | |
| 61 | compute(prog, new_pc, new_mp, new_mem) | |
| 62 | } | |
| 63 | else mem | |
| 64 | } | |
| 65 | ||
| 66 | def run(prog: String, m: Mem = Map()) = compute(prog, 0, 0, m) | |
| 67 | ||
| 636 | 68 | // helper code for timing information | 
| 632 | 69 | def time_needed[T](n: Int, code: => T) = {
 | 
| 70 | val start = System.nanoTime() | |
| 71 | for (i <- 0 until n) code | |
| 72 | val end = System.nanoTime() | |
| 73 | (end - start)/(n * 1.0e9) | |
| 74 | } | |
| 75 | ||
| 738 
03f46065ef04
updated
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: 
737diff
changeset | 76 | // Running Testcases | 
| 
03f46065ef04
updated
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: 
737diff
changeset | 77 | //=================== | 
| 632 | 78 | |
| 737 
826c2bec403b
updated
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: 
736diff
changeset | 79 | @doc(" the argument should be a BF program ")
 | 
| 
826c2bec403b
updated
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: 
736diff
changeset | 80 | @main | 
| 
826c2bec403b
updated
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: 
736diff
changeset | 81 | def main(fname: String) = {
 | 
| 
826c2bec403b
updated
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: 
736diff
changeset | 82 | val bf_str = os.read(os.pwd / fname) | 
| 
826c2bec403b
updated
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: 
736diff
changeset | 83 |   println(s"${time_needed(1, run(bf_str))} secs")
 | 
| 
826c2bec403b
updated
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: 
736diff
changeset | 84 | } | 
| 632 | 85 |