brainfucktt 0.1.1 → 0.1.2

Sign up to get free protection for your applications and to get access to all the features.
data/Rakefile CHANGED
@@ -23,6 +23,7 @@ spec = Gem::Specification.new do |s|
23
23
  s.add_dependency 'treetop', '~> 1.4'
24
24
  s.add_dependency 'polyglot', '~> 0.3'
25
25
  s.add_dependency 'version', '~> 1.0'
26
+ s.add_dependency 'slop', '~> 3.3'
26
27
  s.add_development_dependency 'at', '~> 0.1'
27
28
  s.add_development_dependency 'rake', '~> 10.0'
28
29
  s.add_development_dependency 'guard-rspec', '~> 2.1'
data/VERSION CHANGED
@@ -1 +1 @@
1
- 0.1.1
1
+ 0.1.2
@@ -0,0 +1,15 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'brainfucktt/repl'
4
+ require 'slop'
5
+
6
+ opts = Slop.parse help: true do
7
+ banner "brainfucktt [options]\n Start the Brainfuck REPL"
8
+ end
9
+
10
+ if opts.help?
11
+ puts
12
+ puts Brainfucktt::REPL.instance.help.lines.collect { |line| " #{line}"}.join
13
+ else
14
+ Brainfucktt::REPL.run
15
+ end
@@ -2,14 +2,15 @@
2
2
 
3
3
  Gem::Specification.new do |s|
4
4
  s.name = "brainfucktt"
5
- s.version = "0.1.1"
5
+ s.version = "0.1.2"
6
6
 
7
7
  s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
8
8
  s.authors = ["Ryan Scott Lewis"]
9
9
  s.date = "2012-12-06"
10
10
  s.description = "A Brainfuck interpreter built using Treetop."
11
11
  s.email = "ryan@rynet.us"
12
- s.files = ["Gemfile", "LICENSE", "README.md", "Rakefile", "VERSION", "brainfucktt.gemspec", "examples/hello_world.rb", "examples/hello_world_with_comments.rb", "examples/stringio.rb", "lib/brainfucktt.rb", "lib/brainfucktt/byte.rb", "lib/brainfucktt/conversion_helpers.rb", "lib/brainfucktt/data.rb", "lib/brainfucktt/errors.rb", "lib/brainfucktt/language.rb", "lib/brainfucktt/language/decrement_byte.rb", "lib/brainfucktt/language/decrement_pointer.rb", "lib/brainfucktt/language/increment_byte.rb", "lib/brainfucktt/language/increment_pointer.rb", "lib/brainfucktt/language/input_byte.rb", "lib/brainfucktt/language/loop.rb", "lib/brainfucktt/language/output_byte.rb", "lib/brainfucktt/language/tree.rb", "lib/brainfucktt/language_parser.treetop", "lib/brainfucktt/node.rb", "lib/brainfucktt/parser.rb"]
12
+ s.executables = ["brainfucktt"]
13
+ s.files = ["Gemfile", "LICENSE", "README.md", "Rakefile", "VERSION", "bin/brainfucktt", "brainfucktt.gemspec", "examples/hello_world.rb", "examples/hello_world_with_comments.rb", "examples/rot13.rb", "examples/square_numbers.rb", "examples/stringio.rb", "examples/system_bell.rb", "lib/brainfucktt.rb", "lib/brainfucktt/byte.rb", "lib/brainfucktt/conversion_helpers.rb", "lib/brainfucktt/data.rb", "lib/brainfucktt/errors.rb", "lib/brainfucktt/language.rb", "lib/brainfucktt/language/decrement_byte.rb", "lib/brainfucktt/language/decrement_pointer.rb", "lib/brainfucktt/language/increment_byte.rb", "lib/brainfucktt/language/increment_pointer.rb", "lib/brainfucktt/language/input_byte.rb", "lib/brainfucktt/language/loop.rb", "lib/brainfucktt/language/output_byte.rb", "lib/brainfucktt/language/tree.rb", "lib/brainfucktt/language_parser.treetop", "lib/brainfucktt/node.rb", "lib/brainfucktt/parser.rb", "lib/brainfucktt/repl.rb"]
13
14
  s.homepage = "http://github.com/RyanScottLewis/brainfucktt"
