Skip to content

Instantly share code, notes, and snippets.

@aisuii
Created July 20, 2011 14:48
Show Gist options
  • Save aisuii/1095099 to your computer and use it in GitHub Desktop.
Save aisuii/1095099 to your computer and use it in GitHub Desktop.
# coding: utf-8
class Brainfuck
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 increment
@memory[@pointer] += 1
end
def decrement
@memory[@pointer] -= 1
end
def output
@out.write dump
end
def input
@memory[@pointer] = @in.read(1)
end
def noop
# noop
end
def raw
@memory[@pointer]
end
def dump
raw.chr
end
def null?
raw.zero?
end
end
class Parser
class ParseError < StandardError; end
OPERATOR = {
'>' => :forward,
'<' => :backward,
'+' => :increment,
'-' => :decrement,
'.' => :output,
',' => :input,
'[' => :open,
']' => :close
}
def initialize(src)
@code = parse(src)
@pointer = 0
end
def read(null_flag = false)
cmd = @code[@pointer]
return nil if cmd.nil?
if cmd.is_a? Symbol
@pointer += 1
cmd
else
if cmd.first == :open
@pointer = cmd[1] if null_flag
elsif cmd.first == :close
@pointer = cmd[1] unless null_flag
end
@pointer += 1
:noop
end
end
private
def parse(src)
code = src.chars.map(&method(:operatorize))
code.compact!
stack = []
code.dup.each_with_index do |op, idx|
case op
when :open
stack.push(idx)
when :close
if open_idx = stack.pop
code[idx] = [:close, open_idx]
code[open_idx] = [:open, idx]
end
end
end
raise ParseError unless stack.empty?
code
end
def operatorize(chr)
OPERATOR[chr]
end
end
def initialize(src, opts = {})
@out = opts[:out] || $stdout
@in = opts[:in] || $stdin
@memory = Memory.new(:out => @out, :in => @in)
@code = Parser.new(src || '')
end
def run
while memory_operator = @code.read(@memory.null?)
@memory.__send__ memory_operator
end
end
end
if $0 == __FILE__
src = "Hello +++++++++[>++++++++>+++++++++++>+++++<<<-]>.>++.+++++++..++
+.>-.------------.<++++++++.--------.+++.------.--------.>+. world!"
Brainfuck.new(src).run
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment