brain

以前、C 言語で Brainfuck インタプリタを書きましたが、今度は Ruby で同じものを書いてみました。

クラス Machine を簡単なバーチャルマシンに見立てて、メモリの保持と演算を行なわせています。

brainfuck.rb (Gist)

#!/usr/bin/env ruby
# coding: utf-8

class Machine
  RAMSIZE = 256
  def initialize(file)
    @ram = File.open(file).read.each_char.map.to_a
    @eoc = @ram.size
    @ram.fill(0, @eoc..RAMSIZE)
    @p = @eoc
    @pp = 0
  end
  def run
    case @ram[@pp]
    when '>'; @p += 1
    when '<'; @p -= 1
    when '+'; @ram[@p] += 1
    when '-'; @ram[@p] -= 1
    when '.'; putc @ram[@p]
    when ','; @ram[@p] = stdin.readchar
    when '['
      if (@ram[@p] == 0)
        while @ram[@pp] != ']'
          @pp += 1
        end
      end
    when ']'
      if (@ram[@p] != 0)
        while @ram[@pp] != '['
          @pp -= 1
        end
      end
    else
    end
    @pp += 1
  end
  def start
    while true
      self.run
      break if @pp > @eoc
    end
  end
end

vm = Machine.new("./hello.bf")
vm.start

hello.bf (Gist)

+++++++++[>++++++++>+++++++++++>+++++<<<-]>.>++.+++++++..+++.>-.
------------.<++++++++.--------.+++.------.--------.>+.

C 言語版同様、hello.bf を読み込んで

Hello, world!

と印字します。

演算の内容は C 言語版と変わりありません。大きな違いは Machine オブジェクトごとに独立したメモリ空間・CPUが割り当てられる点と、Brainfuck のコードが読み込まれるメモリ空間と実際に操作可能なメモリ空間が同一配列上に定義されていますので、その気になればコードの実行時に自己書き換えすることが可能な点です。

人工生命シミュレーター Tierra の生物を記述するのに、現実の CPU のアセンブリ言語のような作為的な実装よりも、必要最低限の言語セットだけを持ち、よりシンプルな記述でチューリングマシンが書ける brainfuck で実装し直したら面白いんじゃないかという夏休みの自由研究的な発想から、自己書き換え可能な brainfuck を書いてみています。

オリジナルの Tierra Language の CPU 側にあるレジスタやスタックの概念って世代を重ねるごとに自然形成されるもんなんでしょうかね?

もっと欲を出すと、上の Ruby コードの演算部自体も brainfuck で実装して、さらにそれが書き換えられて進化できるようになると面白そうですが、サルにタイプライターを与えてシェイクスピアを書かせるようなものかもしれません。

Monkey