Brainfuckの言語仕様
これは,wikipediaからの引用です.
処理系は次の要素から成る: Brainfuckプログラム、インストラクションポインタ(プログラム中のある文字を指す)、少なくとも30000個の要素を持つバイトの配列(各要素はゼロで初期化される)、データポインタ(前述の配列のどれかの要素を指す。最も左の要素を指すよう初期化される)、入力と出力の2つのバイトストリーム。 Brainfuckプログラムは、以下の8個の実行可能な命令から成る(他の文字は無視され、読み飛ばされる)。
ポインタをインクリメントする。ポインタをptrとすると、C言語の「ptr++;」に相当する。
- < ポインタをデクリメントする。C言語の「ptr–;」に相当。
- ポインタが指す値をインクリメントする。C言語の「(*ptr)++;」に相当。
- ポインタが指す値をデクリメントする。C言語の「(*ptr)–;」に相当。
- . ポインタが指す値を出力に書き出す。C言語の「putchar(*ptr);」に相当。
- , 入力から1バイト読み込んで、ポインタが指す先に代入する。C言語の「*ptr=getchar();」に相当。
- [ ポインタが指す値が0なら、対応する ] の直後にジャンプする。C言語の「while(*ptr){」に相当。
- ] ポインタが指す値が0でないなら、対応する [ (の直後[1])にジャンプする。C言語の「}」に相当[2]。
実装
rubyを使いました."[“と”]“のところはやっぱり大変.
#!/usr/bin/env ruby
class BrainFuck
def set(program)
@pc = 0 # プログラムポインタ
@pro = program # プログラム
@mar = 0 # メモリアドレスレジスタ
@mem = Array.new(30000,0) # メモリ(30000Bytes分)
end
def step()
# オペコード読み出し
op = @pro[@pc]
@pc+=1
# 実行
case op
when ">"
@mar+=1
when "<"
@mar-=1
when "+"
@mem[@mar]+=1
when "-"
@mem[@mar]-=1
when "."
print @mem[@mar].chr
when "["
if @mem[@mar] == 0
depth = 0
(@pc..@pro.length).each do |i|
# 対応する括弧発見
if depth == 0 && @pro[i] == "]"
@pc = i+1
break
# 深さを調べる
elsif @pro[i] == "["
depth+=1
elsif @pro[i] == "]"
depth-=1
end
end
end
when "]"
if @mem[@mar]!=0
depth = 0
(0..@pc-2).reverse_each do |i|
# 対応する括弧発見
if depth == 0 && @pro[i] == "["
@pc = i+1
break
# 深さを調べる
elsif @pro[i] == "]"
depth+=1
elsif @pro[i] == "["
depth-=1
end
end
end
end
end
def exec()
while @pc!=@pro.length
step
end
print "\n"
end
end
brainfuck = BrainFuck.new
while line = gets
brainfuck.set(line)
brainfuck.exec
end
テスト
brainfuckプログラミングをしているところです.実行権限をつけてから遊んでください.それと,行ごとに読み込んでいるのでbrainfuck中に改行コードが入るとまずいです.
$ ./brainfuck.rb +++++++++[>++++++++>+++++++++++>+++++<<<-]>.>++.+++++++..+++.>-.------------.<++++++++.--------.+++.------.--------.>+. Hello, world! ++++++++++[>++++++++++>+++++++++++>++++++++++++>++++++++++>++++++++++>+++++++++++<<<<<<-]>--.>+.<.>>---.>++++.>+++++.>++++.<<<<. bobuhiro