rbfk 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,20 @@
1
+ Copyright (c) 2012 Sean McCarthy
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
@@ -0,0 +1,43 @@
1
+ == Brainfuck, in Ruby.
2
+
3
+ See http://en.wikipedia.org/wiki/Brainfuck
4
+
5
+ == Usage
6
+
7
+ rbfk.rb <brainfuck source file>
8
+
9
+ OR
10
+
11
+ echo '++++++[>++++++++++<-]+++++.' | rbfk.rb
12
+
13
+ although piping in a script this way that uses the "," operation won't work,
14
+ since the "," operation reads from STDIN.
15
+
16
+ Also supports Ook![http://esolangs.org/wiki/Ook!] and Spoon[http://esolangs.org/wiki/Spoon] scripts.
17
+
18
+ You can use the BrainFuck class in your own programs (why?) like so:
19
+
20
+ require 'brain_fuck'
21
+
22
+ program = File.open('test.bf', 'r')
23
+ #
24
+ # OR any IO stream, e.g.
25
+ # program = StringIO.new('++++++[>++++++++++<-]+++++.')
26
+ #
27
+ bf = BrainFuck.new(program)
28
+ bf.run
29
+
30
+ === Options
31
+
32
+ options = { :memory_size => 50_000 }
33
+ bf = BrainFuck.new(program, options)
34
+ bf.run
35
+
36
+ Where options is a hash with one or more of the following options:
37
+
38
+ [:debug] will emit debugging information to STDOUT
39
+ [:execution_limit] the maximum operations to execute (including repetition in loops) before forced termination (to prevent runaway scripts). Defaults to 1,000,000.
40
+ [:memory_size] the size of the "tape" (the array) size used for the BrainFuck machine's memory. Defaults to 30,000.
41
+ [:input_stream] the IO stream from which the "," operation reads
42
+ [:output_stream] the IO stream to which the "." operation will write
43
+
@@ -0,0 +1,39 @@
1
+ # encoding: utf-8
2
+
3
+ require 'rubygems'
4
+ require 'rake'
5
+
6
+ require 'jeweler'
7
+ Jeweler::Tasks.new do |gem|
8
+ # gem is a Gem::Specification... see http://docs.rubygems.org/read/chapter/20 for more options
9
+ gem.name = "rbfk"
10
+ gem.homepage = "http://github.com/seandmccarthy/rbfk"
11
+ gem.license = "MIT"
12
+ gem.summary = %Q{BrainFuck interpreter}
13
+ gem.description = %Q{An interpreter for BrainFuck that also be embedded in your programs}
14
+ gem.email = "sean@clanmcccarthy.net"
15
+ gem.authors = ["Sean McCarthy"]
16
+ gem.add_development_dependency "rspec", "~> 2.8.0"
17
+ gem.add_development_dependency "rdoc", "~> 3.12"
18
+ gem.add_development_dependency "bundler", "~> 1.0.0"
19
+ gem.add_development_dependency "jeweler", "~> 1.8.3"
20
+ end
21
+ Jeweler::RubygemsDotOrgTasks.new
22
+
23
+ require 'rspec/core'
24
+ require 'rspec/core/rake_task'
25
+ RSpec::Core::RakeTask.new(:spec) do |spec|
26
+ spec.pattern = FileList['spec/**/*_spec.rb']
27
+ end
28
+
29
+ task :default => :spec
30
+
31
+ require 'rdoc/task'
32
+ Rake::RDocTask.new do |rdoc|
33
+ version = File.exist?('VERSION') ? File.read('VERSION') : ""
34
+
35
+ rdoc.rdoc_dir = 'rdoc'
36
+ rdoc.title = "rbfk #{version}"
37
+ rdoc.rdoc_files.include('README*')
38
+ rdoc.rdoc_files.include('lib/**/*.rb')
39
+ end
data/VERSION ADDED
@@ -0,0 +1 @@
1
+ 1.0.0
@@ -0,0 +1,5 @@
1
+ #!/usr/bin/env ruby
2
+ require File.expand_path(File.join('..', '..', 'lib', 'BrainFuck'), __FILE__)
3
+
4
+ src = ARGF.read
5
+ puts BrainFuck.bf_to_ook(src)
@@ -0,0 +1,5 @@
1
+ #!/usr/bin/env ruby
2
+ require File.expand_path(File.join('..', '..', 'lib', 'BrainFuck'), __FILE__)
3
+
4
+ bf = BrainFuck.new(ARGF)
5
+ bf.run
@@ -0,0 +1,228 @@
1
+ #!/usr/bin/env ruby -w
2
+
3
+ class BrainFuck
4
+ DEFAULT_MEMORY_SIZE = 30_000
5
+ DEFAULT_EXEC_LIMIT = 1_000_000 # Stop badly constructed scripts going forever
6
+
7
+ OPS = {
8
+ '+' => :increment,
9
+ '-' => :decrement,
10
+ '>' => :move_pointer_left,
11
+ '<' => :move_pointer_right,
12
+ ',' => :read_in,
13
+ '.' => :print_out,
14
+ '[' => :loop_start,
15
+ ']' => :loop_end
16
+ }
17
+
18
+ DIALECTS = {
19
+ :ook => {
20
+ 'Ook. Ook.' => '+',
21
+ 'Ook! Ook!' => '-',
22
+ 'Ook. Ook?' => '>',
23
+ 'Ook? Ook.' => '<',
24
+ 'Ook! Ook?' => '[',
25
+ 'Ook? Ook!' => ']',
26
+ 'Ook! Ook.' => '.',
27
+ 'Ook. Ook!' => ','
28
+ },
29
+ :spoon => {
30
+ 1 => '+',
31
+ 0 => {
32
+ 0 => {
33
+ 0 => '-',
34
+ 1 => {
35
+ 0 => {
36
+ 0 => '[',
37
+ 1 => {
38
+ 0 => '.',
39
+ 1 => {
40
+ 0 => ','
41
+ }
42
+ }
43
+ },
44
+ 1 => ']'
45
+ }
46
+ },
47
+ 1 => {
48
+ 0 => '>',
49
+ 1 => '<'
50
+ }
51
+ }
52
+ }
53
+ }
54
+
55
+ attr_accessor :memory,
56
+ :data_pointer,
57
+ :instruction_pointer,
58
+ :pointer_stack
59
+
60
+ def initialize(program_input_stream, options={})
61
+ @debug = options[:debug] || false
62
+ @exec_limit = options[:execution_limit] || DEFAULT_EXEC_LIMIT
63
+ @execution_count = 0
64
+
65
+ @instruction_pointer = -1
66
+ @memory_size = options[:memory_size] || DEFAULT_MEMORY_SIZE
67
+ @memory = Array.new(@memory_size){ 0 }
68
+ @data_pointer = 0
69
+ @pointer_stack = []
70
+
71
+ @input_stream = options[:input_stream] || STDIN
72
+ @output_stream = options[:output_stream] || STDOUT
73
+
74
+ @program = get_program(program_input_stream)
75
+ @program_end = @program.size
76
+ end
77
+
78
+ def execute(op)
79
+ return unless OPS.has_key?(op)
80
+ puts op if @debug
81
+ send(OPS[op])
82
+ @execution_count += 1
83
+ end
84
+
85
+ def increment
86
+ @memory[@data_pointer] += 1
87
+ end
88
+
89
+ def decrement
90
+ @memory[@data_pointer] -= 1
91
+ end
92
+
93
+ def read_in
94
+ @memory[@data_pointer] = @input_stream.getc.ord
95
+ end
96
+
97
+ def print_out
98
+ @output_stream.putc @memory[@data_pointer]
99
+ end
100
+
101
+ def move_pointer_left
102
+ @data_pointer += 1
103
+ if @data_pointer == @memory_size
104
+ @data_pointer = 0
105
+ end
106
+ end
107
+
108
+ def move_pointer_right
109
+ if @data_pointer > 0
110
+ @data_pointer -= 1
111
+ else
112
+ @data_pointer = @memory_size - 1
113
+ end
114
+ end
115
+
116
+ def loop_start
117
+ if @memory[@data_pointer] > 0
118
+ @pointer_stack.push(@instruction_pointer-1)
119
+ else
120
+ @instruction_pointer = matching_brace_position(@instruction_pointer)
121
+ end
122
+ end
123
+
124
+ def loop_end
125
+ if @pointer_stack.empty?
126
+ raise "Bracket mismatch"
127
+ end
128
+ if @memory[@data_pointer] == 0
129
+ @pointer_stack.pop
130
+ else
131
+ @instruction_pointer = @pointer_stack.pop
132
+ end
133
+ end
134
+
135
+ def self.ook_to_bf(ook)
136
+ bf = ''
137
+ ook.scan(/(Ook[\.\?\!])\s*(Ook[\.\?\!])/) do |m|
138
+ command = "#{m[0]} #{m[1]}"
139
+ unless DIALECTS[:ook].include?(command)
140
+ raise "Got confused, thought it was Ook!"
141
+ end
142
+ bf << DIALECTS[:ook][command]
143
+ end
144
+ bf
145
+ end
146
+
147
+ def self.bf_to_ook(bf)
148
+ ook = ''
149
+ ook_bf = DIALECTS[:ook].invert
150
+ bf.each_char do |op|
151
+ next unless op.match(/[\>\<\+\-\.,\[\]]/)
152
+ ook << ook_bf[op]
153
+ ook << ' '
154
+ end
155
+ ook
156
+ end
157
+
158
+ def self.spoon_to_bf(spoon)
159
+ src = spoon.gsub(/[^01]/, '')
160
+ bf = ''
161
+ current = DIALECTS[:spoon]
162
+ spoon.each_char do |i|
163
+ current = current[i.to_i]
164
+ unless current.is_a?(Hash)
165
+ bf << current
166
+ current = DIALECTS[:spoon]
167
+ end
168
+ end
169
+ bf
170
+ end
171
+
172
+ def run
173
+ while not ended? do
174
+ dump if @debug
175
+ op = next_instruction
176
+ puts "op = #{op}" if @debug
177
+ execute(op)
178
+ dump if @debug
179
+ end
180
+ end
181
+
182
+ def next_instruction
183
+ @instruction_pointer += 1
184
+ @program[@instruction_pointer]
185
+ end
186
+
187
+ def ended?
188
+ (@instruction_pointer >= @program_end or
189
+ @execution_count >= @exec_limit)
190
+ end
191
+
192
+ def dump
193
+ puts
194
+ puts "instruction_pointer = #{@instruction_pointer}"
195
+ puts "data_pointer = #{@data_pointer}"
196
+ puts "memory@data_pointer = #{@memory[@data_pointer]}"
197
+ puts "pointer_stack = #{@pointer_stack.inspect}"
198
+ puts
199
+ end
200
+
201
+ private
202
+
203
+ def get_program(program_input_stream)
204
+ src = program_input_stream.read
205
+ if src.match(/(Ook[\.\?\!]\s*){2}/) # Probably Ook
206
+ src = src.gsub(/[\r\n]/, ' ')
207
+ program = BrainFuck.ook_to_bf(src)
208
+ elsif src.match(/^[01]+\s*$/m) # Probably Spoon
209
+ program = BrainFuck.spoon_to_bf(src)
210
+ else
211
+ program = src.gsub(/[^\>\<\+\-\.,\[\]]/, '')
212
+ end
213
+ program
214
+ end
215
+
216
+ def matching_brace_position(pointer)
217
+ begin
218
+ pointer += 1
219
+ raise "Bracket mismatch" if pointer >= @program_end
220
+ if @program[pointer] == '['
221
+ pointer = matching_brace_position(pointer) + 1
222
+ end
223
+ end until @program[pointer] == ']'
224
+ pointer
225
+ end
226
+
227
+ end
228
+
@@ -0,0 +1,67 @@
1
+ # Generated by jeweler
2
+ # DO NOT EDIT THIS FILE DIRECTLY
3
+ # Instead, edit Jeweler::Tasks in Rakefile, and run 'rake gemspec'
4
+ # -*- encoding: utf-8 -*-
5
+
6
+ Gem::Specification.new do |s|
7
+ s.name = %q{rbfk}
8
+ s.version = "1.0.0"
9
+
10
+ s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
11
+ s.authors = [%q{Sean McCarthy}]
12
+ s.date = %q{2012-07-06}
13
+ s.description = %q{An interpreter for BrainFuck that also be embedded in your programs}
14
+ s.email = %q{sean@clanmcccarthy.net}
15
+ s.executables = [%q{bf2ook}, %q{rbfk}]
16
+ s.extra_rdoc_files = [
17
+ "LICENSE.txt",
18
+ "README.rdoc"
19
+ ]
20
+ s.files = [
21
+ "LICENSE.txt",
22
+ "README.rdoc",
23
+ "Rakefile",
24
+ "VERSION",
25
+ "bin/bf2ook",
26
+ "bin/rbfk",
27
+ "lib/brain_fuck.rb",
28
+ "rbfk.gemspec",
29
+ "samples/a.bf",
30
+ "samples/get_put.bf",
31
+ "samples/hello_world.bf",
32
+ "samples/hello_world.ook",
33
+ "samples/hello_world.spoon",
34
+ "samples/nested_iteration.bf",
35
+ "samples/quine.bf",
36
+ "samples/rot13.bf",
37
+ "samples/text2bf.bf",
38
+ "spec/brainfuck_spec.rb"
39
+ ]
40
+ s.homepage = %q{http://github.com/seandmccarthy/rbfk}
41
+ s.licenses = [%q{MIT}]
42
+ s.require_paths = [%q{lib}]
43
+ s.rubygems_version = %q{1.8.5}
44
+ s.summary = %q{BrainFuck interpreter}
45
+
46
+ if s.respond_to? :specification_version then
47
+ s.specification_version = 3
48
+
49
+ if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then
50
+ s.add_development_dependency(%q<rspec>, ["~> 2.8.0"])
51
+ s.add_development_dependency(%q<rdoc>, ["~> 3.12"])
52
+ s.add_development_dependency(%q<bundler>, ["~> 1.0.0"])
53
+ s.add_development_dependency(%q<jeweler>, ["~> 1.8.3"])
54
+ else
55
+ s.add_dependency(%q<rspec>, ["~> 2.8.0"])
56
+ s.add_dependency(%q<rdoc>, ["~> 3.12"])
57
+ s.add_dependency(%q<bundler>, ["~> 1.0.0"])
58
+ s.add_dependency(%q<jeweler>, ["~> 1.8.3"])
59
+ end
60
+ else
61
+ s.add_dependency(%q<rspec>, ["~> 2.8.0"])
62
+ s.add_dependency(%q<rdoc>, ["~> 3.12"])
63
+ s.add_dependency(%q<bundler>, ["~> 1.0.0"])
64
+ s.add_dependency(%q<jeweler>, ["~> 1.8.3"])
65
+ end
66
+ end
67
+
@@ -0,0 +1 @@
1
+ ++++++[>++++++++++<-]>+++++.>++++++++++.
@@ -0,0 +1 @@
1
+ ,.>++++++++++.
@@ -0,0 +1,21 @@
1
+ +++++ +++++ initialize counter (cell #0) to 10
2
+ [ use loop to set the next four cells to 70/100/30/10
3
+ > +++++ ++ add 7 to cell #1
4
+ > +++++ +++++ add 10 to cell #2
5
+ > +++ add 3 to cell #3
6
+ > + add 1 to cell #4
7
+ <<<< - decrement counter (cell #0)
8
+ ]
9
+ > ++ . print 'H'
10
+ > + . print 'e'
11
+ +++++ ++ . print 'l'
12
+ . print 'l'
13
+ +++ . print 'o'
14
+ > ++ . print ' '
15
+ << +++++ +++++ +++++ . print 'W'
16
+ > . print 'o'
17
+ +++ . print 'r'
18
+ ----- - . print 'l'
19
+ ----- --- . print 'd'
20
+ > + . print '!'
21
+ > . print '\n'
@@ -0,0 +1,20 @@
1
+ Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook! Ook? Ook. Ook?
2
+ Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook.
3
+ Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook? Ook. Ook! Ook! Ook? Ook! Ook. Ook?
4
+ Ook! Ook. Ook. Ook? Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook.
5
+ Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook! Ook? Ook. Ook? Ook. Ook. Ook. Ook.
6
+ Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook.
7
+ Ook? Ook. Ook! Ook! Ook? Ook! Ook. Ook? Ook. Ook. Ook! Ook. Ook. Ook. Ook. Ook.
8
+ Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook! Ook. Ook! Ook. Ook. Ook.
9
+ Ook. Ook. Ook. Ook. Ook! Ook. Ook. Ook? Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook.
10
+ Ook! Ook? Ook. Ook? Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook.
11
+ Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook? Ook. Ook! Ook! Ook? Ook!
12
+ Ook. Ook? Ook! Ook. Ook? Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook! Ook? Ook. Ook?
13
+ Ook! Ook! Ook! Ook! Ook! Ook! Ook! Ook! Ook? Ook. Ook! Ook! Ook? Ook! Ook. Ook?
14
+ Ook! Ook. Ook? Ook. Ook? Ook. Ook? Ook. Ook? Ook. Ook? Ook. Ook. Ook. Ook. Ook.
15
+ Ook. Ook. Ook! Ook? Ook. Ook? Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook.
16
+ Ook? Ook. Ook! Ook! Ook? Ook! Ook. Ook? Ook! Ook. Ook. Ook? Ook. Ook? Ook! Ook.
17
+ Ook. Ook. Ook. Ook. Ook. Ook. Ook! Ook. Ook! Ook! Ook! Ook! Ook! Ook! Ook! Ook!
18
+ Ook! Ook! Ook! Ook! Ook! Ook. Ook! Ook! Ook! Ook! Ook! Ook! Ook! Ook! Ook! Ook!
19
+ Ook! Ook! Ook! Ook! Ook! Ook! Ook! Ook. Ook. Ook? Ook. Ook? Ook. Ook. Ook! Ook.
20
+ Ook. Ook? Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook! Ook.
@@ -0,0 +1,2 @@
1
+ 11111100100010111111111111011000001101000101001011111111110010001011111111110110000011010100101011111110010100010101110010100101111001000101111111111101100000110100010100111110010001000000000000001100000110100010100110110110110111110010001011111011000001101000101001001000101011100101000000000000000000000101000000000000000000000000000101001001010010100101111111111001010
2
+
@@ -0,0 +1 @@
1
+ ++[>+++++[>++++++<-]<-]>>+++++.>++++++++++.
@@ -0,0 +1 @@
1
+ >>>++++>+>+>+>+>+>+>+>+>+++++>++++>+>+>+>+>+>+>+>+>+++>++>++++++>++++>++>++>+++++++>+++++++>+++>+++>+++++>+++>++++++>++++>+++++>+++>+>+>+>+>+>+>+>+>+++++>+++>+>+>+>+>+>+>+>+>++++>++>++++++>+++>++>++>+++++++>+>++++>+>+>+>+>+++++>+++>++>++>++>++>++>++++>++>++++++>++++>+++++>+++>+++>+++++++>++++>+>++++>++>++++++>+++>++>+++++>++>+++>+>+>++++>+++++>++>+++>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>++++>+++++>++>+++>+>+>++++>+++++>++>+++>++>++++>++++>+>+>+>+>+>+++++>+++>+++>+>+>+>+>+>+>++++>++++>++>++++++>+++>+++++>++>+++>+>+>++++>+++++>++>+++>+>++++>++++>+>+>+>+>+>+>+++++>+++>+++>++>++>++>++>++>++>++>++>++++>++++>++>++++++>+++>++++++>++++++>++++++>++++++>++++++>++++++>++++>++++>++++++>+++>+++>+++>+++++>+++>++++++>++++>+++++>+++++++>++++>++++++>++++++++[>++++++++<-]>--..<<[<]>[<++++++++[<++++++++>-]<--.+>++++[<----->-]>[<<.>+>-]<-[-<++>[-<+++++++++++++++>[-<++>[-<->>+++++[<<++++++>>-]<[-<++>[-<+>>++++++[<<-------->>-]<]]]]]]>>]<<<[<]>[.>]
@@ -0,0 +1,42 @@
1
+ -,+[ Read first character and start outer character
2
+ reading loop
3
+ -[ Skip forward if character is 0
4
+ >>++++[>++++++++<-] Set up divisor (32) for division loop
5
+ (MEMORY LAYOUT: dividend copy remainder divisor
6
+ quotient zero zero)
7
+ <+<-[ Set up dividend (x minus 1) and enter division loop
8
+ >+>+>-[>>>] Increase copy and remainder / reduce divisor /
9
+ Normal case: skip forward
10
+ <[[>+<-]>>+>] Special case: move remainder back to divisor and
11
+ increase quotient
12
+ <<<<<- Decrement dividend
13
+ ] End division loop
14
+ ]>>>[-]+ End skip loop; zero former divisor and reuse space
15
+ for a flag
16
+ >--[-[<->+++[-]]]<[ Zero that flag unless quotient was 2 or 3;
17
+ zero quotient; check flag
18
+ ++++++++++++<[ If flag then set up divisor (13) for second
19
+ division loop
20
+ (MEMORY LAYOUT: zero copy dividend divisor
21
+ remainder quotient zero zero)
22
+ >-[>+>>] Reduce divisor; Normal case: increase remainder
23
+ >[+[<+>-]>+>>] Special case: increase remainder / move it back to
24
+ divisor / increase quotient
25
+ <<<<<- Decrease dividend
26
+ ] End division loop
27
+ >>[<+>-] Add remainder back to divisor to get a useful 13
28
+ >[ Skip forward if quotient was 0
29
+ -[ Decrement quotient and skip forward if quotient
30
+ was 1
31
+ -<<[-]>> Zero quotient and divisor if quotient was 2
32
+ ]<<[<<->>-]>> Zero divisor and subtract 13 from copy if quotient
33
+ was 1
34
+ ]<<[<<+>>-] Zero divisor and add 13 to copy if quotient was 0
35
+ ] End outer skip loop (jump to here if
36
+ ((character minus 1)/32) was not 2 or 3)
37
+ <[-] Clear remainder from first division if second
38
+ division was skipped
39
+ <.[-] Output ROT13ed character from copy and clear it
40
+ <-,+ Read next character
41
+ ] End character reading loop
42
+
@@ -0,0 +1 @@
1
+ ,[>>++++++[-<+++++++>]<+<[->.<]>+++.<++++[->++++<]>.>,]
@@ -0,0 +1,127 @@
1
+ require File.expand_path(File.join('..', '..', 'lib', 'brain_fuck'), __FILE__)
2
+
3
+ describe BrainFuck do
4
+ describe "The Brain Fuck instruction set" do
5
+ before :each do
6
+ @bf = BrainFuck.new(StringIO.new(''))
7
+ end
8
+
9
+ it "should increment the value at the current memory location" do
10
+ @bf.execute('+')
11
+ @bf.memory[0].should == 1
12
+ end
13
+
14
+ it "should decrement the value at the current memory location" do
15
+ @bf.execute('-')
16
+ @bf.memory[0].should == -1
17
+ end
18
+
19
+ it "should increment the data pointer" do
20
+ @bf.execute('>')
21
+ @bf.data_pointer.should == 1
22
+ end
23
+
24
+ it "should decrement the data pointer" do
25
+ @bf.execute('>')
26
+ @bf.data_pointer.should == 1
27
+ @bf.execute('<')
28
+ @bf.data_pointer.should == 0
29
+ end
30
+
31
+ it "should read a char into the current memory location" do
32
+ STDIN.should_receive(:getc).and_return('A')
33
+ @bf.execute(',')
34
+ @bf.memory[0].should == 65
35
+ end
36
+
37
+ it "output the value at the current memory location" do
38
+ @bf.memory[0] = 65
39
+ STDOUT.should_receive(:putc).with(65)
40
+ @bf.execute('.')
41
+ end
42
+
43
+ describe "loops" do
44
+ it "should begin a loop when the current memory value is > 0" do
45
+ @bf.execute('+')
46
+ @bf.execute('[')
47
+ @bf.pointer_stack.should_not be_empty
48
+ end
49
+
50
+ it "should skip the loop when the current memory value is = 0" do
51
+ @bf.should_receive(:matching_brace_position).and_return(1)
52
+ @bf.execute('[')
53
+ @bf.pointer_stack.should == []
54
+ @bf.instruction_pointer.should == 1
55
+ end
56
+
57
+ it "should begin a new iteration when the current memory value is > 0" do
58
+
59
+ # Increment current memory position
60
+ @bf.execute('+')
61
+
62
+ # Start loop
63
+ @bf.instruction_pointer = 1
64
+ @bf.execute('[')
65
+
66
+ # The pointer stack should have (instruction_pointer - 1) pushed on
67
+ @bf.pointer_stack.should == [0]
68
+
69
+ # End of loop, should see memory position > zero, then
70
+ # - pop the last value from pointer_stack
71
+ # - instruction_pointer should be set to this value
72
+ @bf.execute(']')
73
+ @bf.pointer_stack.should == []
74
+ @bf.instruction_pointer.should == 0
75
+ end
76
+
77
+ it "should finish iterating when the current memory value is = 0" do
78
+
79
+ # Increment current memory position
80
+ @bf.execute('+')
81
+
82
+ # Start loop
83
+ @bf.instruction_pointer = 1
84
+ @bf.execute('[')
85
+
86
+ # The pointer stack should have (instruction_pointer - 1) pushed on
87
+ @bf.pointer_stack.should == [0]
88
+
89
+ # Decrement current memory position, making it zero
90
+ @bf.execute('-')
91
+
92
+ # End of loop, should notice memory position is zero, then
93
+ # - pop the last value from pointer_stack
94
+ # - instruction_pointer should (remain) at index for ']' in @program
95
+ @bf.instruction_pointer = 3
96
+ @bf.execute(']')
97
+ @bf.pointer_stack.should == []
98
+ @bf.instruction_pointer.should == 3
99
+ end
100
+
101
+ it "should permit nested loops" do
102
+ pending
103
+ end
104
+
105
+ it "should raise an exception for mismatched braces" do
106
+ lambda { @bf.execute(']') }.should raise_error
107
+ end
108
+ end
109
+
110
+ end
111
+
112
+ describe "running programs" do
113
+ it "should indicate when a program execution should end" do
114
+ @bf = BrainFuck.new(StringIO.new(''))
115
+ @bf.ended?.should be_false
116
+ @bf.next_instruction
117
+ @bf.ended?.should be_true
118
+ end
119
+ end
120
+
121
+ describe "Translating and executing other dialects" do
122
+ pending
123
+ #self.ook_to_bf(ook)
124
+ #self.bf_to_ook(bf)
125
+ #self.spoon_to_bf(spoon)
126
+ end
127
+ end
metadata ADDED
@@ -0,0 +1,116 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: rbfk
3
+ version: !ruby/object:Gem::Version
4
+ prerelease:
5
+ version: 1.0.0
6
+ platform: ruby
7
+ authors:
8
+ - Sean McCarthy
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+
13
+ date: 2012-07-06 00:00:00 Z
14
+ dependencies:
15
+ - !ruby/object:Gem::Dependency
16
+ name: rspec
17
+ prerelease: false
18
+ requirement: &id001 !ruby/object:Gem::Requirement
19
+ none: false
20
+ requirements:
21
+ - - ~>
22
+ - !ruby/object:Gem::Version
23
+ version: 2.8.0
24
+ type: :development
25
+ version_requirements: *id001
26
+ - !ruby/object:Gem::Dependency
27
+ name: rdoc
28
+ prerelease: false
29
+ requirement: &id002 !ruby/object:Gem::Requirement
30
+ none: false
31
+ requirements:
32
+ - - ~>
33
+ - !ruby/object:Gem::Version
34
+ version: "3.12"
35
+ type: :development
36
+ version_requirements: *id002
37
+ - !ruby/object:Gem::Dependency
38
+ name: bundler
39
+ prerelease: false
40
+ requirement: &id003 !ruby/object:Gem::Requirement
41
+ none: false
42
+ requirements:
43
+ - - ~>
44
+ - !ruby/object:Gem::Version
45
+ version: 1.0.0
46
+ type: :development
47
+ version_requirements: *id003
48
+ - !ruby/object:Gem::Dependency
49
+ name: jeweler
50
+ prerelease: false
51
+ requirement: &id004 !ruby/object:Gem::Requirement
52
+ none: false
53
+ requirements:
54
+ - - ~>
55
+ - !ruby/object:Gem::Version
56
+ version: 1.8.3
57
+ type: :development
58
+ version_requirements: *id004
59
+ description: An interpreter for BrainFuck that also be embedded in your programs
60
+ email: sean@clanmcccarthy.net
61
+ executables:
62
+ - bf2ook
63
+ - rbfk
64
+ extensions: []
65
+
66
+ extra_rdoc_files:
67
+ - LICENSE.txt
68
+ - README.rdoc
69
+ files:
70
+ - LICENSE.txt
71
+ - README.rdoc
72
+ - Rakefile
73
+ - VERSION
74
+ - bin/bf2ook
75
+ - bin/rbfk
76
+ - lib/brain_fuck.rb
77
+ - rbfk.gemspec
78
+ - samples/a.bf
79
+ - samples/get_put.bf
80
+ - samples/hello_world.bf
81
+ - samples/hello_world.ook
82
+ - samples/hello_world.spoon
83
+ - samples/nested_iteration.bf
84
+ - samples/quine.bf
85
+ - samples/rot13.bf
86
+ - samples/text2bf.bf
87
+ - spec/brainfuck_spec.rb
88
+ homepage: http://github.com/seandmccarthy/rbfk
89
+ licenses:
90
+ - MIT
91
+ post_install_message:
92
+ rdoc_options: []
93
+
94
+ require_paths:
95
+ - lib
96
+ required_ruby_version: !ruby/object:Gem::Requirement
97
+ none: false
98
+ requirements:
99
+ - - ">="
100
+ - !ruby/object:Gem::Version
101
+ version: "0"
102
+ required_rubygems_version: !ruby/object:Gem::Requirement
103
+ none: false
104
+ requirements:
105
+ - - ">="
106
+ - !ruby/object:Gem::Version
107
+ version: "0"
108
+ requirements: []
109
+
110
+ rubyforge_project:
111
+ rubygems_version: 1.8.5
112
+ signing_key:
113
+ specification_version: 3
114
+ summary: BrainFuck interpreter
115
+ test_files: []
116
+