ScalaでBrainf*ck

「言語の入門ではまずBrainf*ck処理系を作れ」なる持論を何故か若手の会で発表したこともあり、ScalaでBrainf*ckの処理系書いた。コンパイラインタプリタ方式。一回Scalaの () => unit な関数列にコンパイルしてから実行。なんか色々適当。

import java.lang.System
import java.io.FileInputStream
import java.io.InputStream
import java.io.File
import scala.collection.mutable.ArrayBuffer

object BFi{
  val in = System.in
  val out = System.out
  val mem = new Array[Byte](30000)
  var pt = 0
  def incExp(){
    mem(pt) = (mem(pt) + 1).toByte
  }
  def decExp(){
    mem(pt) = (mem(pt) - 1).toByte
  }
  def nextExp(){
    pt = pt + 1
  }
  def prevExp(){
    pt = pt - 1
  }
  def getExp(){
    mem(pt) = in.read.toByte
  }
  def putExp(){
    out.write(mem(pt).toChar)
  }
  def noneExp(){
  }
  def makeExp(input: InputStream, c: Int): () => unit = c match{
    case '+' => incExp
    case '-' => decExp
    case '>' => nextExp
    case '<' => prevExp
    case '.' => putExp
    case ',' => getExp
    case '[' => makeBlock(input)
    case _ => noneExp
  }
  def makeBlock(input: InputStream): () => unit = {
    var exps = new ArrayBuffer[() => unit]
    var c = input.read
    while(c != ']' && c!= -1){
      val exp = makeExp(input, c)
      if(exp != noneExp){
        exps + exp
      }
      c = input.read
    }
    def block(){
      while(mem(pt)!=0) exps.foreach(x => x())
    }
    return block
  }
  def compile(input: InputStream): () => unit = {
    var exps = new ArrayBuffer[() => unit]
    var c = input.read
    while(c != -1){
      val exp = makeExp(input, c)
      if(exp != noneExp){
        exps + exp
      }
      c = input.read
    }
    def block(){
      exps.foreach(x => x())
    }
    return block
  }
  def main(args: Array[String]){
    if(args.length>0){
      val sourceFile = new File(args(0))
      val input = new FileInputStream(sourceFile)
      val body = compile(input)
      body()
      out.flush
    }
  }
}

while(c!=-1) とかその辺、超ほげすぎる。

% cat echo.bf
+[,.]
% scala BFi echo.bf 
hogeghoge
hogeghoge
あいうえお
あいうえお

test