Brainfuck Language Specification

This is a quote from Wikipedia.

The interpreter consists of the following elements: a Brainfuck program, an instruction pointer (pointing to a character in the program), an array of at least 30000 bytes (each element initialized to zero), a data pointer (pointing to one of the elements in the array, initialized to point to the leftmost element), and two byte streams for input and output. A Brainfuck program consists of 8 executable instructions (other characters are ignored and skipped):

  • Increment the pointer. Equivalent to C’s “ptr++;”.

  • < Decrement the pointer. Equivalent to C’s “ptr–;”.
    • Increment the value at the pointer. Equivalent to C’s “(*ptr)++;”.
    • Decrement the value at the pointer. Equivalent to C’s “(*ptr)–;”.
  • . Output the value at the pointer. Equivalent to C’s “putchar(*ptr);”.
  • , Read one byte from input and assign it to the pointer. Equivalent to C’s “*ptr=getchar();”.
  • [ If the value at the pointer is 0, jump to the instruction after the corresponding ]. Equivalent to C’s “while(*ptr){”.
  • ] If the value at the pointer is not 0, jump to the corresponding [ (right after it[1]). Equivalent to C’s “}"[2].

Implementation

I used Ruby. The “[” and “]” parts are still difficult.

#!/usr/bin/env ruby

class BrainFuck
  def set(program)
    @pc = 0                         # Program pointer   
    @pro = program                  # Program
    @mar = 0                        # Memory address register
    @mem = Array.new(30000,0)       # Memory (30000 Bytes)
  end

  def step()
    # Fetch opcode
    op = @pro[@pc]
    @pc+=1

    # Execute
    case op
    when ">"
      @mar+=1
    when "<"
      @mar-=1
    when "+"
      @mem[@mar]+=1
    when "-"
      @mem[@mar]-=1
    when "."
      print @mem[@mar].chr
    when "["
      if @mem[@mar] == 0
        depth = 0  
        (@pc..@pro.length).each do |i|
          # Found matching bracket
          if depth == 0 && @pro[i] == "]"
            @pc = i+1
            break
          # Check depth
          elsif @pro[i] == "["
            depth+=1
          elsif @pro[i] == "]"
            depth-=1
          end
        end
      end
    when "]"
      if @mem[@mar]!=0
        depth = 0
        (0..@pc-2).reverse_each do |i|
          # Found matching bracket
          if depth == 0 && @pro[i] == "["  
            @pc = i+1
            break
          # Check depth
          elsif @pro[i] == "]"
            depth+=1
          elsif @pro[i] == "["
            depth-=1
          end
        end
      end
    end
  end

  def exec()
    while @pc!=@pro.length 
      step 
    end
    print "\n"
  end
end


brainfuck = BrainFuck.new

while line = gets
  brainfuck.set(line)
  brainfuck.exec
end

Test

This is Brainfuck programming in action. Please add execution permissions before playing. Also, since it reads line by line, it’s bad if there are newline codes in the brainfuck code.

$ ./brainfuck.rb
+++++++++[>++++++++>+++++++++++>+++++<<<-]>.>++.+++++++..+++.>-.------------.<++++++++.--------.+++.------.--------.>+.
Hello, world!
++++++++++[>++++++++++>+++++++++++>++++++++++++>++++++++++>++++++++++>+++++++++++<<<<<<-]>--.>+.<.>>---.>++++.>+++++.>++++.<<<<.
bobuhiro