Repository navigation
Expand file tree
/
Copy pathbrainrubyck.rb
More file actions
157 lines (129 loc) · 3.03 KB
/
Copy pathbrainrubyck.rb
File metadata and controls
157 lines (129 loc) · 3.03 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
class BrainRubyck
# These are accessible to be modified after the object has been instantiated
attr_accessor :code, :logging, :dump_all
# These are only readable, for debugging purposes and whatnot
attr_reader :cursor, :memory, :out
def initialize(opts = {})
# The Brainfuck code
@code = opts[:code] || ""
# The cursor position
@cursor = 0
# The memory set
initial_memory = opts[:initial_memory] || 300
@memory = Array.new(initial_memory, 0)
# If true, logs every operation and dumps the memory at the end
@logging = opts[:logging] || opts[:log] || opts[:debug] || false
# If true, dumps the memory after every operation
@dump_all = opts[:dump_all] || false
# The Brainfuck commands
@commands = {
'+' => :plus,
'-' => :minus,
'>' => :forward,
'<' => :backward,
'[' => :begin_loop,
']' => :end_loop,
'.' => :output,
',' => :input
}
@loops = []
end
def parse!
# The char we're at in the @code string
@i = 0
# The output of the program
@out = ""
# Using while so we can manipulate the index
while @i < @code.length
cmd = @commands[@code[@i]]
if cmd.nil?
next_i
else
log(:before, cmd) if @logging
self.send(cmd)
log(:after, cmd) if @logging
self.dump if @dump_all
end
end
# Log the final state of memory at the end of the program
if @logging
puts "END OF PROGRAM"
self.dump
end
# Return the output
@out
end
# Debugging methods
def dump
puts "Memory size:#{@memory.length}"
puts "Data as bytes: #{@memory.join(' ')}"
puts "Data as chars: " + @memory.map {|b| b.chr}.join(' ')
@memory
end
private
def log (whn, cmd)
if whn == :before
print "Before command "
else
print "After command "
end
print "'#{cmd}' (#{@code[@i]}): i: #{@i}, cursor: #{@cursor}, byte: #{@memory[@cursor]}, char: #{@memory[@cursor].chr}, loops: #{@loops}\n"
end
# Brainfuck commands
def plus
@memory[@cursor] += 1
next_i
end
def minus
@memory[@cursor] -= 1
next_i
end
def forward
@cursor += 1
next_i
end
def backward
@cursor -= 1
next_i
end
def begin_loop
if @memory[@cursor] == 0
loop_count = 1
while loop_count > 0
next_i
case @commands[@code[@i]]
when :begin_loop
loop_count += 1
when :end_loop
loop_count -= 1
end
end
next_i
else
@loops.push(@i)
next_i
end
end
def end_loop
if @memory[@cursor] == 0
@loops.pop
next_i
else
@i = @loops.pop
end
end
def output
ch = @memory[@cursor].chr
print ch
@out << ch
next_i
end
def input
@memory[@cursor] = gets[0].ord
next_i
end
# Helpers
def next_i
@i += 1
end
end