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 あいうえお あいうえお