main_testing5/bf.scala
author Christian Urban <christian.urban@kcl.ac.uk>
Sat, 11 Mar 2023 23:22:05 +0000
changeset 468 0587ef444547
parent 463 0315d9983cd0
child 475 59e005dcf163
permissions -rw-r--r--
updated and cleaned

// Main Part 5 about an Interpreter for 
// the Brainf*** language
//==============================================


object M5a {

// representation of BF memory 

type Mem = Map[Int, Int]

import io.Source
import scala.util._

// ADD YOUR CODE BELOW
//======================

// (1)
def load_bff(name: String) : String = {
    Try(Source.fromFile(name)("ISO-8859-1").mkString).getOrElse("")
}

// (2) 

def sread(mem: Mem, mp: Int) : Int = {
    Try(mem.apply(mp)).getOrElse(0)
}

def write(mem: Mem, mp: Int, v: Int) : Mem = {
    mem + (mp -> v)
}

// sread(Map(), 2) == 0
// sread(Map(2 -> 1), 2) == 1
// write(Map(), 1, 2) == Map(1 -> 2)
// write(Map(1 -> 0), 1, 2) == Map(1 -> 2)

// val current = sread(Map(2 -> 1), 2)
// write(Map(2 -> 1), 2, current+1)

// (3) 

def jumpRight(prog: String, pc: Int, level: Int) : Int = prog.toList.apply(pc) match{
    case '[' => jumpRight(prog, pc+1, level+1)
    case ']' => level match {
        case 0 => pc+1
        case _ => if (pc+1 >= prog.length) prog.length else jumpRight(prog, pc+1, level-1)
    }
    case _ => if (pc+1 >= prog.length) prog.length else jumpRight(prog, pc+1, level)
}

def jumpLeft(prog: String, pc: Int, level: Int) : Int = prog.toList.apply(pc) match{
    case ']' => jumpLeft(prog, pc-1, level+1)
    case '[' => level match {
        case 0 => pc+1
        case _ => if (pc-1 < 0) -1 else jumpLeft(prog, pc-1, level-1)
    }
    case _ => if (pc-1 < 0) -1 else jumpLeft(prog, pc-1, level)
}


// testcases
// jumpRight("""--[..+>--],>,++""", 3, 0)         // => 10
// jumpLeft("""--[..+>--],>,++""", 8, 0)          // => 3
// jumpRight("""--[..[+>]--],>,++""", 3, 0)       // => 12
// jumpRight("""--[..[[-]+>[.]]--],>,++""", 3, 0) // => 18
// jumpRight("""--[..[[-]+>[.]]--,>,++""", 3, 0)  // => 22 (outside)
// jumpLeft("""[******]***""", 7, 0)              // => -1 (outside)



// (4)
def compute(prog: String, pc: Int, mp: Int, mem: Mem) : Mem = (pc >= 0 && pc < prog.length) match {
    case false => mem
    case true => prog.toList.apply(pc) match{
        case '>' => compute(prog, pc+1, mp+1, mem)
        case '<' => compute(prog, pc+1, mp-1, mem)
        case '+' => {
            val current = sread(mem, mp)
            compute(prog, pc+1, mp, write(mem, mp, current+1))
        }
        case '-' => {
            val current = sread(mem, mp)
            compute(prog, pc+1, mp, write(mem, mp, current-1))
        }
        case '.' => {
            print(mem.apply(mp).toChar)
            compute(prog, pc+1, mp, mem)
        }
        case '[' => {
            if (mem.apply(mp) == 0) compute(prog, jumpRight(prog, pc+1, 0), mp, mem)
            else compute(prog, pc+1, mp, mem)
        }
        case ']' => {
           if (mem.apply(mp) != 0) compute(prog, jumpLeft(prog, pc-1, 0), mp, mem)
           else compute(prog, pc+1, mp, mem) 
        }
        case _ => compute(prog, pc, mp, mem)
    }
}

def run(prog: String, m: Mem = Map()) = {
    compute(prog, 0, 0, m)
}

// run("[-]", Map(0 -> 100)) == Map(0 -> 0)
// run("[->+<]", Map(0 -> 10)) == Map(0 -> 0, 1 -> 10)
// run("[>>+>>+<<<<-]", Map(0 -> 42)) == Map(0 -> 0, 2 -> 42, 4 -> 42)
// run("""+++++[->++++++++++<]>--<+++[->>++++++++++<<]>>++<<----------[+>.>.<+<]""") == Map(0 -> 0, 1 -> 58, 2 -> 32)

// (5)
def generate(msg: List[Char]) : String = msg match {
    case Nil => ""
    case c => "+"*c.head.toInt + ".[-]" + generate(msg.tail)
}

// generate("ABC".toList)

// run("+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++.[-]++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++.[-]+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++.[-]", Map())

// some sample bf-programs collected from the Internet
//=====================================================


// some contrived (small) programs
//---------------------------------

// // clears the 0-cell
// run("[-]", Map(0 -> 100))    // Map will be 0 -> 0

// // moves content of the 0-cell to 1-cell
// run("[->+<]", Map(0 -> 10))  // Map will be 0 -> 0, 1 -> 10


// // copies content of the 0-cell to 2-cell and 4-cell
// run("[>>+>>+<<<<-]", Map(0 -> 42))    // Map(0 -> 0, 2 -> 42, 4 -> 42)


// // prints out numbers 0 to 9
// run("""+++++[->++++++++++<]>--<+++[->>++++++++++<<]>>++<<----------[+>.>.<+<]""")


// // some more "useful" programs
// //-----------------------------

// // hello world program 1
// run("""++++++++[>++++[>++>+++>+++>+<<<<-]>+>+>->>+[<]<-]>>.>---.+++++++..+++.>>.<-.<.+++.------.--------.>>+.>++.""")

// // hello world program 2
// run("""++++++++++[>+++++++>++++++++++>+++>+<<<<-]>++.>+.+++++++..+++.>++.<<+++++++++++++++.>.+++.------.--------.>+.>.""")

// // hello world program 3
// run("""+++++++++[>++++++++>+++++++++++>+++++<<<-]>.>++.+++++++..+++.>-.------------.<++++++++.--------.+++.------.--------.>+.""")

 
// // draws the Sierpinski triangle
// run(load_bff("sierpinski.bf"))


// //fibonacci numbers below 100
// run("""+++++++++++
//      >+>>>>++++++++++++++++++++++++++++++++++++++++++++
//      >++++++++++++++++++++++++++++++++<<<<<<[>[>>>>>>+>
//      +<<<<<<<-]>>>>>>>[<<<<<<<+>>>>>>>-]<[>++++++++++[-
//      <-[>>+>+<<<-]>>>[<<<+>>>-]+<[>[-]<[-]]>[<<[>>>+<<<
//      -]>>[-]]<<]>>>[>>+>+<<<-]>>>[<<<+>>>-]+<[>[-]<[-]]
//      >[<<+>>[-]]<<<<<<<]>>>>>[+++++++++++++++++++++++++
//      +++++++++++++++++++++++.[-]]++++++++++<[->-<]>++++
//      ++++++++++++++++++++++++++++++++++++++++++++.[-]<<
//      <<<<<<<<<<[>>>+>+<<<<-]>>>>[<<<<+>>>>-]<-[>>.>.<<<
//      [-]]<<[>>+>+<<<-]>>>[<<<+>>>-]<<[<+>-]>[<+>-]<<<-]""")

// //outputs the square numbers up to 10000
// run("""++++[>+++++<-]>[<+++++>-]+<+[>[>+>+<<-]++>>[<<+>>-]>>>[-]++>[-]+
//       >>>+[[-]++++++>>>]<<<[[<++++++++<++>>-]+<.<[>----<-]<]
//       <<[>>>>>[>>>[-]+++++++++<[>-<-]+++++++++>[-[<->-]+[<<<]]<[>+<-]>]<<-]<<-]""")


// // calculates 2 to the power of 6 
// // (example from a C-to-BF compiler at https://github.com/elikaski/BF-it)
// run(""">>[-]>[-]++>[-]++++++><<<>>>>[-]+><>[-]<<[-]>[>+<<+>-]>[<+>-]
//       <><[-]>[-]<<<[>>+>+<<<-]>>>[<<<+>>>-][-]><<>>[-]>[-]<<<[>>[-]
//       <[>+>+<<-]>[<+>-]+>[[-]<-<->>]<<<-]>>[<<+>>-]<<[[-]>[-]<<[>+>
//       +<<-]>>[<<+>>-][-]>[-]<<<<<[>>>>+>+<<<<<-]>>>>>[<<<<<+>>>>>-]
//       <<>>[-]>[-]<<<[>>>+<<<-]>>>[<<[<+>>+<-]>[<+>-]>-]<<<>[-]<<[-]
//       >[>+<<+>-]>[<+>-]<><[-]>[-]<<<[>>+>+<<<-]>>>-[<<<+>>>-]<[-]>[-]
//       <<<[>>+>+<<<-]>>>[<<<+>>>-][-]><<>>[-]>[-]<<<[>>[-]<[>+>+<<-]>
//       [<+>-]+>[[-]<-<->>]<<<-]>>[<<+>>-]<<][-]>[-]<<[>+>+<<-]>>[<<+>
//       >-]<<<<<[-]>>>>[<<<<+>>>>-]<<<<><>[-]<<[-]>[>+<<+>-]>[<+>-]<>
//       <[-]>[-]>[-]<<<[>>+>+<<<-]>>>[<<<+>>>-]<<>>[-]>[-]>[-]>[-]>[-]>
//       [-]>[-]>[-]>[-]>[-]<<<<<<<<<<>>++++++++++<<[->+>-[>+>>]>[+[-<+
//       >]>+>>]<<<<<<]>>[-]>>>++++++++++<[->-[>+>>]>[+[-<+>]>+>>]<<<<<
//       ]>[-]>>[>++++++[-<++++++++>]<.<<+>+>[-]]<[<[->-<]++++++[->++++
//       ++++<]>.[-]]<<++++++[-<++++++++>]<.[-]<<[-<+>]<<><<<""")



// // a Mandelbrot set generator in brainf*** written by Erik Bosman
// (http://esoteric.sange.fi/brainfuck/utils/mandelbrot/)

// run(load_bff("mandelbrot.bf"))


// // a benchmark program (counts down from 'Z' to 'A')
// //
// run(load_bff("benchmark.bf"))

// // calculates the Collatz series for numbers from 1 to 30
// //
// run(load_bff("collatz.bf"))

}





// This template code is subject to copyright 
// by King's College London, 2022. Do not 
// make the template code public in any shape 
// or form, and do not exchange it with other 
// students under any circumstance.