Home Bobbity flop

Ruby BrainF*ck interpreter

This is an implementation of the BrainFuck language in Ruby.

In case you haven't come across Ruby before, it is an extremely well designed object oriented programming language, which has a number of interesting features - to learn more visit the Ruby home page.

Personally, I prefer ETA to BrainFuck, but I was wondering if you could translate between the two. In fact, I think it would be possible to write a BrainFuck to ETA converter without too much trouble, but going the other way would be enormously difficult - the divide instruction would be particularly tricky I think.

A converter from to ETA would need to represent the array on the stack - meaning that at the start of the program you would need to place 30,000 zeros there, so your program would begin with 60k of ne instructions. Unless you invented some clever way of extending the stack as required. Of course, strict ETA interpreters that only have a 100 byte stack don't stand a chance anyway, but let's not worry about that.

I wrote this interpreter as a step to inventing a translation program, and it's here in case anyone needs it for anything, unlikely as that may seem.

Source Code

***** Updated 16.5.2012

Alexandre Moutot wrote to me that my program did not work. And so it didn't - it was totally broken. So it only took 11 years for someone to notice. Anyway, I've fixed it now - this version should work ok.

***** Updated 26.10.2013

Alexandre Moutot again - this time providing a patch that allows you to print the character '\0', which was confused with EOF. Also adding some restrictions to enforce char sized values after increment or decrement. Thanks!

You can download the program here.

class Bf
  def initialize
    @a = [0] * 30000
    @b = []
    @p = 0
    @x = 0
  end

  def r
    @p += 1
  end

  def l
    @p -= 1
  end

  def i
    @a[@p] = (@a[@p] + 1) % 256
  end

  def d
    @a[@p] = (@a[@p] - 1) % 256
  end

  def o
    if @a[@p] == -1
      print 255.chr
    else
      print @a[@p].chr
    end
  end

  def n
    @a[@p] = $stdin.getc || -1
  end

  def j
    @x += 1
    if !$j
      if @a[@p] == 0
        $j = @x
      else
        @b[@x] = $i
      end
    end
  end

  def e
    if $j || @a[@p] == 0
      $j = false if $j == @x
      @x -= 1
    else
      $i = @b[@x]
    end
  end

  def b
    10.times {|a| print @a[a].chr}
  end
end

b = Bf.new
$i = 0
p = $<.readlines.join.tr('^><+\-.,[]#','').tr('><+\-.,[]#', 'rlidonjeb')
while $i < p.size
  c = p[$i].chr
  if !$j || c == "j" || c == "e"
    b.send(c)
  end
  $i += 1
end