ScalaでBrainf*ckのインタプリタを書いてみたよ - 都元ダイスケ IT-PRESS
Scalaを頑張っておるようなので、私もBrainf*ckのインタープリタをなんとなく実装してみた。
BrainfuckRuntimeと、Expression系のクラスが関数型らしくないのでなんとかしたいな...。
ソースはgithubにあげてます。ツッコミ or フォーク歓迎 https://github.com/j5ik2o/brainfuck-scala
とりあえず、nullチェックとか、例外処理は適当です。
package com.github.j5ik2o.brainfuck object BrainfuckApplication { def main(args: Array[String]) = try { new BrainfuckRuntime(new BrainfuckParser).execute(args(0)) } catch { case BrainfuckException(msg) => println(msg) } }
以下のように実行するとHello World!が表示されるはず。
$ scala com.github.j5ik2o.brainfuck.BrainfuckApplication "++++++++++[>++++++++++<-]>++++.+++++++.--------.--."
以下、パーサーとランタイムのソース。
package com.github.j5ik2o.brainfuck case class BrainfuckException(msg:String) extends RuntimeException class BrainfuckRuntime(parser: BrainfuckParser, size: Int) { require(size > 0) val memory = Array.fill(size)(0) var pointer = 0 var counter = 0 val evaluator = new Evaluator() def this(parser: BrainfuckParser) = this (parser, 3000) // Brainfuckのスクリプトを実行する def execute(script: String) { val parseResult = parser.parse(script) if (parseResult.successful) { evaluateExpressions(parseResult.get) println } else { throw new BrainfuckException("parse error") } } // ASTを評価するビジター class Evaluator extends ExpressionVisitor { override def visit(expression: Expression): Unit = expression match { case IncrementPointerExpression() => incrementPointer case DecrementPointerExpression() => decrementPointer case IncrementMemoryAtPointerExpression() => incrementMemoryAtPointer case DecrementMemoryAtPointerExpression() => decrementMemoryAtPointer case OutputMemoryAtPointerExpression() => outputMemoryAtPointer case LoopExpression(expressions: List[Expression]) => loop(expressions) } } // 以下、ランタイムが持つAPI private def validateRange = if (counter > size) throw new BrainfuckException("limit over") private def readMemory = { validateRange memory(pointer) } private def writeMemory(b: Int) = { validateRange memory(pointer) = b } private def incrementPointer { validateRange pointer += 1 counter += 1 } private def decrementPointer { validateRange pointer -= 1 counter += 1 } private def incrementMemoryAtPointer { writeMemory(readMemory + 1) } private def decrementMemoryAtPointer { writeMemory(readMemory - 1) } private def outputMemoryAtPointer { print(readMemory.toChar) } private def loop(expressions: List[Expression]) { while (readMemory != 0) { evaluateExpressions(expressions) } } private def evaluateExpressions(expressions: List[Expression]) { expressions.foreach(_.accept(evaluator)) } }
Scalaのパーサコンビネータを使って実装しているので、以下のURLを読むとコードを理解しやすいと思います。
http://www.coins.tsukuba.ac.jp/~i021216/Scala-parser-combinator.pdf
package com.github.j5ik2o.brainfuck import util.parsing.combinator._ // 式を訪問するビジター trait ExpressionVisitor { def visit(e: Expression): Unit } // 式を表すトレイト trait Expression { def accept(visitor: ExpressionVisitor): Unit = { visitor.visit(this) } } // 式の実装 これを使ってASTを構築する case class IncrementPointerExpression extends Expression case class DecrementPointerExpression extends Expression case class IncrementMemoryAtPointerExpression extends Expression case class DecrementMemoryAtPointerExpression extends Expression case class OutputMemoryAtPointerExpression extends Expression case class LoopExpression(expressions:List[Expression]) extends Expression // Brainfuckパーサ class BrainfuckParser extends JavaTokenParsers { def parse(source:String) = parseAll(brainfuck, source) def brainfuck: Parser[List[Expression]] = rep(instruction) def instruction: Parser[Expression] = loop | token def token: Parser[Expression] = incrementPointer ||| decrementPointer ||| incrementMemoryAtPointer ||| decrementMemoryAtPointer ||| outputMemoryAtPointer def incrementPointer: Parser[Expression] = ">" ^^ { case ops => IncrementPointerExpression() } def decrementPointer: Parser[Expression] = "<" ^^ { case ops => DecrementPointerExpression() } def incrementMemoryAtPointer: Parser[Expression] = "+" ^^ { case ops => IncrementMemoryAtPointerExpression() } def decrementMemoryAtPointer: Parser[Expression] = "-" ^^ { case ops => DecrementMemoryAtPointerExpression() } def outputMemoryAtPointer: Parser[Expression] = "." ^^ { case ops => OutputMemoryAtPointerExpression() } def loop: Parser[Expression] = "["~>brainfuck<~"]" ^^ { case exprs => LoopExpression(exprs) } }