Ruby で Brainfuck インタプリタを実装する

はじめに

Ruby で Brainfuck インタプリタを実装しました。できるだけ https://www.muppetlabs.com/~breadbox/bf/ にある仕様の記述をそのまま表す書き方にしています。例外処理はほとんどしていません。

ソースコード

#!/usr/bin/env ruby
# A Brainfuck program has an implicit byte pointer, called "the pointer".
# It can move freely within an array of 30,000 bytes, all initially set to zero.
# The pointer is initialized to the beginning of this array.
pointer, array = 0, Array.new(30000, 0)

source = ARGV[0]

# Computes and stores forward and backward matching brackets.
# A stack of positions of opening brackets.
open_brackets = []
forward_matching = {}
backward_matching = {}
source.each_char.each_with_index do |c, i|
  case c
  when "["
    open_brackets.push(i)
  when "]"
    open_pos = open_brackets.pop
    forward_matching[open_pos] = i
    backward_matching[i] = open_pos
  end
end

# Current instruction index.
i = 0

# The Brainfuck programming language consists of eight commands, each of which is represented as a single character.
commands = {
  ">" => ->() { pointer += 1 },
  "<" => ->() { pointer -= 1 },
  "+" => ->() { array[pointer] += 1 },
  "-" => ->() { array[pointer] -= 1 },
  "." => ->() { print array[pointer].chr },
  "," => ->() { array[pointer] = STDIN.getc.ord },
  "[" => ->() { i = forward_matching[i] if array[pointer] == 0 },
  "]" => ->() { i = backward_matching[i] if array[pointer] != 0 },
}

while i < source.length
  pre = i
  c = commands[source[i]]
  c.call if c
  i += 1 if pre == i
end

おわりに

リポジトリは https://github.com/jajimajp/bfrb にあります。