Skip to content

Instantly share code, notes, and snippets.

@aisuii
Created July 7, 2011 08:45
Show Gist options
  • Save aisuii/1069116 to your computer and use it in GitHub Desktop.
Save aisuii/1069116 to your computer and use it in GitHub Desktop.
ruby de brainf*ck
# coding: utf-8
class Memory
def initialize(opts = {})
@memory = Hash.new{|h,k| h[k] = 0 }
@pointer = 0
@out = opts[:out] || $stdout
@in = opts[:in] || $stdin
end
def forward
@pointer += 1
end
def backward
@pointer -= 1
end
def inc
@memory[@pointer] += 1
end
def dec
@memory[@pointer] -= 1
end
def output
@out.write dump
end
def input
@memory[@pointer] = @in.read(1)
end
def raw
@memory[@pointer]
end
def dump
null? ? 0.chr : raw.chr
end
def null?
raw.nil? or raw.zero?
end
end
class Bf
class BfSyntaxError < StandardError; end
OP = {
'>' => :forward,
'<' => :backward,
'+' => :inc,
'-' => :dec,
'.' => :output,
',' => :input,
}
LOOP = {
:open => '[',
:close => ']'
}
def initialize(src, opts = {})
@src = src || ''
@out = opts[:out] || $stdout
@in = opts[:in] || $stdin
@memory = Memory.new(:out => @out, :in => @in)
@pointer = 0
@stack = []
@code = @src.chars.to_a
raise BfSyntaxError unless syntax_valid?
end
def run
while cmd = read!
if op = OP[cmd]
@memory.__send__ op
elsif loop_open? cmd
if @memory.null?
proceed_to_close
else
@stack.push(@pointer - 1)
end
elsif loop_close? cmd
unless @memory.null?
@pointer = @stack.pop
end
end
end
end
private
def read!
cmd = read
@pointer += 1
cmd
end
def read
@code[@pointer]
end
def proceed_to_close
while true
break if loop_close?(read!)
end
end
def loop_open?(cmd)
LOOP[:open] == cmd
end
def loop_close?(cmd)
LOOP[:close] == cmd
end
def syntax_valid?
stack = []
@code.each do |char|
if loop_open?(char)
stack.push(true)
elsif loop_close?(char)
return false unless stack.pop
end
end
stack.empty?
end
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment