Execute Brain****/Ruby: Difference between revisions

m
Fixed syntax highlighting.
m (needs attention: nested loops)
m (Fixed syntax highlighting.)
 
(6 intermediate revisions by 5 users not shown)
Line 1:
{{implementation|Brainf***}}{{collection|RCBF}}[[Category:Ruby]]
===Version 1===
{{needs-review|Ruby|'''Does not handle nested loops.'''}}
An implementation of a [[Brainf***]] interpreter in [[Ruby]].
More effort could be made to read a program from a file or from stdin.
 
<langsyntaxhighlight lang="ruby">class RCBF
def initialize(program)
@d = [0] * 30_000
@program = program
@jumpback_table = read_program
end
 
def read_program
jumpback_table = {}
jump_to = []
@program.each_char.with_index do |char, idx|
case char
when "[" then jump_to.push(idx)
when "]" then jumpback_table[idx] = jump_to.pop
end
end
jumpback_table
end
def run
invert_table = @jumpback_table.invert
dc = 0
pc = 0
while pc < @program.length
print [pc, @program[pc].chr].inspect if $DEBUG
 
case @program[pc]
when ?>
dc += 1
print "\t#{dc}" if $DEBUG
when ?<
dc -= 1
print "\t#{dc}" if $DEBUG
when ?+
@d[dc] += 1
print "\t#{dc},#{@d[dc]}" if $DEBUG
when ?-
@d[dc] -= 1
print "\t#{dc},#{@d[dc]}" if $DEBUG
when ?.
print "\t#{dc},#{@d[dc]}\t" if $DEBUG
print @d[dc].chr
when ?, then
@d[dc] = $stdin.getc
print "\t#{dc},#{@d[dc]}" if $DEBUG
when ?[ then
if @d[dc] == 0
pc += 1 while @programinvert_table[pc] != ?]
pprint " #{[pc,@program[pc].chr].inspect}" if $DEBUG
end
when ?] then
if @d[dc] != 0
pc -= 1 while @programjumpback_table[pc] != ?[
pprint " #{[pc,@program[pc].chr].inspect}" if $DEBUG
end
end
Line 49 ⟶ 64:
end
end
end</lang>
 
Test:
# output 'Hello World!\n'
<pre>irb(main):048:0> helloworld = '++++++++++[>+++++++>++++++++++>+++>+<<<<-]>++.>+.+++++++..+++.>++.<<+++++++++++++++.>.+++.------.--------.>+.>.'
helloworld = <<PROGRAM
=> "++++++++++[>+++++++>++++++++++>+++>+<<<<-]>++.>+.+++++++..+++.>++.<<+++++++++++++++.>.+++.------.--------.>+.>."
++++++++++[>+++++++>++++++++++>+++>+<<<<-]
irb(main):049:0> bf = RCBF.new(helloworld)
<pre>irb(main):048:0> helloworld = '++++++++++[>+++++++>++++++++++>+++>+<<<<-]>++.>+.+++++++..+++.>++.<<+++++++++++++++.>.+++.------.--------.>+.>.'
=> #<RCBF:0x7ff537d0 @d=[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
PROGRAM
...
irb(main):049:0> bf = RCBF.new(helloworld)
irb(main):050:0> bf.run
bf.run
Hello World!
=> nil</pre>
# use nested loop to increment count to 64 and print (should be '@')
# followed by a newline
RCBF.new('>>++++[<++++[<++++>-]>-]<<.[-]++++++++++.').run</syntaxhighlight>
 
{{out}}
<pre>Hello World!
=> nil@</pre>
 
===Version 2===
This variant converts the brainfuck into Ruby code and runs that instead.
Do note that this requires Ruby1.9.1 or later, earlier versions need a somewhat more verbose variant.
 
BF code may be read from a file or taken from STDIN.
 
<syntaxhighlight lang="ruby">eval 'm=Hash.new(p=0);'+ARGF.read.gsub(
/./,
'>' => 'p+=1;',
'<' => 'p-=1;',
'+' => 'm[p]+=1;',
'-' => 'm[p]-=1;',
'[' => '(;',
']' => ')while((m[p]&=255)!=0);',
'.' => 'putc(m[p]&=255);',
',' => 'm[p]=STDIN.getc.ord if !STDIN.eof;')</syntaxhighlight>
9,476

edits