14
15
  s.require_paths = ["lib"]
15
16
  s.rubygems_version = "1.8.24"
@@ -22,6 +23,7 @@ Gem::Specification.new do |s|
22
23
  s.add_runtime_dependency(%q<treetop>, ["~> 1.4"])
23
24
  s.add_runtime_dependency(%q<polyglot>, ["~> 0.3"])
24
25
  s.add_runtime_dependency(%q<version>, ["~> 1.0"])
26
+ s.add_runtime_dependency(%q<slop>, ["~> 3.3"])
25
27
  s.add_development_dependency(%q<at>, ["~> 0.1"])
26
28
  s.add_development_dependency(%q<rake>, ["~> 10.0"])
27
29
  s.add_development_dependency(%q<guard-rspec>, ["~> 2.1"])
@@ -34,6 +36,7 @@ Gem::Specification.new do |s|
34
36
  s.add_dependency(%q<treetop>, ["~> 1.4"])
35
37
  s.add_dependency(%q<polyglot>, ["~> 0.3"])
36
38
  s.add_dependency(%q<version>, ["~> 1.0"])
39
+ s.add_dependency(%q<slop>, ["~> 3.3"])
37
40
  s.add_dependency(%q<at>, ["~> 0.1"])
38
41
  s.add_dependency(%q<rake>, ["~> 10.0"])
39
42
  s.add_dependency(%q<guard-rspec>, ["~> 2.1"])
@@ -47,6 +50,7 @@ Gem::Specification.new do |s|
47
50
  s.add_dependency(%q<treetop>, ["~> 1.4"])
48
51
  s.add_dependency(%q<polyglot>, ["~> 0.3"])
49
52
  s.add_dependency(%q<version>, ["~> 1.0"])
53
+ s.add_dependency(%q<slop>, ["~> 3.3"])
50
54
  s.add_dependency(%q<at>, ["~> 0.1"])
51
55
  s.add_dependency(%q<rake>, ["~> 10.0"])
52
56
  s.add_dependency(%q<guard-rspec>, ["~> 2.1"])
@@ -1,8 +1,6 @@
1
1
  require_relative '../lib/brainfucktt'
2
2
 
3
- code = DATA.read
4
-
5
- Brainfucktt.run(code)
3
+ Brainfucktt.run( DATA.read )
6
4
 
7
5
  __END__
8
6
  +++++ +++++ initialize counter (cell #0) to 10
@@ -0,0 +1,37 @@
1
+ require_relative '../lib/brainfucktt'
2
+
3
+ Brainfucktt.run( DATA.read )
4
+
5
+ __END__
6
+ WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING
7
+ THIS IS SLOW THIS IS SLOW THIS IS SLOW THIS IS SLOW THIS IS SLOW THIS IS SLOW
8
+ WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING
9
+
10
+ -,+[ Read first character and start outer character reading loop
11
+ -[ Skip forward if character is 0
12
+ >>++++[>++++++++<-] Set up divisor (32) for division loop
13
+ (MEMORY LAYOUT: dividend copy remainder divisor quotient zero zero)
14
+ <+<-[ Set up dividend (x minus 1) and enter division loop
15
+ >+>+>-[>>>] Increase copy and remainder / reduce divisor / Normal case: skip forward
16
+ <[[>+<-]>>+>] Special case: move remainder back to divisor and increase quotient
17
+ <<<<<- Decrement dividend
18
+ ] End division loop
19
+ ]>>>[-]+ End skip loop; zero former divisor and reuse space for a flag
20
+ >--[-[<->+++[-]]]<[ Zero that flag unless quotient was 2 or 3; zero quotient; check flag
21
+ ++++++++++++<[ If flag then set up divisor (13) for second division loop
22
+ (MEMORY LAYOUT: zero copy dividend divisor remainder quotient zero zero)
23
+ >-[>+>>] Reduce divisor; Normal case: increase remainder
24
+ >[+[<+>-]>+>>] Special case: increase remainder / move it back to 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 was 1
30
+ -<<[-]>> Zero quotient and divisor if quotient was 2
31
+ ]<<[<<->>-]>> Zero divisor and subtract 13 from copy if quotient was 1
32
+ ]<<[<<+>>-] Zero divisor and add 13 to copy if quotient was 0
33
+ ] End outer skip loop (jump to here if ((character minus 1)/32) was not 2 or 3)
34
+ <[-] Clear remainder from first division if second division was skipped
35
+ <.[-] Output ROT13ed character from copy and clear it
36
+ <-,+ Read next character
37
+ ] End character reading loop
@@ -0,0 +1,37 @@
1
+ # require 'brainfucktt'
2
+ $:.unshift(File.expand_path(File.join(__FILE__, '..', '..', 'lib-compiled')))
3
+ Rubinius::CodeLoader.require_compiled 'brainfucktt'
4
+
5
+ Brainfucktt.run( DATA.read )
6
+
7
+ =begin Benchmarks
8
+
9
+ ruby 1.9.3p327 (2012-11-10 revision 37606) [x86_64-darwin12.2.0]
10
+
11
+ real 0m9.986s
12
+ user 0m9.564s
13
+ sys 0m0.274s
14
+
15
+ rubinius 2.0.0rc1 (1.8.7 release 2012-11-02 JI) [x86_64-apple-darwin12.2.0]
16
+
17
+ uncompiled
18
+
19
+ real 0m5.828s
20
+ user 0m6.330s
21
+ sys 0m0.233s
22
+
23
+ jruby 1.7.0 (1.9.3p203) 2012-10-22 ff1ebbe on Java HotSpot(TM) 64-Bit Server VM 1.6.0_37-b06-434-11M3909 [darwin-x86_64]
24
+
25
+ real 0m17.404s
26
+ user 0m26.151s
27
+ sys 0m1.402s
28
+
29
+
30
+ =end
31
+
32
+
33
+ __END__
34
+ ++++[>+++++<-]>[<+++++>-]+<+[>[>+>+<<-]++>>[<<+>>-]>>>[-]++>[-]+>>>+[[-]++++++>
35
+ >>]<<<[[<++++++++<++>>-]+<.<[>----<-]<]<<[>>>>>[>>>[-]+++++++++<[>-<-]+++++++++
36
+ >[-[<->-]+[<<<]]<[>+<-]>]<<-]<<-]
37
+
@@ -0,0 +1,3 @@
1
+ require_relative '../lib/brainfucktt'
2
+
3
+ Brainfucktt.run('+++++++.')
@@ -1,17 +1,30 @@
1
- require 'pathname'
2
- require 'forwardable'
3
-
4
- __LIB__ ||= Pathname.new(__FILE__).join('..').expand_path
5
- $:.unshift(__LIB__.to_s) unless $:.include?(__LIB__)
1
+ # require 'pathname'
2
+ #
3
+ # __LIB__ ||= Pathname.new(__FILE__).join('..').expand_path
4
+ # $:.unshift(__LIB__.to_s) unless $:.include?(__LIB__)
6
5
 
7
6
  require 'brainfucktt/parser'
8
7
 
9
8
  # A Brainfuck interpreter built in Ruby using Treetop.
10
9
  module Brainfucktt
11
10
  class << self
12
- extend Forwardable
13
11
 
14
- delegate [:parse, :run] => Parser
12
+ # Parse the given Brainfuck code.
13
+ #
14
+ # @param [String, #to_s] code
15
+ # @raise [Brainfucktt::ParserError]
16
+ # @return [Brainfucktt::Parser]
17
+ def parse(code)
18
+ Parser.parse(code)
19
+ end
20
+
21
+ # Parse and run the given Brainfuck code.
22
+ #
23
+ # @param [String, #to_s] code
24
+ # @param [Hash, #to_hash, #to_h] options
25
+ def run(code=nil, options={})
26
+ Parser.run(code, options)
27
+ end
15
28
 
16
29
  end
17
30
  end
