Skip to content

Instantly share code, notes, and snippets.

@ingramj
Created February 25, 2009 00:37
Show Gist options
  • Star 8 You must be signed in to star a gist
  • Fork 2 You must be signed in to fork a gist
  • Save ingramj/69910 to your computer and use it in GitHub Desktop.
Save ingramj/69910 to your computer and use it in GitHub Desktop.
A Brainfuck interpreter written in Ruby.
#!/usr/bin/env ruby
class BrainFuck
def initialize
@ops = create_ops
@tape = Array.new(1024,0)
@tp = 0
@code = []
@cp = 0
end
def compile c
c.split("").each do |o|
if @ops.has_key? o
@code << o
end
end
return self
end
def run
while @cp < @code.size
run_op @code[@cp]
end
@cp = 0
end
private
def run_op op
@ops[op].call
@cp += 1
end
def get_input
@tape[@tp] = STDIN.getc
# getc returns nil on EOF. We want to use 0 instead.
@tape[@tp] = 0 unless @tape[@tp]
end
def create_ops
{ ">" => Proc.new { @tp = (@tp == @tape.size - 1 ? 0 : @tp + 1) },
"<" => Proc.new { @tp = (@tp == 0 ? @tape.size - 1 : @tp - 1) },
"+" => Proc.new { @tape[@tp] += 1 },
"-" => Proc.new { @tape[@tp] -= 1 },
"." => Proc.new { print @tape[@tp].chr if @tape[@tp] },
"," => Proc.new { get_input },
"[" => Proc.new { jump_to_close if @tape[@tp] == 0 },
"]" => Proc.new { jump_to_open unless @tape[@tp] == 0 }
}
end
def jump_to_close
level = 1
while @cp < @code.size
@cp += 1
if @code[@cp] == '['
level += 1
elsif @code[@cp] == ']'
level -= 1
end
break if level == 0
end
end
def jump_to_open
level = 1
while @cp >= 0
@cp -= 1
if @code[@cp] == ']'
level += 1
elsif @code[@cp] == '['
level -= 1
end
break if level == 0
end
end
end
if __FILE__ == $0
app = BrainFuck.new
File.open(ARGV[0], 'r') { |f|
app.compile(f.read)
}
app.run
end
@jchillerup
Copy link

Not a rubyist, but isn't there a problem with the "." operator? Doesn't it support only printable characters? The ol'school Brainfuck interpreter allows printing all the ASCII control chars too.

@ingramj
Copy link
Author

ingramj commented Sep 9, 2011

As far as I can tell, they behave the same. Here are the lines from the original:

case '.': putchar(a[p]); fflush(stdout); break;
case ',': a[p]=getchar();fflush(stdout); break;

Here's what happens when you enter a ^C character:
% cat test.bf
,.
% ruby brainfuck.rb test.bf | hexdump
^V^C
0000000 0003
0000001

@jchillerup
Copy link

Seems I stand corrected! Cool, thanks!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment