module Brainfuck extend self
OPS = {
"[" => :loop_start,
"]" => :loop_end,
">" => :move_right,
"<" => :move_left,
"+" => :inc_memory,
"-" => :dec_memory,
"." => :put_char,
"," => :get_char
}
MEM_SIZE = 65536
def parse(source)
source.chars.map { |ch|
OPS[ch]
}.compact
end
def execute(ops)
memory = Array.new(MEM_SIZE){0}
pc = 0
pointer = 0
stack = []
jump_table = {}.tap do |table|
table_stack = []
ops.each_with_index do |op, i|
case op
when :loop_start
table_stack.push(i)
when :loop_end
table[table_stack.pop || abort("invalid program")] = i
end
end
abort "invalid program" unless stack.empty?
end
while pc < ops.size
case ops[pc]
when :loop_start
if memory[pointer] == 0
pc = jump_table[pc]
else
stack.push(pc)
end
when :loop_end
pc = stack.pop - 1;
when :move_right
pointer += 1
when :move_left
pointer -= 1
when :inc_memory
memory[pointer] += 1
when :dec_memory
memory[pointer] -= 1
when :put_char
print memory[pointer].chr
when :get_char
memory[pointer] = $stdin.getc.ord
else
abort "undefined operation: #{ops[pc].inspect}"
end
memory[pointer] %= 256
pc += 1
end
end
def run(source)
execute(parse(source))
end
end
fizzbuzz = <<BRAINFUCK
>++++++++++[<++++++++++>-]<[>+>[-]>++++++++++[<++++++++++>-]<+<<[->>->+<<<]>>>
[-<<<+>>>]<>>+++<<[->+>-[>+>>]>[+[-<+>]>+>>]<<<<<<]>[-<+>]+>[-]>[<<->>[-]]>[-]
<<<[[-]++++++++++[>++++++++++<-]>++.+++.[-]<[-]+++++++++++[>+++++++++++<-]>+..
[-]<[-]<<[-]>>]<>>+++++<<[->+>-[>+>>]>[+[-<+>]>+>>]<<<<<<]>[-<+>]+>[-]>[<<->>[
-]]>[-]<<<[[-]+++++++++[>+++++++++++<-]>-.[-]<[-]+++++++++[>+++++++++++++<-]>.
+++++..[-]<[-]<<[-]>>]<<[[-]>>++++++++++<[->-[>+>>]>[+[-<+>]>+>>]<<<<<]>[-]>>[
>++++++++[<++++++>-]<.[-]]<>++++++++[<++++++>-]<.[-]<<<]>[-]++++++++++.[-]<[-]
<-]
BRAINFUCK
Brainfuck.run(ARGV.first ? File.read(ARGV.first) : fizzbuzz)
bW9kdWxlIEJyYWluZnVjayBleHRlbmQgc2VsZgogIE9QUyA9IHsKICAgICJbIiA9PiA6bG9vcF9zdGFydCwKICAgICJdIiA9PiA6bG9vcF9lbmQsCiAgICAiPiIgPT4gOm1vdmVfcmlnaHQsCiAgICAiPCIgPT4gOm1vdmVfbGVmdCwKICAgICIrIiA9PiA6aW5jX21lbW9yeSwKICAgICItIiA9PiA6ZGVjX21lbW9yeSwKICAgICIuIiA9PiA6cHV0X2NoYXIsCiAgICAiLCIgPT4gOmdldF9jaGFyCiAgfQogIE1FTV9TSVpFID0gNjU1MzYKCiAgZGVmIHBhcnNlKHNvdXJjZSkKICAgIHNvdXJjZS5jaGFycy5tYXAgeyB8Y2h8CiAgICAgIE9QU1tjaF0KICAgIH0uY29tcGFjdAogIGVuZAoKICBkZWYgZXhlY3V0ZShvcHMpCiAgICBtZW1vcnkgPSBBcnJheS5uZXcoTUVNX1NJWkUpezB9CiAgICBwYyA9IDAKICAgIHBvaW50ZXIgPSAwCiAgICBzdGFjayA9IFtdCgogICAganVtcF90YWJsZSA9IHt9LnRhcCBkbyB8dGFibGV8CiAgICAgIHRhYmxlX3N0YWNrID0gW10KICAgICAgb3BzLmVhY2hfd2l0aF9pbmRleCBkbyB8b3AsIGl8CiAgICAgICAgY2FzZSBvcAogICAgICAgIHdoZW4gOmxvb3Bfc3RhcnQKICAgICAgICAgIHRhYmxlX3N0YWNrLnB1c2goaSkKICAgICAgICB3aGVuIDpsb29wX2VuZAogICAgICAgICAgdGFibGVbdGFibGVfc3RhY2sucG9wIHx8IGFib3J0KCJpbnZhbGlkIHByb2dyYW0iKV0gPSBpCiAgICAgICAgZW5kCiAgICAgIGVuZAogICAgICBhYm9ydCAiaW52YWxpZCBwcm9ncmFtIiB1bmxlc3Mgc3RhY2suZW1wdHk/CiAgICBlbmQKCiAgICB3aGlsZSBwYyA8IG9wcy5zaXplCiAgICAgIGNhc2Ugb3BzW3BjXQogICAgICB3aGVuIDpsb29wX3N0YXJ0CiAgICAgICAgaWYgbWVtb3J5W3BvaW50ZXJdID09IDAKICAgICAgICAgIHBjID0ganVtcF90YWJsZVtwY10KICAgICAgICBlbHNlCiAgICAgICAgICBzdGFjay5wdXNoKHBjKQogICAgICAgIGVuZAogICAgICB3aGVuIDpsb29wX2VuZAogICAgICAgIHBjID0gc3RhY2sucG9wIC0gMTsKICAgICAgd2hlbiA6bW92ZV9yaWdodAogICAgICAgIHBvaW50ZXIgKz0gMQogICAgICB3aGVuIDptb3ZlX2xlZnQKICAgICAgICBwb2ludGVyIC09IDEKICAgICAgd2hlbiA6aW5jX21lbW9yeQogICAgICAgIG1lbW9yeVtwb2ludGVyXSArPSAxCiAgICAgIHdoZW4gOmRlY19tZW1vcnkKICAgICAgICBtZW1vcnlbcG9pbnRlcl0gLT0gMQogICAgICB3aGVuIDpwdXRfY2hhcgogICAgICAgIHByaW50IG1lbW9yeVtwb2ludGVyXS5jaHIKICAgICAgd2hlbiA6Z2V0X2NoYXIKICAgICAgICBtZW1vcnlbcG9pbnRlcl0gPSAkc3RkaW4uZ2V0Yy5vcmQKICAgICAgZWxzZQogICAgICAgIGFib3J0ICJ1bmRlZmluZWQgb3BlcmF0aW9uOiAje29wc1twY10uaW5zcGVjdH0iCiAgICAgIGVuZAoKICAgICAgbWVtb3J5W3BvaW50ZXJdICU9IDI1NgogICAgICBwYyArPSAxCiAgICBlbmQKICBlbmQKCiAgZGVmIHJ1bihzb3VyY2UpCiAgICBleGVjdXRlKHBhcnNlKHNvdXJjZSkpCiAgZW5kCmVuZAoKZml6emJ1enogPSA8PEJSQUlORlVDSwogPisrKysrKysrKytbPCsrKysrKysrKys+LV08Wz4rPlstXT4rKysrKysrKysrWzwrKysrKysrKysrPi1dPCs8PFstPj4tPis8PDxdPj4+CiBbLTw8PCs+Pj5dPD4+KysrPDxbLT4rPi1bPis+Pl0+WytbLTwrPl0+Kz4+XTw8PDw8PF0+Wy08Kz5dKz5bLV0+Wzw8LT4+Wy1dXT5bLV0KIDw8PFtbLV0rKysrKysrKysrWz4rKysrKysrKysrPC1dPisrLisrKy5bLV08Wy1dKysrKysrKysrKytbPisrKysrKysrKysrPC1dPisuLgogWy1dPFstXTw8Wy1dPj5dPD4+KysrKys8PFstPis+LVs+Kz4+XT5bK1stPCs+XT4rPj5dPDw8PDw8XT5bLTwrPl0rPlstXT5bPDwtPj5bCiAtXV0+Wy1dPDw8W1stXSsrKysrKysrK1s+KysrKysrKysrKys8LV0+LS5bLV08Wy1dKysrKysrKysrWz4rKysrKysrKysrKysrPC1dPi4KICsrKysrLi5bLV08Wy1dPDxbLV0+Pl08PFtbLV0+PisrKysrKysrKys8Wy0+LVs+Kz4+XT5bK1stPCs+XT4rPj5dPDw8PDxdPlstXT4+WwogPisrKysrKysrWzwrKysrKys+LV08LlstXV08PisrKysrKysrWzwrKysrKys+LV08LlstXTw8PF0+Wy1dKysrKysrKysrKy5bLV08Wy1dCiA8LV0KQlJBSU5GVUNLCgpCcmFpbmZ1Y2sucnVuKEFSR1YuZmlyc3QgPyBGaWxlLnJlYWQoQVJHVi5maXJzdCkgOiBmaXp6YnV6eikK