@@ -44,7 +44,7 @@ module Brainfucktt
44
44
  #
45
45
  # @return [true, false]
46
46
  def ==(other)
47
- self == other
47
+ self.object_id == other.object_id
48
48
  end
49
49
 
50
50
  # Check to see if the given object instance as an Integer is the same as the value of
@@ -74,7 +74,7 @@ module Brainfucktt
74
74
  #
75
75
  # @return [String]
76
76
  def to_binary
77
- @value.to_s(2)
77
+ "%08b" % @value
78
78
  end
79
79
 
80
80
  # Return the Byte as an ASCII character.
@@ -89,7 +89,7 @@ module Brainfucktt
89
89
  #
90
90
  # @return [String]
91
91
  def to_hex
92
- @value.to_s(16)
92
+ '%02x' % @value
93
93
  end
94
94
 
95
95
  # Return the Byte as a binary string.
@@ -39,11 +39,6 @@ module Brainfucktt
39
39
 
40
40
  # Raised when the code being parsed has a syntax error.
41
41
  class ParserError < Error
42
- extend Forwardable
43
-
44
- def_delegator :@language_parser, :failure_reason, :reason
45
- def_delegator :@language_parser, :failure_line, :line
46
- def_delegator :@language_parser, :failure_column, :column
47
42
 
48
43
  # @param [Brainfucktt::LanguageParser] language_parser
49
44
  def initialize(language_parser)
@@ -57,6 +52,21 @@ module Brainfucktt
57
52
  "Error at column #{column}, line #{line} - '#{reason}'"
58
53
  end
59
54
 
55
+ # @return [String]
56
+ def reason
57
+ @language_parser.failure_reason
58
+ end
59
+
60
+ # @return [String]
61
+ def line
62
+ @language_parser.failure_line
63
+ end
64
+
65
+ # @return [String]
66
+ def column
67
+ @language_parser.failure_column
68
+ end
69
+
60
70
  end
61
71
 
62
72
  end
@@ -8,7 +8,7 @@ module Brainfucktt
8
8
 
9
9
  # Input an ASCII character and store it in the byte at the pointer.
10
10
  def run(parser)
11
- parser.byte = get_character(parser.stdin)
11
+ parser.byte = get_character(parser.input)
12
12
  end
13
13
 
14
14
  protected
@@ -8,7 +8,7 @@ module Brainfucktt
8
8
 
9
9
  # Run the loop
10
10
  def run(parser)
11
- elements.first.run(parser) until parser.byte.empty?
11
+ elements[0].run(parser) until parser.byte.empty?
12
12
  end
13
13
 
14
14
  end
@@ -5,13 +5,11 @@ module Brainfucktt
5
5
  # The base class for Brainfucktt syntax nodes in the AST
6
6
  class Node < Treetop::Runtime::SyntaxNode
7
7
 
8
- alias_method :elements_with_treetop, :elements
9
-
10
8
  # The children of this Node instance.
11
9
  #
12
10
  # @return [<Brainfucktt::Node>]
13
11
  def elements
14
- elements_with_treetop.find_all { |node| node.is_a?(Brainfucktt::Node) } rescue []
12
+ super.find_all { |node| node.is_a?(Brainfucktt::Node) } rescue []
15
13
  end
16
14
 
17
15
  # Return the text value of this Node instance.
@@ -16,9 +16,16 @@ module Brainfucktt
16
16
 
17
17
  # Get a new or the cached instance of this class.
18
18
  #
19
- # @return [Brainfucktt::LanguageParser]
19
+ # @return [Brainfucktt::Parser]
20
20
  def instance
21
- @instance ||= LanguageParser.new
21
+ @instance ||= new
22
+ end
23
+
24
+ # Get a new or the cached instance of this class.
25
+ #
26
+ # @return [Brainfucktt::Parser]
27
+ def language_parser
28
+ @language_parser ||= LanguageParser.new
22
29
  end
23
30
 
24
31
  # Parse the given Brainfuck code.
@@ -27,38 +34,55 @@ module Brainfucktt
27
34
  # @raise [Brainfucktt::ParserError]
