BFコンパイラー
以下のようにonelinerで可能です。
ただしLanguage::BF 0.03が必要です。
CodeRepos経由
で、
- svn co svn.coderepos.org/share/lang/perl/Language-BF
- cd Language-BF/trunk
- perl Makefile.PL
- make install
するか、CPANにVersion 0.03が現れるのをお待ち下さい。
Dan the Brainf.cker
1 2 3 4 | perl -MLanguage::BF \
-e 'print Language::BF->new_from_file(shift)->as_perl' t/hello.bf \
| perl
Hello World!
|
Posted feedbacks - Ruby
ひねりなし。 配列の値がbyte型を越える場合についてはとりあえず考慮しない方向で…
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 | class BF
def compile(str)
depth = 0
code = []
code << "mem = [0]"
code << "ptr = 0"
str.each_byte do |ch|
if ch == ?>
code << "\t" * depth + "ptr += 1; mem[ptr] = 0 if ptr >= mem.size"
elsif ch == ?<
code << "\t" * depth + "(ptr == 0)? mem.unshift(0) : ptr -= 1"
elsif ch == ?+
code << "\t" * depth + "mem[ptr] += 1"
elsif ch == ?-
code << "\t" * depth + "mem[ptr] -= 1"
elsif ch == ?.
code << "\t" * depth + "putc(mem[ptr])"
elsif ch == ?,
code << "\t" * depth + "mem[ptr] = STDIN.getc"
elsif ch == ?[
code << "\t" * depth + "while(mem[ptr] != 0) do"
depth += 1
elsif ch == ?]
depth -= 1
code << "\t" * depth + "end"
end
end
code.join "\n"
end
end
eval BF.new.compile("++++++++++[>+++++++>++++++++++>+++>+<<<<-]>++.>+.+++++++..+++.>++.<<+++++++++++++++.>.+++.------.--------.>+.>.") # => Hello World!
|
これまたif文の羅列を置き換える方向で書き換えてみました。
Cと違ってHashが気軽に使えるのがうれしい。
next unless が使えるのもPerl Mongerとしてはうれしい。
str.unpack("C*").map{|c| c.chr}.each do |ch|
は、単に{}とdo endを両方使ってみたかったから。
Dan the Occasional Rubyist
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 | class BF
@@opcode = {
'>' => "ptr += 1; mem[ptr] = 0 if ptr >= mem.size",
'<' => "(ptr == 0)? mem.unshift(0) : ptr -= 1",
'+' => "mem[ptr] += 1",
'-' => "mem[ptr] -= 1",
'.' => "putc(mem[ptr])",
',' => "mem[ptr] = STDIN.getc",
'[' => "while(mem[ptr] != 0) do",
']' => "end"
}
def compile(str)
code = ["mem = [0]", "ptr = 0"]
str.unpack("C*").map{|c| c.chr}.each do |ch|
next unless @@opcode[ch]
code << @@opcode[ch]
end
code.join "\n"
end
end
|
ポインタとメモリ領域を,文字列stackの中に置き,regexpなどでstackを操作しつつ動作するようなコードを吐きます.
例)
% cat hello.bf
++++++++++[>+++++++>++++++++++>+++>+<<<<-]
>++.>+.+++++++..+++.>++.<<+++++++++++++++.
>.+++.------.--------.>+.>.
% make
ruby bfcompile.rb < hello.bf > hello.rb
ruby hello.rb
Hello World!
% cat hello.rb
class String
def until_nz
while self[self[0] + 1] != 0
replace(yield(self))
end
self
end
def refer
self.sub(/\A(.)(.*)\Z/m) do
$1 + $2.sub(/^(.{#{$1[0]}})(.)/m) do
$1 + yield($2)
end
end
end
end
stack = "\000" + "\000" * 256
stack.refer {|mem| (mem[0] + 1).chr }.
refer {|mem| (mem[0] + 1).chr }.
refer {|mem| (mem[0] + 1).chr }.
refer {|mem| (mem[0] + 1).chr }.
refer {|mem| (mem[0] + 1).chr }.
refer {|mem| (mem[0] + 1).chr }.
refer {|mem| (mem[0] + 1).chr }.
refer {|mem| (mem[0] + 1).chr }.
refer {|mem| (mem[0] + 1).chr }.
refer {|mem| (mem[0] + 1).chr }.
until_nz {|stack|
stack.
sub(/./m) {|p| (p[0] + 1).chr }.
refer {|mem| (mem[0] + 1).chr }.
refer {|mem| (mem[0] + 1).chr }.
refer {|mem| (mem[0] + 1).chr }.
refer {|mem| (mem[0] + 1).chr }.
refer {|mem| (mem[0] + 1).chr }.
refer {|mem| (mem[0] + 1).chr }.
refer {|mem| (mem[0] + 1).chr }.
sub(/./m) {|p| (p[0] + 1).chr }.
refer {|mem| (mem[0] + 1).chr }.
refer {|mem| (mem[0] + 1).chr }.
refer {|mem| (mem[0] + 1).chr }.
refer {|mem| (mem[0] + 1).chr }.
refer {|mem| (mem[0] + 1).chr }.
refer {|mem| (mem[0] + 1).chr }.
refer {|mem| (mem[0] + 1).chr }.
refer {|mem| (mem[0] + 1).chr }.
refer {|mem| (mem[0] + 1).chr }.
refer {|mem| (mem[0] + 1).chr }.
sub(/./m) {|p| (p[0] + 1).chr }.
refer {|mem| (mem[0] + 1).chr }.
refer {|mem| (mem[0] + 1).chr }.
refer {|mem| (mem[0] + 1).chr }.
sub(/./m) {|p| (p[0] + 1).chr }.
refer {|mem| (mem[0] + 1).chr }.
sub(/./m) {|p| (p[0] - 1).chr }.
sub(/./m) {|p| (p[0] - 1).chr }.
sub(/./m) {|p| (p[0] - 1).chr }.
sub(/./m) {|p| (p[0] - 1).chr }.
refer {|mem| (mem[0] - 1).chr }.
to_s
}.
sub(/./m) {|p| (p[0] + 1).chr }.
refer {|mem| (mem[0] + 1).chr }.
refer {|mem| (mem[0] + 1).chr }.
refer {|mem| putc(mem) }.
sub(/./m) {|p| (p[0] + 1).chr }.
refer {|mem| (mem[0] + 1).chr }.
refer {|mem| putc(mem) }.
refer {|mem| (mem[0] + 1).chr }.
refer {|mem| (mem[0] + 1).chr }.
refer {|mem| (mem[0] + 1).chr }.
refer {|mem| (mem[0] + 1).chr }.
refer {|mem| (mem[0] + 1).chr }.
refer {|mem| (mem[0] + 1).chr }.
refer {|mem| (mem[0] + 1).chr }.
refer {|mem| putc(mem) }.
refer {|mem| putc(mem) }.
refer {|mem| (mem[0] + 1).chr }.
refer {|mem| (mem[0] + 1).chr }.
refer {|mem| (mem[0] + 1).chr }.
refer {|mem| putc(mem) }.
sub(/./m) {|p| (p[0] + 1).chr }.
refer {|mem| (mem[0] + 1).chr }.
refer {|mem| (mem[0] + 1).chr }.
refer {|mem| putc(mem) }.
sub(/./m) {|p| (p[0] - 1).chr }.
sub(/./m) {|p| (p[0] - 1).chr }.
refer {|mem| (mem[0] + 1).chr }.
refer {|mem| (mem[0] + 1).chr }.
refer {|mem| (mem[0] + 1).chr }.
refer {|mem| (mem[0] + 1).chr }.
refer {|mem| (mem[0] + 1).chr }.
refer {|mem| (mem[0] + 1).chr }.
refer {|mem| (mem[0] + 1).chr }.
refer {|mem| (mem[0] + 1).chr }.
refer {|mem| (mem[0] + 1).chr }.
refer {|mem| (mem[0] + 1).chr }.
refer {|mem| (mem[0] + 1).chr }.
refer {|mem| (mem[0] + 1).chr }.
refer {|mem| (mem[0] + 1).chr }.
refer {|mem| (mem[0] + 1).chr }.
refer {|mem| (mem[0] + 1).chr }.
refer {|mem| putc(mem) }.
sub(/./m) {|p| (p[0] + 1).chr }.
refer {|mem| putc(mem) }.
refer {|mem| (mem[0] + 1).chr }.
refer {|mem| (mem[0] + 1).chr }.
refer {|mem| (mem[0] + 1).chr }.
refer {|mem| putc(mem) }.
refer {|mem| (mem[0] - 1).chr }.
refer {|mem| (mem[0] - 1).chr }.
refer {|mem| (mem[0] - 1).chr }.
refer {|mem| (mem[0] - 1).chr }.
refer {|mem| (mem[0] - 1).chr }.
refer {|mem| (mem[0] - 1).chr }.
refer {|mem| putc(mem) }.
refer {|mem| (mem[0] - 1).chr }.
refer {|mem| (mem[0] - 1).chr }.
refer {|mem| (mem[0] - 1).chr }.
refer {|mem| (mem[0] - 1).chr }.
refer {|mem| (mem[0] - 1).chr }.
refer {|mem| (mem[0] - 1).chr }.
refer {|mem| (mem[0] - 1).chr }.
refer {|mem| (mem[0] - 1).chr }.
refer {|mem| putc(mem) }.
sub(/./m) {|p| (p[0] + 1).chr }.
refer {|mem| (mem[0] + 1).chr }.
refer {|mem| putc(mem) }.
sub(/./m) {|p| (p[0] + 1).chr }.
refer {|mem| putc(mem) }.
to_s
例)
% cat hello.bf
++++++++++[>+++++++>++++++++++>+++>+<<<<-]
>++.>+.+++++++..+++.>++.<<+++++++++++++++.
>.+++.------.--------.>+.>.
% make
ruby bfcompile.rb < hello.bf > hello.rb
ruby hello.rb
Hello World!
% cat hello.rb
class String
def until_nz
while self[self[0] + 1] != 0
replace(yield(self))
end
self
end
def refer
self.sub(/\A(.)(.*)\Z/m) do
$1 + $2.sub(/^(.{#{$1[0]}})(.)/m) do
$1 + yield($2)
end
end
end
end
stack = "\000" + "\000" * 256
stack.refer {|mem| (mem[0] + 1).chr }.
refer {|mem| (mem[0] + 1).chr }.
refer {|mem| (mem[0] + 1).chr }.
refer {|mem| (mem[0] + 1).chr }.
refer {|mem| (mem[0] + 1).chr }.
refer {|mem| (mem[0] + 1).chr }.
refer {|mem| (mem[0] + 1).chr }.
refer {|mem| (mem[0] + 1).chr }.
refer {|mem| (mem[0] + 1).chr }.
refer {|mem| (mem[0] + 1).chr }.
until_nz {|stack|
stack.
sub(/./m) {|p| (p[0] + 1).chr }.
refer {|mem| (mem[0] + 1).chr }.
refer {|mem| (mem[0] + 1).chr }.
refer {|mem| (mem[0] + 1).chr }.
refer {|mem| (mem[0] + 1).chr }.
refer {|mem| (mem[0] + 1).chr }.
refer {|mem| (mem[0] + 1).chr }.
refer {|mem| (mem[0] + 1).chr }.
sub(/./m) {|p| (p[0] + 1).chr }.
refer {|mem| (mem[0] + 1).chr }.
refer {|mem| (mem[0] + 1).chr }.
refer {|mem| (mem[0] + 1).chr }.
refer {|mem| (mem[0] + 1).chr }.
refer {|mem| (mem[0] + 1).chr }.
refer {|mem| (mem[0] + 1).chr }.
refer {|mem| (mem[0] + 1).chr }.
refer {|mem| (mem[0] + 1).chr }.
refer {|mem| (mem[0] + 1).chr }.
refer {|mem| (mem[0] + 1).chr }.
sub(/./m) {|p| (p[0] + 1).chr }.
refer {|mem| (mem[0] + 1).chr }.
refer {|mem| (mem[0] + 1).chr }.
refer {|mem| (mem[0] + 1).chr }.
sub(/./m) {|p| (p[0] + 1).chr }.
refer {|mem| (mem[0] + 1).chr }.
sub(/./m) {|p| (p[0] - 1).chr }.
sub(/./m) {|p| (p[0] - 1).chr }.
sub(/./m) {|p| (p[0] - 1).chr }.
sub(/./m) {|p| (p[0] - 1).chr }.
refer {|mem| (mem[0] - 1).chr }.
to_s
}.
sub(/./m) {|p| (p[0] + 1).chr }.
refer {|mem| (mem[0] + 1).chr }.
refer {|mem| (mem[0] + 1).chr }.
refer {|mem| putc(mem) }.
sub(/./m) {|p| (p[0] + 1).chr }.
refer {|mem| (mem[0] + 1).chr }.
refer {|mem| putc(mem) }.
refer {|mem| (mem[0] + 1).chr }.
refer {|mem| (mem[0] + 1).chr }.
refer {|mem| (mem[0] + 1).chr }.
refer {|mem| (mem[0] + 1).chr }.
refer {|mem| (mem[0] + 1).chr }.
refer {|mem| (mem[0] + 1).chr }.
refer {|mem| (mem[0] + 1).chr }.
refer {|mem| putc(mem) }.
refer {|mem| putc(mem) }.
refer {|mem| (mem[0] + 1).chr }.
refer {|mem| (mem[0] + 1).chr }.
refer {|mem| (mem[0] + 1).chr }.
refer {|mem| putc(mem) }.
sub(/./m) {|p| (p[0] + 1).chr }.
refer {|mem| (mem[0] + 1).chr }.
refer {|mem| (mem[0] + 1).chr }.
refer {|mem| putc(mem) }.
sub(/./m) {|p| (p[0] - 1).chr }.
sub(/./m) {|p| (p[0] - 1).chr }.
refer {|mem| (mem[0] + 1).chr }.
refer {|mem| (mem[0] + 1).chr }.
refer {|mem| (mem[0] + 1).chr }.
refer {|mem| (mem[0] + 1).chr }.
refer {|mem| (mem[0] + 1).chr }.
refer {|mem| (mem[0] + 1).chr }.
refer {|mem| (mem[0] + 1).chr }.
refer {|mem| (mem[0] + 1).chr }.
refer {|mem| (mem[0] + 1).chr }.
refer {|mem| (mem[0] + 1).chr }.
refer {|mem| (mem[0] + 1).chr }.
refer {|mem| (mem[0] + 1).chr }.
refer {|mem| (mem[0] + 1).chr }.
refer {|mem| (mem[0] + 1).chr }.
refer {|mem| (mem[0] + 1).chr }.
refer {|mem| putc(mem) }.
sub(/./m) {|p| (p[0] + 1).chr }.
refer {|mem| putc(mem) }.
refer {|mem| (mem[0] + 1).chr }.
refer {|mem| (mem[0] + 1).chr }.
refer {|mem| (mem[0] + 1).chr }.
refer {|mem| putc(mem) }.
refer {|mem| (mem[0] - 1).chr }.
refer {|mem| (mem[0] - 1).chr }.
refer {|mem| (mem[0] - 1).chr }.
refer {|mem| (mem[0] - 1).chr }.
refer {|mem| (mem[0] - 1).chr }.
refer {|mem| (mem[0] - 1).chr }.
refer {|mem| putc(mem) }.
refer {|mem| (mem[0] - 1).chr }.
refer {|mem| (mem[0] - 1).chr }.
refer {|mem| (mem[0] - 1).chr }.
refer {|mem| (mem[0] - 1).chr }.
refer {|mem| (mem[0] - 1).chr }.
refer {|mem| (mem[0] - 1).chr }.
refer {|mem| (mem[0] - 1).chr }.
refer {|mem| (mem[0] - 1).chr }.
refer {|mem| putc(mem) }.
sub(/./m) {|p| (p[0] + 1).chr }.
refer {|mem| (mem[0] + 1).chr }.
refer {|mem| putc(mem) }.
sub(/./m) {|p| (p[0] + 1).chr }.
refer {|mem| putc(mem) }.
to_s
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 | puts <<'EOS'
class String
def until_nz
while self[self[0] + 1] != 0
replace(yield(self))
end
self
end
def refer
self.sub(/\A(.)(.*)\Z/m) do
$1 + $2.sub(/^(.{#{$1[0]}})(.)/m) do
$1 + yield($2)
end
end
end
end
stack = "\000" + "\000" * 256
EOS
print 'stack.'
code = {
'>' => [ 'sub(/./m) {|p| (p[0] + 1).chr }.' ],
'<' => [ 'sub(/./m) {|p| (p[0] - 1).chr }.' ],
'+' => [ 'refer {|mem| (mem[0] + 1).chr }.' ],
'-' => [ 'refer {|mem| (mem[0] - 1).chr }.' ],
'.' => [ 'refer {|mem| putc(mem) }.' ],
',' => [ 'refer { STDIN.getc }.' ],
'[' => [ 'until_nz {|stack|', 'stack.' ],
']' => [ 'to_s', '}.' ],
}
while ch = STDIN.getc
next if code[ch.chr].nil?
puts code[ch.chr]
end
puts 'to_s'
|
メモリとポインタを用意しておいて,あとは命令を1つずつRubyに置き換えるだけ。他の人と々アプローチだけど,いくらかわかりやすく書いたつもり。
書いてて気がついたけど,BFのループって終了判定が2カ所(前後)にあるんだな。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 | print <<"EOBF"
class BF
def initialize
@memory = [0]
@pointer = 0
end
def current
@memory[@pointer]
end
def incr
@memory[@pointer] += 1
end
def decr
@memory[@pointer] -= 1
end
def right
@pointer += 1
unless @memory[@pointer]
@memory << 0
end
end
def left
@pointer -= 1
end
def set(c)
@memory[@pointer] = c
end
def printc
print @memory[@pointer].chr
end
end
bf = BF.new
EOBF
commands = {
">" => "bf.right",
"<" => "bf.left",
"+" => "bf.incr",
"-" => "bf.decr",
"." => "bf.printc",
"," => "c = STDIN.getc; bf.set(c)",
"[" => "begin; break if bf.current.zero?",
"]" => "end until bf.current.zero?"
}
ARGF.each_byte do |c|
cmd = commands[c.chr]
puts cmd if cmd
end
|




dankogai
#3886()
Rating0/2=0.00
「どう書く?」でまだ出ていないのが不思議なお題。それがBF処理系。 ここでは、BFで書かれたソースを、同じ言語に変換するコンパイラーを募集します。
私自身、すでにPerlとJavaScriptに関しては http://blog.livedoor.jp/dankogai/archives/50545151.html でやっているのですが、他の言語バージョンも是非見たいので。
Dan the Brainf.ucker
see: Brainfuck - Wikipedia
1 reply [ reply ]