Created
February 25, 2009 00:37
-
-
Save ingramj/69910 to your computer and use it in GitHub Desktop.
A Brainfuck interpreter written in Ruby.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/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 |
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
Seems I stand corrected! Cool, thanks!
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
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.