28
35
  # @return [Brainfucktt::Parser]
29
36
  def parse(code)
30
- tree = instance.parse(code)
31
- raise ParserError, instance unless tree
32
-
33
- new(tree)
37
+ instance.parse(code)
34
38
  end
35
39
 
36
40
  # Parse and run the given Brainfuck code.
37
41
  #
38
42
  # @param [String, #to_s] code
39
- def run(code, options={})
40
- parse(code).run(options)
43
+ # @param [Hash, #to_hash, #to_h] options
44
+ def run(code=nil, options={})
45
+ instance.run(code, options)
41
46
  end
47
+
42
48
  end
43
49
 
44
50
  attr_reader :data, :tree, :input, :output
45
51
  attr_accessor :pointer
46
52
 
47
- def initialize(tree)
48
- @data, @tree, @pointer = Data.new, tree, 0
49
- end
53
+ def initialize(options={})
54
+ options = { :input => STDIN, :output => STDOUT }.merge( convert_to_options(options) )
50
55
 
56
+ @input, @output = options.values_at(:input, :output)
57
+ @data, @pointer, @tree = Data.new, 0, nil
58
+ end
59
+
51
60
  # Run the parsed Brainfuck code.
52
61
  #
53
- # @raise [Brainfucktt::InvalidOptionsError] When the given offset cannot be converted into an Integer.
62
+ # @param [String, #to_s] code The code to parse before running.
54
63
  # @param [Hash, #to_hash, #to_h] options
55
- def run(options={})
56
- options = { input: STDIN, output: STDOUT }.merge( convert_to_options(options) )
57
-
64
+ # @raise [Brainfucktt::InvalidOptionsError] When the given offset cannot be converted into an Integer.
65
+ def run(code=nil, options={})
66
+ options = { :input => @input, :output => @output }.merge( convert_to_options(options) )
58
67
  @input, @output = options.values_at(:input, :output)
68
+
69
+ parse(code) unless code.nil?
70
+
59
71
  @tree.run(self)
60
72
  end
61
73
 
74
+ # Parse the given Brainfuck code.
75
+ #
76
+ # @param [String, #to_s] code
77
+ # @raise [Brainfucktt::ParserError]
78
+ # @return [Brainfucktt::Parser]
79
+ def parse(code)
80
+ @tree = self.class.language_parser.parse(code)
81
+ raise ParserError, self unless @tree
82
+
83
+ self
84
+ end
85
+
62
86
  # Returns the Byte instance within the @data collection at pointer.
63
87
  #
64
88
  # @return [Brainfucktt::Byte]
