Class: BrainFuck

Inherits:
Object
  • Object
show all
Defined in:
lib/brain_fuck.rb

Constant Summary collapse

DEFAULT_MEMORY_SIZE =
30_000
DEFAULT_EXEC_LIMIT =

Stop badly constructed scripts going forever

1_000_000
OPS =
{
  '+' => :increment,
  '-' => :decrement,
  '>' => :move_pointer_left,
  '<' => :move_pointer_right,
  ',' => :read_in,
  '.' => :print_out,
  '[' => :loop_start,
  ']' => :loop_end
}
DIALECTS =
{
  :ook => {
    'Ook. Ook.' => '+',
    'Ook! Ook!' => '-',
    'Ook. Ook?' => '>',
    'Ook? Ook.' => '<',
    'Ook! Ook?' => '[',
    'Ook? Ook!' => ']',
    'Ook! Ook.' => '.',
    'Ook. Ook!' => ','
  },
  :spoon => {
    1 => '+',
    0 => {
      0 => {
        0 => '-',
        1 => {
          0 => {
            0 => '[',
            1 => {
              0 => '.',
              1 => {
                0 => ','
              }
            }
          },
          1 => ']'
        }
      },
      1 => {
        0 => '>',
        1 => '<'
      }
    }
  }
}

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(program_input_stream, options = {}) ⇒ BrainFuck

Returns a new instance of BrainFuck.



60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
# File 'lib/brain_fuck.rb', line 60

def initialize(program_input_stream, options={})
  @debug               = options[:debug] || false
  @exec_limit          = options[:execution_limit] || DEFAULT_EXEC_LIMIT
  @execution_count     = 0

  @instruction_pointer = -1
  @memory_size         = options[:memory_size] || DEFAULT_MEMORY_SIZE
  @memory              = Array.new(@memory_size){ 0 }
  @data_pointer        = 0
  @pointer_stack       = []

  @input_stream        = options[:input_stream] || STDIN
  @output_stream       = options[:output_stream] || STDOUT

  @program             = get_program(program_input_stream)
  @program_end         = @program.size
end

Instance Attribute Details

#data_pointerObject

Returns the value of attribute data_pointer.



55
56
57
# File 'lib/brain_fuck.rb', line 55

def data_pointer
  @data_pointer
end

#instruction_pointerObject

Returns the value of attribute instruction_pointer.



55
56
57
# File 'lib/brain_fuck.rb', line 55

def instruction_pointer
  @instruction_pointer
end

#memoryObject

Returns the value of attribute memory.



55
56
57
# File 'lib/brain_fuck.rb', line 55

def memory
  @memory
end

#pointer_stackObject

Returns the value of attribute pointer_stack.



55
56
57
# File 'lib/brain_fuck.rb', line 55

def pointer_stack
  @pointer_stack
end

Class Method Details

.bf_to_ook(bf) ⇒ Object



147
148
149
150
151
152
153
154
155
156
# File 'lib/brain_fuck.rb', line 147

def self.bf_to_ook(bf)
  ook = ''
  ook_bf = DIALECTS[:ook].invert
  bf.each_char do |op|
    next unless op.match(/[\>\<\+\-\.,\[\]]/)
    ook << ook_bf[op]
    ook << ' '
  end
  ook
end

.ook_to_bf(ook) ⇒ Object



135
136
137
138
139
140
141
142
143
144
145
# File 'lib/brain_fuck.rb', line 135

def self.ook_to_bf(ook)
  bf = ''
  ook.scan(/(Ook[\.\?\!])\s*(Ook[\.\?\!])/) do |m|
    command = "#{m[0]} #{m[1]}"
    unless DIALECTS[:ook].include?(command)
      raise "Got confused, thought it was Ook!"
    end
    bf << DIALECTS[:ook][command]
  end
  bf
end

.spoon_to_bf(spoon) ⇒ Object



158
159
160
161
162
163
164
165
166
167
168
169
170
# File 'lib/brain_fuck.rb', line 158

def self.spoon_to_bf(spoon)
  src = spoon.gsub(/[^01]/, '')
  bf = ''
  current = DIALECTS[:spoon]
  spoon.each_char do |i|
    current = current[i.to_i]
    unless current.is_a?(Hash)
      bf << current
      current = DIALECTS[:spoon]
    end
  end
  bf
end

Instance Method Details

#decrementObject



89
90
91
# File 'lib/brain_fuck.rb', line 89

def decrement
  @memory[@data_pointer] -= 1
end

#dumpObject



192
193
194
195
196
197
198
199
# File 'lib/brain_fuck.rb', line 192

def dump
  puts
  puts "instruction_pointer = #{@instruction_pointer}"
  puts "data_pointer    = #{@data_pointer}"
  puts "memory@data_pointer = #{@memory[@data_pointer]}"
  puts "pointer_stack     = #{@pointer_stack.inspect}"
  puts
end

#ended?Boolean

Returns:

  • (Boolean)


187
188
189
190
# File 'lib/brain_fuck.rb', line 187

def ended?
  (@instruction_pointer >= @program_end or
   @execution_count >= @exec_limit)
end

#execute(op) ⇒ Object



78
79
80
81
82
83
# File 'lib/brain_fuck.rb', line 78

def execute(op)
  return unless OPS.has_key?(op)
  puts op if @debug
  send(OPS[op])
  @execution_count += 1
end

#incrementObject



85
86
87
# File 'lib/brain_fuck.rb', line 85

def increment
  @memory[@data_pointer] += 1
end

#loop_endObject



124
125
126
127
128
129
130
131
132
133
# File 'lib/brain_fuck.rb', line 124

def loop_end
  if @pointer_stack.empty?
    raise "Bracket mismatch"
  end
  if @memory[@data_pointer] == 0
    @pointer_stack.pop
  else
    @instruction_pointer = @pointer_stack.pop
  end
end

#loop_startObject



116
117
118
119
120
121
122
# File 'lib/brain_fuck.rb', line 116

def loop_start
  if @memory[@data_pointer] > 0
    @pointer_stack.push(@instruction_pointer-1)
  else
    @instruction_pointer = matching_brace_position(@instruction_pointer)
  end
end

#move_pointer_leftObject



101
102
103
104
105
106
# File 'lib/brain_fuck.rb', line 101

def move_pointer_left
  @data_pointer += 1
  if @data_pointer == @memory_size
    @data_pointer = 0
  end
end

#move_pointer_rightObject



108
109
110
111
112
113
114
# File 'lib/brain_fuck.rb', line 108

def move_pointer_right
  if @data_pointer > 0
    @data_pointer -= 1
  else
    @data_pointer = @memory_size - 1
  end
end

#next_instructionObject



182
183
184
185
# File 'lib/brain_fuck.rb', line 182

def next_instruction
  @instruction_pointer += 1
  @program[@instruction_pointer]
end


97
98
99
# File 'lib/brain_fuck.rb', line 97

def print_out
  @output_stream.putc @memory[@data_pointer]
end

#read_inObject



93
94
95
# File 'lib/brain_fuck.rb', line 93

def read_in
  @memory[@data_pointer] = @input_stream.getc.ord
end

#runObject



172
173
174
175
176
177
178
179
180
# File 'lib/brain_fuck.rb', line 172

def run
  while not ended? do
    dump if @debug
    op = next_instruction
    puts "op = #{op}" if @debug
    execute(op)
    dump if @debug
  end
end