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

From Rosetta Code
Content added Content deleted
(handle nested loops)
m (Fixed syntax highlighting.)
 
(5 intermediate revisions by 5 users not shown)
Line 1: Line 1:
{{implementation|Brainf***}}{{collection|RCBF}}[[Category:Ruby]]
{{implementation|Brainf***}}{{collection|RCBF}}
===Version 1===
An implementation of a [[Brainf***]] interpreter in [[Ruby]].
More effort could be made to read a program from a file or from stdin.
More effort could be made to read a program from a file or from stdin.


<lang ruby>class RCBF
<syntaxhighlight lang="ruby">class RCBF
def initialize(program)
def initialize(program)
@d = [0] * 30_000
@d = [0] * 30_000
Line 11: Line 13:
def read_program
def read_program
jumpback_table = {}
jumpback_table = {}
nest_level = 0
jump_to = []
@program.each_char.with_index do |char, idx|
start_idx = []
@program.each_char.each_with_index do |char, idx|
case char
case char
when "["
when "[" then jump_to.push(idx)
start_idx[nest_level] = idx
when "]" then jumpback_table[idx] = jump_to.pop
nest_level += 1
when "]"
nest_level -= 1
jumpback_table[idx] = start_idx[nest_level]
end
end
end
end
jumpback_table
jumpback_table
end
end

def run
def run
invert_table = @jumpback_table.invert
dc = 0
dc = 0
pc = 0
pc = 0
while pc < @program.length
while pc < @program.length
print [pc, @program[pc].chr].inspect if $DEBUG
print [pc, @program[pc]] if $DEBUG

case @program[pc]
case @program[pc]
when ?>
when ?>
dc += 1
dc += 1
print "\t#{dc}" if $DEBUG
print "\t#{dc}" if $DEBUG
when ?<
when ?<
dc -= 1
dc -= 1
print "\t#{dc}" if $DEBUG
print "\t#{dc}" if $DEBUG
when ?+
when ?+
@d[dc] += 1
@d[dc] += 1
print "\t#{dc},#{@d[dc]}" if $DEBUG
print "\t#{dc},#{@d[dc]}" if $DEBUG
when ?-
when ?-
@d[dc] -= 1
@d[dc] -= 1
print "\t#{dc},#{@d[dc]}" if $DEBUG
print "\t#{dc},#{@d[dc]}" if $DEBUG
when ?.
when ?.
print "\t#{dc},#{@d[dc]}\t" if $DEBUG
print "\t#{dc},#{@d[dc]}\t" if $DEBUG
print @d[dc].chr
print @d[dc].chr
when ?, then
when ?,
@d[dc] = $stdin.getc
@d[dc] = $stdin.getc
print "\t#{dc},#{@d[dc]}" if $DEBUG
print "\t#{dc},#{@d[dc]}" if $DEBUG
when ?[ then
when ?[
if @d[dc] == 0
if @d[dc] == 0
pc = @jumpback_table.invert[pc]
pc = invert_table[pc]
p " #{[pc,@program[pc].chr].inspect}" if $DEBUG
print " #{[pc,@program[pc]]}" if $DEBUG
end
end
when ?] then
when ?]
if @d[dc] != 0
if @d[dc] != 0
pc = @jumpback_table[pc]
pc = @jumpback_table[pc]
p " #{[pc,@program[pc].chr].inspect}" if $DEBUG
print " #{[pc,@program[pc]]}" if $DEBUG
end
end
end
end
Line 75: Line 73:
bf = RCBF.new(helloworld)
bf = RCBF.new(helloworld)
bf.run
bf.run
# use nested loop to increment count to 64 and print (should be '@')
# followed by a newline
RCBF.new('>>++++[<++++[<++++>-]>-]<<.[-]++++++++++.').run</syntaxhighlight>


{{out}}
# use nested loop to increment count to 64 and print (should be '@')"
# 64 = 4*4*4
nestedloop = '>>++++[<++++[<++++>-]>-]<<.[-]++++++++++.'
bf = RCBF.new(nestedloop)
bf.run</lang>

Output:
<pre>Hello World!
<pre>Hello World!
@</pre>
@</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>

Latest revision as of 11:57, 1 September 2022

Execute Brain****/Ruby is an implementation of Brainf***. Other implementations of Brainf***.
Execute Brain****/Ruby is part of RCBF. You may find other members of RCBF at Category:RCBF.

Version 1

An implementation of a Brainf*** interpreter in Ruby. More effort could be made to read a program from a file or from stdin.

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]] 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 ?,
        @d[dc] = $stdin.getc
        print "\t#{dc},#{@d[dc]}" if $DEBUG
      when ?[
        if @d[dc] == 0
          pc = invert_table[pc]
          print "  #{[pc,@program[pc]]}" if $DEBUG
        end
      when ?]
        if @d[dc] != 0
          pc = @jumpback_table[pc]
          print "  #{[pc,@program[pc]]}" if $DEBUG
        end
      end
      puts if $DEBUG
      pc += 1
    end
  end
end

# output 'Hello World!\n'
helloworld = <<PROGRAM
++++++++++[>+++++++>++++++++++>+++>+<<<<-]
>++.>+.+++++++..+++.>++.<<+++++++++++++++.>.+++.------.--------.>+.>.
PROGRAM
bf = RCBF.new(helloworld)
bf.run
 
# use nested loop to increment count to 64 and print (should be '@')
# followed by a newline 
RCBF.new('>>++++[<++++[<++++>-]>-]<<.[-]++++++++++.').run
Output:
Hello World!
@

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.

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;')