@@ -0,0 +1,103 @@
1
+ require 'brainfucktt/parser'
2
+
3
+ module Brainfucktt
4
+
5
+ class REPL
6
+
7
+ class << self
8
+
9
+ def instance
10
+ @instance ||= new
11
+ end
12
+
13
+ def run
14
+ puts instance.help
15
+ instance.loop
16
+ end
17
+
18
+ end
19
+
20
+ def initialize
21
+ trap('INT') { self.exit }
22
+ @input, @output = nil
23
+ @parser = Brainfucktt::Parser.new
24
+ end
25
+
26
+ def read
27
+ Kernel.print '> '
28
+ @input = gets
29
+ end
30
+
31
+ def eval
32
+ case @input.strip
33
+ when 'help' then puts help
34
+ when '?' then puts help
35
+ when 'quit' then self.exit
36
+ when 'exit' then self.exit
37
+ when 'hex' then puts hex
38
+ when 'ascii' then puts ascii
39
+ when 'binary' then puts binary
40
+ when 'decimal' then puts decimal
41
+ else; @parser.run(@input)
42
+ end
43
+ end
44
+
45
+ def print
46
+ puts @parser.data.bytes.collect { |byte|
47
+ byte_str = ''
48
+ byte_str << (@parser.byte == byte ? '>' : '|')
49
+ byte_str << byte.to_hex
50
+ byte_str << (@parser.byte == byte ? '<' : '|')
51
+
52
+ byte_str
53
+ }.join(' ')
54
+
55
+ @input = nil
56
+ end
57
+
58
+ def loop
59
+ Kernel.loop do
60
+ # begin
61
+ read
62
+ eval
63
+ print
64
+ # rescue
65
+ # # Do squat
66
+ # end
67
+ end
68
+ end
69
+
70
+ def help
71
+ result = ''
72
+ result << "Type 'help' or '?' for help.\n"
73
+ result << "Type 'hex' to output the data buffer in hexadecimal.\n"
74
+ result << "Type 'ascii' to output the data buffer in ASCII.\n"
75
+ result << "Type 'binary' to output the data buffer in binary.\n"
76
+ result << "Type 'decimal' to output the data buffer in decimal.\n"
77
+ result << "Type 'exit' or 'quit' or press CTRL-C to exit.\n\n"
78
+ end
79
+
80
+ def exit
81
+ puts
82
+ Kernel.exit
83
+ end
84
+
85
+ def hex
86
+ @parser.data.bytes.collect(&:to_hex).join(' ')
87
+ end
88
+
89
+ def ascii
90
+ @parser.data.bytes.collect(&:to_ascii).join
91
+ end
92
+
93
+ def binary
94
+ @parser.data.bytes.collect(&:to_binary).join(' ')
95
+ end
96
+
97
+ def decimal
98
+ @parser.data.bytes.collect(&:to_i).join(' ')
99
+ end
100
+
101
+ end
102
+
103
+ end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: brainfucktt
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.1
4
+ version: 0.1.2
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -59,6 +59,22 @@ dependencies:
59
59
  - - ~>
60
60
  - !ruby/object:Gem::Version
61
61
  version: '1.0'
62
+ - !ruby/object:Gem::Dependency
63
+ name: slop
64
+ requirement: !ruby/object:Gem::Requirement
65
+ none: false
66
+ requirements:
67
+ - - ~>
68
+ - !ruby/object:Gem::Version
69
+ version: '3.3'
70
+ type: :runtime
71
+ prerelease: false
72
+ version_requirements: !ruby/object:Gem::Requirement
73
+ none: false
74
+ requirements:
75
+ - - ~>
76
+ - !ruby/object:Gem::Version
77
+ version: '3.3'
62
78
  - !ruby/object:Gem::Dependency
63
79
  name: at
64
80
  requirement: !ruby/object:Gem::Requirement
@@ -189,7 +205,8 @@ dependencies:
189
205
  version: '0.7'
190
206
  description: A Brainfuck interpreter built using Treetop.
191
207
  email: ryan@rynet.us
192
- executables: []
208
+ executables:
209
+ - brainfucktt
193
210
  extensions: []
194
211
  extra_rdoc_files: []
195
212
  files:
@@ -198,10 +215,14 @@ files:
198
215
  - README.md
199
216
  - Rakefile
200
217
  - VERSION
218
+ - bin/brainfucktt
201
219
  - brainfucktt.gemspec
202
220
  - examples/hello_world.rb
203
221
  - examples/hello_world_with_comments.rb
222
+ - examples/rot13.rb
223
+ - examples/square_numbers.rb
204
224
  - examples/stringio.rb
225
+ - examples/system_bell.rb
205
226
  - lib/brainfucktt.rb
206
227
  - lib/brainfucktt/byte.rb
207
228
  - lib/brainfucktt/conversion_helpers.rb
@@ -219,6 +240,7 @@ files:
219
240
  - lib/brainfucktt/language_parser.treetop
220
241
  - lib/brainfucktt/node.rb
221
242
  - lib/brainfucktt/parser.rb
243
+ - lib/brainfucktt/repl.rb
222
244
  homepage: http://github.com/RyanScottLewis/brainfucktt
223
245
  licenses: []
224
246
  post_install_message:
@@ -233,7 +255,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
233
255
  version: '0'
234
256
  segments:
235
257
  - 0
236
- hash: -107453280338519890
258
+ hash: -1731370008399117762
237
259
  required_rubygems_version: !ruby/object:Gem::Requirement
238
260
  none: false
239
261
  requirements: