brainfucktt 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- data/Gemfile +3 -0
- data/LICENSE +20 -0
- data/README.md +97 -0
- data/Rakefile +62 -0
- data/VERSION +1 -0
- data/brainfucktt.gemspec +59 -0
- data/examples/hello_world.rb +6 -0
- data/examples/hello_world_with_comments.rb +28 -0
- data/examples/stringio.rb +11 -0
- data/lib/brainfucktt.rb +17 -0
- data/lib/brainfucktt/byte.rb +104 -0
- data/lib/brainfucktt/conversion_helpers.rb +37 -0
- data/lib/brainfucktt/data.rb +56 -0
- data/lib/brainfucktt/errors.rb +62 -0
- data/lib/brainfucktt/language.rb +14 -0
- data/lib/brainfucktt/language/decrement_byte.rb +17 -0
- data/lib/brainfucktt/language/decrement_pointer.rb +17 -0
- data/lib/brainfucktt/language/increment_byte.rb +17 -0
- data/lib/brainfucktt/language/increment_pointer.rb +17 -0
- data/lib/brainfucktt/language/input_byte.rb +28 -0
- data/lib/brainfucktt/language/loop.rb +17 -0
- data/lib/brainfucktt/language/output_byte.rb +17 -0
- data/lib/brainfucktt/language/tree.rb +17 -0
- data/lib/brainfucktt/language_parser.treetop +49 -0
- data/lib/brainfucktt/node.rb +45 -0
- data/lib/brainfucktt/parser.rb +78 -0
- metadata +279 -0
data/Gemfile
ADDED
data/LICENSE
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
Copyright (c) 2012 Ryan Scott Lewis <ryan@rynet.us>.
|
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.
|
data/README.md
ADDED
@@ -0,0 +1,97 @@
|
|
1
|
+
# Brainfucktt
|
2
|
+
|
3
|
+
A [Brainfuck][brainfuck] interpreter built in [Ruby][ruby] using [Treetop][treetop].
|
4
|
+
|
5
|
+
Brainfuck is an eight-instruction turing-clomplete programming language created in 1993
|
6
|
+
by Urban Müller, based on the more formal programming language [P′′][p''] created by Corrado
|
7
|
+
Böhm in 1964.
|
8
|
+
|
9
|
+
It is designed to challenge and amuse programmers, and is not made to be suitable for
|
10
|
+
practical use.
|
11
|
+
|
12
|
+
## Install
|
13
|
+
|
14
|
+
### Bundler: `gem 'brainfucktt'`
|
15
|
+
|
16
|
+
### RubyGems: `gem install brainfucktt`
|
17
|
+
|
18
|
+
## Brainfuck Instructions
|
19
|
+
|
20
|
+
`>` Increment the data pointer (to point to the next cell to the right).
|
21
|
+
|
22
|
+
`<` Decrement the data pointer (to point to the next cell to the left).
|
23
|
+
|
24
|
+
`+` Increment (increase by one) the byte at the data pointer.
|
25
|
+
|
26
|
+
`-` Decrement (decrease by one) the byte at the data pointer.
|
27
|
+
|
28
|
+
`.` Output the byte at the data pointer as an ASCII encoded character.
|
29
|
+
|
30
|
+
`,` Accept one byte of input, storing its value in the byte at the data pointer.
|
31
|
+
|
32
|
+
`[` If the byte at the data pointer is zero, then instead of moving the instruction pointer forward to the next command, jump it forward to the command after the matching `]` command.
|
33
|
+
|
34
|
+
`]` If the byte at the data pointer is nonzero, then instead of moving the instruction pointer forward to the next command, jump it back to the command after the matching `[` command.
|
35
|
+
|
36
|
+
### Comments
|
37
|
+
|
38
|
+
Any character besides one of the 8 instructions above is not parsed and will be regarded as a comment.
|
39
|
+
|
40
|
+
## Usage
|
41
|
+
|
42
|
+
### Running
|
43
|
+
|
44
|
+
```ruby
|
45
|
+
require 'brainfucktt'
|
46
|
+
|
47
|
+
# "Hello World!" written in Brainfuck
|
48
|
+
code = '++++++++++[>+++++++>++++++++++>+++>+<<<<-]>++.>+.+++++++..+++.>++.<<+++++++++++++++.>.+++.------.--------.>+.>.'
|
49
|
+
|
50
|
+
Brainfucktt.run(code)
|
51
|
+
```
|
52
|
+
|
53
|
+
### Parsing
|
54
|
+
|
55
|
+
```ruby
|
56
|
+
require 'brainfucktt'
|
57
|
+
|
58
|
+
# "Hello World!" written in Brainfuck
|
59
|
+
code = '++++++++++[>+++++++>++++++++++>+++>+<<<<-]>++.>+.+++++++..+++.>++.<<+++++++++++++++.>.+++.------.--------.>+.>.'
|
60
|
+
parser = Brainfucktt.parse(code)
|
61
|
+
|
62
|
+
# Print out the AST of the code
|
63
|
+
p parser.tree
|
64
|
+
|
65
|
+
# Run the code within Ruby
|
66
|
+
parser.run
|
67
|
+
```
|
68
|
+
|
69
|
+
### StringIO
|
70
|
+
|
71
|
+
Sometimes you do now want to use STDIN or STDOUT for the I/O of the Brainfuck program.
|
72
|
+
|
73
|
+
To do that, you must use the stdlib `stringio`:
|
74
|
+
|
75
|
+
```ruby
|
76
|
+
require 'brainfucktt'
|
77
|
+
require 'stringio'
|
78
|
+
|
79
|
+
# "Hello World!" written in Brainfuck
|
80
|
+
code = '++++++++++[>+++++++>++++++++++>+++>+<<<<-]>++.>+.+++++++..+++.>++.<<+++++++++++++++.>.+++.------.--------.>+.>.'
|
81
|
+
|
82
|
+
output = StringIO.new
|
83
|
+
Brainfucktt.run(code, output: output)
|
84
|
+
|
85
|
+
p output.string # => "Hello World!\n"
|
86
|
+
```
|
87
|
+
|
88
|
+
## Copyright
|
89
|
+
|
90
|
+
Copyright © 2012 Ryan Scott Lewis <ryan@rynet.us>.
|
91
|
+
|
92
|
+
The MIT License (MIT) - See LICENSE for further details.
|
93
|
+
|
94
|
+
[brainfuck]: http://www.muppetlabs.com/~breadbox/bf/
|
95
|
+
[ruby]: http://ruby-lang.org
|
96
|
+
[treetop]: http://treetop.rubyforge.org
|
97
|
+
[p'']: http://en.wikipedia.org/wiki/P%E2%80%B2%E2%80%B2
|
data/Rakefile
ADDED
@@ -0,0 +1,62 @@
|
|
1
|
+
require 'pathname'
|
2
|
+
|
3
|
+
def require_task(path)
|
4
|
+
begin
|
5
|
+
require path
|
6
|
+
|
7
|
+
yield
|
8
|
+
rescue LoadError
|
9
|
+
puts '', "Could not load '#{path}'.", 'Try to `rake gem:spec` and `bundle install` and try again.', ''
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
spec = Gem::Specification.new do |s|
|
14
|
+
|
15
|
+
# Variables
|
16
|
+
s.name = 'brainfucktt'
|
17
|
+
s.author = 'Ryan Scott Lewis'
|
18
|
+
s.email = 'ryan@rynet.us'
|
19
|
+
s.summary = 'A Brainfuck interpreter built in Ruby using Treetop.'
|
20
|
+
|
21
|
+
# Dependencies
|
22
|
+
s.add_dependency 'treetop', '~> 1.4'
|
23
|
+
s.add_dependency 'polyglot', '~> 0.3'
|
24
|
+
s.add_dependency 'version', '~> 1.0'
|
25
|
+
s.add_development_dependency 'at', '~> 0.1'
|
26
|
+
s.add_development_dependency 'rake', '~> 10.0'
|
27
|
+
s.add_development_dependency 'guard-rspec', '~> 2.1'
|
28
|
+
s.add_development_dependency 'guard-yard', '~> 2.0'
|
29
|
+
s.add_development_dependency 'rb-fsevent', '~> 0.9'
|
30
|
+
s.add_development_dependency 'fuubar', '~> 1.1'
|
31
|
+
s.add_development_dependency 'redcarpet', '~> 2.2.2'
|
32
|
+
s.add_development_dependency 'github-markup', '~> 0.7'
|
33
|
+
|
34
|
+
# Pragmatically set variables
|
35
|
+
s.homepage = "http://github.com/RyanScottLewis/#{s.name}"
|
36
|
+
s.version = Pathname.glob('VERSION*').first.read
|
37
|
+
s.description = Pathname.glob('README*').first.read
|
38
|
+
s.require_paths = ['lib']
|
39
|
+
s.files = `git ls-files`.lines.to_a.collect { |s| s.strip }
|
40
|
+
s.executables = `git ls-files -- bin/*`.lines.to_a.collect { |s| File.basename(s.strip) }
|
41
|
+
|
42
|
+
end
|
43
|
+
|
44
|
+
desc 'Generate the gemspec defined in this Rakefile'
|
45
|
+
task :gemspec do
|
46
|
+
Pathname.new("#{spec.name}.gemspec").open('w') { |f| f.write(spec.to_ruby) }
|
47
|
+
end
|
48
|
+
|
49
|
+
require_task 'rake/version_task' do
|
50
|
+
Rake::VersionTask.new do |t|
|
51
|
+
t.with_git_tag = true
|
52
|
+
t.with_gemspec = spec
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
require 'rubygems/package_task'
|
57
|
+
Gem::PackageTask.new(spec) do |t|
|
58
|
+
t.need_zip = false
|
59
|
+
t.need_tar = false
|
60
|
+
end
|
61
|
+
|
62
|
+
task :default => :gemspec
|
data/VERSION
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
0.1.0
|
data/brainfucktt.gemspec
ADDED
@@ -0,0 +1,59 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
|
3
|
+
Gem::Specification.new do |s|
|
4
|
+
s.name = "brainfucktt"
|
5
|
+
s.version = "0.1.0"
|
6
|
+
|
7
|
+
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
8
|
+
s.authors = ["Ryan Scott Lewis"]
|
9
|
+
s.date = "2012-12-06"
|
10
|
+
s.description = "# Brainfucktt\n\nA [Brainfuck][brainfuck] interpreter built in [Ruby][ruby] using [Treetop][treetop].\n\nBrainfuck is an eight-instruction turing-clomplete programming language created in 1993\nby Urban M\u{fc}ller, based on the more formal programming language [P\u{2032}\u{2032}][p''] created by Corrado\nB\u{f6}hm in 1964.\n\nIt is designed to challenge and amuse programmers, and is not made to be suitable for \npractical use.\n\n## Install\n\n### Bundler: `gem 'brainfucktt'`\n\n### RubyGems: `gem install brainfucktt`\n\n## Brainfuck Instructions\n\n`>` Increment the data pointer (to point to the next cell to the right).\n\n`<` Decrement the data pointer (to point to the next cell to the left).\n\n`+` Increment (increase by one) the byte at the data pointer.\n\n`-` Decrement (decrease by one) the byte at the data pointer.\n\n`.` Output the byte at the data pointer as an ASCII encoded character.\n\n`,` Accept one byte of input, storing its value in the byte at the data pointer.\n\n`[` If the byte at the data pointer is zero, then instead of moving the instruction pointer forward to the next command, jump it forward to the command after the matching `]` command.\n\n`]` If the byte at the data pointer is nonzero, then instead of moving the instruction pointer forward to the next command, jump it back to the command after the matching `[` command.\n\n### Comments\n\nAny character besides one of the 8 instructions above is not parsed and will be regarded as a comment.\n\n## Usage\n\n### Running\n\n```ruby\nrequire 'brainfucktt'\n\n# \"Hello World!\" written in Brainfuck\ncode = '++++++++++[>+++++++>++++++++++>+++>+<<<<-]>++.>+.+++++++..+++.>++.<<+++++++++++++++.>.+++.------.--------.>+.>.'\n\nBrainfucktt.run(code)\n```\n\n### Parsing\n\n```ruby\nrequire 'brainfucktt'\n\n# \"Hello World!\" written in Brainfuck\ncode = '++++++++++[>+++++++>++++++++++>+++>+<<<<-]>++.>+.+++++++..+++.>++.<<+++++++++++++++.>.+++.------.--------.>+.>.'\nparser = Brainfucktt.parse(code)\n\n# Print out the AST of the code\np parser.tree\n\n# Run the code within Ruby\nparser.run\n```\n\n### StringIO\n\nSometimes you do now want to use STDIN or STDOUT for the I/O of the Brainfuck program.\n\nTo do that, you must use the stdlib `stringio`:\n\n```ruby\nrequire 'brainfucktt'\nrequire 'stringio'\n\n# \"Hello World!\" written in Brainfuck\ncode = '++++++++++[>+++++++>++++++++++>+++>+<<<<-]>++.>+.+++++++..+++.>++.<<+++++++++++++++.>.+++.------.--------.>+.>.'\n\noutput = StringIO.new\nBrainfucktt.run(code, output: output)\n\np output.string # => \"Hello World!\\n\"\n```\n\n## Copyright\n\nCopyright \u{a9} 2012 Ryan Scott Lewis <ryan@rynet.us>.\n\nThe MIT License (MIT) - See LICENSE for further details.\n\n[brainfuck]: http://www.muppetlabs.com/~breadbox/bf/\n[ruby]: http://ruby-lang.org\n[treetop]: http://treetop.rubyforge.org\n[p'']: http://en.wikipedia.org/wiki/P%E2%80%B2%E2%80%B2"
|
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"]
|
13
|
+
s.homepage = "http://github.com/RyanScottLewis/brainfucktt"
|
14
|
+
s.require_paths = ["lib"]
|
15
|
+
s.rubygems_version = "1.8.24"
|
16
|
+
s.summary = "A Brainfuck interpreter built in Ruby using Treetop."
|
17
|
+
|
18
|
+
if s.respond_to? :specification_version then
|
19
|
+
s.specification_version = 3
|
20
|
+
|
21
|
+
if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then
|
22
|
+
s.add_runtime_dependency(%q<treetop>, ["~> 1.4"])
|
23
|
+
s.add_runtime_dependency(%q<polyglot>, ["~> 0.3"])
|
24
|
+
s.add_runtime_dependency(%q<version>, ["~> 1.0"])
|
25
|
+
s.add_development_dependency(%q<at>, ["~> 0.1"])
|
26
|
+
s.add_development_dependency(%q<rake>, ["~> 10.0"])
|
27
|
+
s.add_development_dependency(%q<guard-rspec>, ["~> 2.1"])
|
28
|
+
s.add_development_dependency(%q<guard-yard>, ["~> 2.0"])
|
29
|
+
s.add_development_dependency(%q<rb-fsevent>, ["~> 0.9"])
|
30
|
+
s.add_development_dependency(%q<fuubar>, ["~> 1.1"])
|
31
|
+
s.add_development_dependency(%q<redcarpet>, ["~> 2.2.2"])
|
32
|
+
s.add_development_dependency(%q<github-markup>, ["~> 0.7"])
|
33
|
+
else
|
34
|
+
s.add_dependency(%q<treetop>, ["~> 1.4"])
|
35
|
+
s.add_dependency(%q<polyglot>, ["~> 0.3"])
|
36
|
+
s.add_dependency(%q<version>, ["~> 1.0"])
|
37
|
+
s.add_dependency(%q<at>, ["~> 0.1"])
|
38
|
+
s.add_dependency(%q<rake>, ["~> 10.0"])
|
39
|
+
s.add_dependency(%q<guard-rspec>, ["~> 2.1"])
|
40
|
+
s.add_dependency(%q<guard-yard>, ["~> 2.0"])
|
41
|
+
s.add_dependency(%q<rb-fsevent>, ["~> 0.9"])
|
42
|
+
s.add_dependency(%q<fuubar>, ["~> 1.1"])
|
43
|
+
s.add_dependency(%q<redcarpet>, ["~> 2.2.2"])
|
44
|
+
s.add_dependency(%q<github-markup>, ["~> 0.7"])
|
45
|
+
end
|
46
|
+
else
|
47
|
+
s.add_dependency(%q<treetop>, ["~> 1.4"])
|
48
|
+
s.add_dependency(%q<polyglot>, ["~> 0.3"])
|
49
|
+
s.add_dependency(%q<version>, ["~> 1.0"])
|
50
|
+
s.add_dependency(%q<at>, ["~> 0.1"])
|
51
|
+
s.add_dependency(%q<rake>, ["~> 10.0"])
|
52
|
+
s.add_dependency(%q<guard-rspec>, ["~> 2.1"])
|
53
|
+
s.add_dependency(%q<guard-yard>, ["~> 2.0"])
|
54
|
+
s.add_dependency(%q<rb-fsevent>, ["~> 0.9"])
|
55
|
+
s.add_dependency(%q<fuubar>, ["~> 1.1"])
|
56
|
+
s.add_dependency(%q<redcarpet>, ["~> 2.2.2"])
|
57
|
+
s.add_dependency(%q<github-markup>, ["~> 0.7"])
|
58
|
+
end
|
59
|
+
end
|
@@ -0,0 +1,28 @@
|
|
1
|
+
require_relative '../lib/brainfucktt'
|
2
|
+
|
3
|
+
code = DATA.read
|
4
|
+
|
5
|
+
Brainfucktt.run(code)
|
6
|
+
|
7
|
+
__END__
|
8
|
+
+++++ +++++ initialize counter (cell #0) to 10
|
9
|
+
[ use loop to set the next four cells to 70/100/30/10
|
10
|
+
> +++++ ++ add 7 to cell #1
|
11
|
+
> +++++ +++++ add 10 to cell #2
|
12
|
+
> +++ add 3 to cell #3
|
13
|
+
> + add 1 to cell #4
|
14
|
+
<<<< - decrement counter (cell #0)
|
15
|
+
] end loop
|
16
|
+
> ++ . print 'H'
|
17
|
+
> + . print 'e'
|
18
|
+
+++++ ++ . print 'l'
|
19
|
+
. print 'l'
|
20
|
+
+++ . print 'o'
|
21
|
+
> ++ . print ' '
|
22
|
+
<< +++++ +++++ +++++ . print 'W'
|
23
|
+
> . print 'o'
|
24
|
+
+++ . print 'r'
|
25
|
+
----- - . print 'l'
|
26
|
+
----- --- . print 'd'
|
27
|
+
> + . print '!'
|
28
|
+
> . print '\n'
|
@@ -0,0 +1,11 @@
|
|
1
|
+
require_relative '../lib/brainfucktt'
|
2
|
+
|
3
|
+
require 'stringio'
|
4
|
+
|
5
|
+
# "Hello World!" written in Brainfuck
|
6
|
+
code = '++++++++++[>+++++++>++++++++++>+++>+<<<<-]>++.>+.+++++++..+++.>++.<<+++++++++++++++.>.+++.------.--------.>+.>.'
|
7
|
+
|
8
|
+
output = StringIO.new
|
9
|
+
Brainfucktt.run(code, output: output)
|
10
|
+
|
11
|
+
p output.string # => "Hello World!\n"
|
data/lib/brainfucktt.rb
ADDED
@@ -0,0 +1,17 @@
|
|
1
|
+
require 'pathname'
|
2
|
+
require 'forwardable'
|
3
|
+
|
4
|
+
__LIB__ ||= Pathname.new(__FILE__).join('..').expand_path
|
5
|
+
$:.unshift(__LIB__.to_s) unless $:.include?(__LIB__)
|
6
|
+
|
7
|
+
require 'brainfucktt/parser'
|
8
|
+
|
9
|
+
# A Brainfuck interpreter built in Ruby using Treetop.
|
10
|
+
module Brainfucktt
|
11
|
+
class << self
|
12
|
+
extend Forwardable
|
13
|
+
|
14
|
+
delegate [:parse, :run] => Parser
|
15
|
+
|
16
|
+
end
|
17
|
+
end
|
@@ -0,0 +1,104 @@
|
|
1
|
+
require 'brainfucktt/conversion_helpers'
|
2
|
+
|
3
|
+
module Brainfucktt
|
4
|
+
|
5
|
+
# A Byte.
|
6
|
+
class Byte
|
7
|
+
include ConversionHelpers
|
8
|
+
include Comparable
|
9
|
+
|
10
|
+
# Set the value of the Byte instance at the given offset.
|
11
|
+
#
|
12
|
+
# @param [Byte, Integer, #to_i] value
|
13
|
+
# @raise [Brainfucktt::InvalidByteError] When the given value cannot be converted into an Integer or is not between 0 and 255.
|
14
|
+
def initialize(value=0)
|
15
|
+
@value = convert_to_integer(value)
|
16
|
+
end
|
17
|
+
|
18
|
+
# Add to this Byte instance's value.
|
19
|
+
#
|
20
|
+
# @param [Byte, Integer, #to_i] value
|
21
|
+
# @raise [Brainfucktt::InvalidByteError] When the given value cannot be converted into an Integer or is not between 0 and 255.
|
22
|
+
# @return [Integer] The new value.
|
23
|
+
def +(value)
|
24
|
+
@value += convert_to_integer(value)
|
25
|
+
end
|
26
|
+
|
27
|
+
# Subtract from this Byte instance's value.
|
28
|
+
#
|
29
|
+
# @param [Byte, Integer, #to_i] value
|
30
|
+
# @raise [Brainfucktt::InvalidByteError] When the given value cannot be converted into an Integer or is not between 0 and 255.
|
31
|
+
# @return [Integer] The new value.
|
32
|
+
def -(value)
|
33
|
+
@value -= convert_to_integer(value)
|
34
|
+
end
|
35
|
+
|
36
|
+
# Compare with another Byte, Integer, String, etc..
|
37
|
+
#
|
38
|
+
# @return [nil, Integer]
|
39
|
+
def <=>(other)
|
40
|
+
@value <=> convert_to_integer(other)
|
41
|
+
end
|
42
|
+
|
43
|
+
# Check to see if the given object instance is the same instance as self.
|
44
|
+
#
|
45
|
+
# @return [true, false]
|
46
|
+
def ==(other)
|
47
|
+
self == other
|
48
|
+
end
|
49
|
+
|
50
|
+
# Check to see if the given object instance as an Integer is the same as the value of
|
51
|
+
# this Byte instance.
|
52
|
+
#
|
53
|
+
# @return [true, false]
|
54
|
+
def eql?(other)
|
55
|
+
@value == convert_to_integer(other)
|
56
|
+
end
|
57
|
+
alias_method :equal?, :eql?
|
58
|
+
|
59
|
+
# Check this Byte instance is empty.
|
60
|
+
#
|
61
|
+
# @return [true, false]
|
62
|
+
def empty?
|
63
|
+
@value == 0
|
64
|
+
end
|
65
|
+
|
66
|
+
# Return the Byte as an Integer
|
67
|
+
#
|
68
|
+
# @return [Integer]
|
69
|
+
def to_i
|
70
|
+
@value
|
71
|
+
end
|
72
|
+
|
73
|
+
# Return the Byte as a binary string.
|
74
|
+
#
|
75
|
+
# @return [String]
|
76
|
+
def to_binary
|
77
|
+
@value.to_s(2)
|
78
|
+
end
|
79
|
+
|
80
|
+
# Return the Byte as an ASCII character.
|
81
|
+
#
|
82
|
+
# @return [String]
|
83
|
+
def to_ascii
|
84
|
+
@value.chr
|
85
|
+
end
|
86
|
+
alias_method :to_s, :to_ascii
|
87
|
+
|
88
|
+
# Return the Byte as a hexadecimal string.
|
89
|
+
#
|
90
|
+
# @return [String]
|
91
|
+
def to_hex
|
92
|
+
@value.to_s(16)
|
93
|
+
end
|
94
|
+
|
95
|
+
# Return the Byte as a binary string.
|
96
|
+
#
|
97
|
+
# @return [String]
|
98
|
+
def inspect
|
99
|
+
"#<#{self.class}:#{object_id.to_s(16)} integer=#{to_i.inspect} hex=#{to_hex.inspect} ascii=#{to_ascii.inspect} binary=#{to_binary.inspect} >"
|
100
|
+
end
|
101
|
+
|
102
|
+
end
|
103
|
+
|
104
|
+
end
|
@@ -0,0 +1,37 @@
|
|
1
|
+
require 'brainfucktt/errors'
|
2
|
+
|
3
|
+
module Brainfucktt
|
4
|
+
|
5
|
+
# Helpers for Classes which have methods that accepts a value that need
|
6
|
+
# to be converted into a specific type.
|
7
|
+
module ConversionHelpers
|
8
|
+
|
9
|
+
protected
|
10
|
+
|
11
|
+
def convert_to_integer(value)
|
12
|
+
raise InvalidByteError unless value.is_a?(Integer) || value.respond_to?(:to_i)
|
13
|
+
value = value.to_i unless value.is_a?(Integer)
|
14
|
+
|
15
|
+
value
|
16
|
+
end
|
17
|
+
|
18
|
+
def convert_to_byte(value)
|
19
|
+
raise InvalidByteError unless value.is_a?(Byte) || value.is_a?(Integer) || value.respond_to?(:to_i)
|
20
|
+
value = value.to_i unless value.is_a?(Byte) || value.is_a?(Integer)
|
21
|
+
value = Byte.new(value) unless value.is_a?(Byte)
|
22
|
+
|
23
|
+
# TODO: Complain about 0 to 255 compliance
|
24
|
+
|
25
|
+
value
|
26
|
+
end
|
27
|
+
|
28
|
+
def convert_to_options(value)
|
29
|
+
raise InvalidOptionsError unless value.is_a?(Hash) || value.respond_to?(:to_hash) || value.respond_to?(:to_h)
|
30
|
+
value = value.to_hash rescue value.to_h unless value.is_a?(Hash)
|
31
|
+
|
32
|
+
value
|
33
|
+
end
|
34
|
+
|
35
|
+
end
|
36
|
+
|
37
|
+
end
|
@@ -0,0 +1,56 @@
|
|
1
|
+
require 'brainfucktt/conversion_helpers'
|
2
|
+
require 'brainfucktt/byte'
|
3
|
+
|
4
|
+
module Brainfucktt
|
5
|
+
|
6
|
+
# An Array of Byte instances.
|
7
|
+
class Data
|
8
|
+
include ConversionHelpers
|
9
|
+
|
10
|
+
attr_reader :bytes
|
11
|
+
|
12
|
+
def initialize
|
13
|
+
@bytes = []
|
14
|
+
end
|
15
|
+
|
16
|
+
# Retrieve the Byte instance at the given offset.
|
17
|
+
#
|
18
|
+
# @param [Integer, #to_i] offset
|
19
|
+
# @raise [Brainfucktt::InvalidOffsetError] When the given offset cannot be converted into an Integer.
|
20
|
+
# @return [Byte] The Byte instance at the given offset.
|
21
|
+
def [](offset)
|
22
|
+
offset = convert_to_integer(offset)
|
23
|
+
self[offset] = 0 if @bytes[offset].nil?
|
24
|
+
|
25
|
+
@bytes[offset]
|
26
|
+
end
|
27
|
+
|
28
|
+
# Set the value of the Byte instance at the given offset.
|
29
|
+
#
|
30
|
+
# @param [Integer, #to_i] offset
|
31
|
+
# @param [Byte, Integer, #to_i] value
|
32
|
+
# @raise [Brainfucktt::InvalidByteError] When the given value cannot be converted into an Integer or is not between 0 and 255.
|
33
|
+
# @raise [Brainfucktt::InvalidOffsetError] When the given offset cannot be converted into an Integer.
|
34
|
+
# @return [Byte] The Byte instance at the given offset.
|
35
|
+
def []=(offset, value)
|
36
|
+
expand_to(offset)
|
37
|
+
|
38
|
+
@bytes[offset] = convert_to_byte(value)
|
39
|
+
end
|
40
|
+
|
41
|
+
# Fill from the end of the Data collection to the given offset with empty
|
42
|
+
# Byte instances, if Data collection is less than the given offset.
|
43
|
+
#
|
44
|
+
# @param [Integer, #to_i] offset
|
45
|
+
# @raise [Brainfucktt::InvalidOffsetError] When the given offset cannot be converted into an Integer.
|
46
|
+
# @return [Byte] The Byte instance at the given offset.
|
47
|
+
def expand_to(offset)
|
48
|
+
offset = convert_to_integer(offset)
|
49
|
+
(@bytes.length..offset).each { @bytes << Byte.new } if @bytes.at(offset).nil?
|
50
|
+
|
51
|
+
@bytes[offset]
|
52
|
+
end
|
53
|
+
|
54
|
+
end
|
55
|
+
|
56
|
+
end
|
@@ -0,0 +1,62 @@
|
|
1
|
+
require 'brainfucktt/language_parser'
|
2
|
+
|
3
|
+
module Brainfucktt
|
4
|
+
|
5
|
+
# Base class for all errors within this library.
|
6
|
+
class Error < StandardError
|
7
|
+
|
8
|
+
end
|
9
|
+
|
10
|
+
# Raised when the value set within a Data instance is greater than a byte or less than zero.
|
11
|
+
class InvalidByteError < Error
|
12
|
+
|
13
|
+
# @return [String] The error message.
|
14
|
+
def to_s
|
15
|
+
'The value of a Byte must be an Integer or respond to to_i and be between 0 and 255'
|
16
|
+
end
|
17
|
+
|
18
|
+
end
|
19
|
+
|
20
|
+
# Raised when the offset given is notDatanteger.
|
21
|
+
class InvalidOffsetError < Error
|
22
|
+
|
23
|
+
# @return [String] The error message.
|
24
|
+
def to_s
|
25
|
+
'The offset of a Byte must be an Integer or respond to to_i'
|
26
|
+
end
|
27
|
+
|
28
|
+
end
|
29
|
+
|
30
|
+
# Raised when the offset given is notDatash.
|
31
|
+
class InvalidOptionsError < Error
|
32
|
+
|
33
|
+
# @return [String] The error message.
|
34
|
+
def to_s
|
35
|
+
'The options must be a Hash or respond to to_hash or to_h'
|
36
|
+
end
|
37
|
+
|
38
|
+
end
|
39
|
+
|
40
|
+
# Raised when the code being parsed has a syntax error.
|
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
|
+
|
48
|
+
# @param [Brainfucktt::LanguageParser] language_parser
|
49
|
+
def initialize(language_parser)
|
50
|
+
raise TypeError unless language_parser.instance_of?(Brainfucktt::LanguageParser)
|
51
|
+
|
52
|
+
@language_parser = language_parser
|
53
|
+
end
|
54
|
+
|
55
|
+
# @return [String]
|
56
|
+
def to_s
|
57
|
+
"Error at column #{column}, line #{line} - '#{reason}'"
|
58
|
+
end
|
59
|
+
|
60
|
+
end
|
61
|
+
|
62
|
+
end
|
@@ -0,0 +1,28 @@
|
|
1
|
+
require 'brainfucktt/node'
|
2
|
+
|
3
|
+
module Brainfucktt
|
4
|
+
module Language
|
5
|
+
|
6
|
+
# ,
|
7
|
+
class InputByte < Node
|
8
|
+
|
9
|
+
# Input an ASCII character and store it in the byte at the pointer.
|
10
|
+
def run(parser)
|
11
|
+
parser.byte = get_character(parser.stdin)
|
12
|
+
end
|
13
|
+
|
14
|
+
protected
|
15
|
+
|
16
|
+
def get_character(io)
|
17
|
+
begin
|
18
|
+
system("stty raw -echo")
|
19
|
+
str = io.getc
|
20
|
+
ensure
|
21
|
+
system("stty -raw echo")
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
end
|
26
|
+
|
27
|
+
end
|
28
|
+
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
require 'brainfucktt/node'
|
2
|
+
|
3
|
+
module Brainfucktt
|
4
|
+
module Language
|
5
|
+
|
6
|
+
# .
|
7
|
+
class OutputByte < Node
|
8
|
+
|
9
|
+
# Output the byte at the pointer as an ASCII character.
|
10
|
+
def run(parser)
|
11
|
+
parser.output.print parser.byte.to_s
|
12
|
+
end
|
13
|
+
|
14
|
+
end
|
15
|
+
|
16
|
+
end
|
17
|
+
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
require 'brainfucktt/node'
|
2
|
+
|
3
|
+
module Brainfucktt
|
4
|
+
module Language
|
5
|
+
|
6
|
+
# The syntax tree of the source code or loop.
|
7
|
+
class Tree < Node
|
8
|
+
attr_accessor :data
|
9
|
+
|
10
|
+
# Run the code.
|
11
|
+
def run(parser)
|
12
|
+
elements.each { |element| element.run(parser) }
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
end
|
17
|
+
end
|
@@ -0,0 +1,49 @@
|
|
1
|
+
module Brainfucktt
|
2
|
+
grammar Language
|
3
|
+
|
4
|
+
rule tree
|
5
|
+
(loop / increment_pointer / decrement_pointer / increment_byte / decrement_byte / input_byte / output_byte / ignored_character)* <Tree>
|
6
|
+
end
|
7
|
+
|
8
|
+
rule ignored_character
|
9
|
+
!(begin_loop / end_loop / increment_pointer / decrement_pointer / increment_byte / decrement_byte / input_byte / output_byte) .
|
10
|
+
end
|
11
|
+
|
12
|
+
rule loop
|
13
|
+
begin_loop tree end_loop <Loop>
|
14
|
+
end
|
15
|
+
|
16
|
+
rule begin_loop
|
17
|
+
'['
|
18
|
+
end
|
19
|
+
|
20
|
+
rule end_loop
|
21
|
+
']'
|
22
|
+
end
|
23
|
+
|
24
|
+
rule increment_pointer
|
25
|
+
'>' <IncrementPointer>
|
26
|
+
end
|
27
|
+
|
28
|
+
rule decrement_pointer
|
29
|
+
'<' <DecrementPointer>
|
30
|
+
end
|
31
|
+
|
32
|
+
rule increment_byte
|
33
|
+
'+' <IncrementByte>
|
34
|
+
end
|
35
|
+
|
36
|
+
rule decrement_byte
|
37
|
+
'-' <DecrementByte>
|
38
|
+
end
|
39
|
+
|
40
|
+
rule input_byte
|
41
|
+
',' <InputByte>
|
42
|
+
end
|
43
|
+
|
44
|
+
rule output_byte
|
45
|
+
'.' <OutputByte>
|
46
|
+
end
|
47
|
+
|
48
|
+
end
|
49
|
+
end
|
@@ -0,0 +1,45 @@
|
|
1
|
+
require 'treetop/runtime/syntax_node'
|
2
|
+
|
3
|
+
module Brainfucktt
|
4
|
+
|
5
|
+
# The base class for Brainfucktt syntax nodes in the AST
|
6
|
+
class Node < Treetop::Runtime::SyntaxNode
|
7
|
+
|
8
|
+
alias_method :elements_with_treetop, :elements
|
9
|
+
|
10
|
+
# The children of this Node instance.
|
11
|
+
#
|
12
|
+
# @return [<Brainfucktt::Node>]
|
13
|
+
def elements
|
14
|
+
elements_with_treetop.find_all { |node| node.is_a?(Brainfucktt::Node) } rescue []
|
15
|
+
end
|
16
|
+
|
17
|
+
# Return the text value of this Node instance.
|
18
|
+
#
|
19
|
+
# @return [String]
|
20
|
+
def to_s
|
21
|
+
text_value
|
22
|
+
end
|
23
|
+
|
24
|
+
# Print out the AST of this instance node and it's children with indentation.
|
25
|
+
#
|
26
|
+
# @return [String]
|
27
|
+
def inspect(indent="")
|
28
|
+
result = ""
|
29
|
+
result << indent
|
30
|
+
result << self.class.to_s.sub(/.*:/,'')
|
31
|
+
result << " #{to_s} " unless self.is_a?(Language::Tree) || self.is_a?(Language::Loop)
|
32
|
+
|
33
|
+
unless elements.empty?
|
34
|
+
result << ":"
|
35
|
+
elements.each do |e|
|
36
|
+
result << "\n#{e.inspect(indent+" ")}" rescue "\n#{indent} #{e.inspect}"
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
result
|
41
|
+
end
|
42
|
+
|
43
|
+
end
|
44
|
+
|
45
|
+
end
|
@@ -0,0 +1,78 @@
|
|
1
|
+
require 'polyglot'
|
2
|
+
require 'treetop'
|
3
|
+
require 'brainfucktt/errors'
|
4
|
+
require 'brainfucktt/language'
|
5
|
+
require 'brainfucktt/language_parser'
|
6
|
+
require 'brainfucktt/data'
|
7
|
+
require 'brainfucktt/conversion_helpers'
|
8
|
+
|
9
|
+
module Brainfucktt
|
10
|
+
|
11
|
+
# The Brainfuck parser.
|
12
|
+
class Parser
|
13
|
+
include ConversionHelpers
|
14
|
+
|
15
|
+
class << self
|
16
|
+
|
17
|
+
# Get a new or the cached instance of this class.
|
18
|
+
#
|
19
|
+
# @return [Brainfucktt::LanguageParser]
|
20
|
+
def instance
|
21
|
+
@instance ||= LanguageParser.new
|
22
|
+
end
|
23
|
+
|
24
|
+
# Parse the given Brainfuck code.
|
25
|
+
#
|
26
|
+
# @param [String, #to_s] code
|
27
|
+
# @raise [Brainfucktt::ParserError]
|
28
|
+
# @return [Brainfucktt::Parser]
|
29
|
+
def parse(code)
|
30
|
+
tree = instance.parse(code)
|
31
|
+
raise ParserError, instance unless tree
|
32
|
+
|
33
|
+
new(tree)
|
34
|
+
end
|
35
|
+
|
36
|
+
# Parse and run the given Brainfuck code.
|
37
|
+
#
|
38
|
+
# @param [String, #to_s] code
|
39
|
+
def run(code, options={})
|
40
|
+
parse(code).run(options)
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
attr_reader :data, :tree, :input, :output
|
45
|
+
attr_accessor :pointer
|
46
|
+
|
47
|
+
def initialize(tree)
|
48
|
+
@data, @tree, @pointer = Data.new, tree, 0
|
49
|
+
end
|
50
|
+
|
51
|
+
# Run the parsed Brainfuck code.
|
52
|
+
#
|
53
|
+
# @raise [Brainfucktt::InvalidOptionsError] When the given offset cannot be converted into an Integer.
|
54
|
+
# @param [Hash, #to_hash, #to_h] options
|
55
|
+
def run(options={})
|
56
|
+
options = { input: STDIN, output: STDOUT }.merge( convert_to_options(options) )
|
57
|
+
|
58
|
+
@input, @output = options.values_at(:input, :output)
|
59
|
+
@tree.run(self)
|
60
|
+
end
|
61
|
+
|
62
|
+
# Returns the Byte instance within the @data collection at pointer.
|
63
|
+
#
|
64
|
+
# @return [Brainfucktt::Byte]
|
65
|
+
def byte
|
66
|
+
@data[@pointer]
|
67
|
+
end
|
68
|
+
|
69
|
+
# Set the value of the Byte instance within the @data collection at pointer.
|
70
|
+
#
|
71
|
+
# @return [Brainfucktt::Byte]
|
72
|
+
def byte=(value)
|
73
|
+
@data[@pointer] = value
|
74
|
+
end
|
75
|
+
|
76
|
+
end
|
77
|
+
|
78
|
+
end
|
metadata
ADDED
@@ -0,0 +1,279 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: brainfucktt
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.1.0
|
5
|
+
prerelease:
|
6
|
+
platform: ruby
|
7
|
+
authors:
|
8
|
+
- Ryan Scott Lewis
|
9
|
+
autorequire:
|
10
|
+
bindir: bin
|
11
|
+
cert_chain: []
|
12
|
+
date: 2012-12-06 00:00:00.000000000 Z
|
13
|
+
dependencies:
|
14
|
+
- !ruby/object:Gem::Dependency
|
15
|
+
name: treetop
|
16
|
+
requirement: !ruby/object:Gem::Requirement
|
17
|
+
none: false
|
18
|
+
requirements:
|
19
|
+
- - ~>
|
20
|
+
- !ruby/object:Gem::Version
|
21
|
+
version: '1.4'
|
22
|
+
type: :runtime
|
23
|
+
prerelease: false
|
24
|
+
version_requirements: !ruby/object:Gem::Requirement
|
25
|
+
none: false
|
26
|
+
requirements:
|
27
|
+
- - ~>
|
28
|
+
- !ruby/object:Gem::Version
|
29
|
+
version: '1.4'
|
30
|
+
- !ruby/object:Gem::Dependency
|
31
|
+
name: polyglot
|
32
|
+
requirement: !ruby/object:Gem::Requirement
|
33
|
+
none: false
|
34
|
+
requirements:
|
35
|
+
- - ~>
|
36
|
+
- !ruby/object:Gem::Version
|
37
|
+
version: '0.3'
|
38
|
+
type: :runtime
|
39
|
+
prerelease: false
|
40
|
+
version_requirements: !ruby/object:Gem::Requirement
|
41
|
+
none: false
|
42
|
+
requirements:
|
43
|
+
- - ~>
|
44
|
+
- !ruby/object:Gem::Version
|
45
|
+
version: '0.3'
|
46
|
+
- !ruby/object:Gem::Dependency
|
47
|
+
name: version
|
48
|
+
requirement: !ruby/object:Gem::Requirement
|
49
|
+
none: false
|
50
|
+
requirements:
|
51
|
+
- - ~>
|
52
|
+
- !ruby/object:Gem::Version
|
53
|
+
version: '1.0'
|
54
|
+
type: :runtime
|
55
|
+
prerelease: false
|
56
|
+
version_requirements: !ruby/object:Gem::Requirement
|
57
|
+
none: false
|
58
|
+
requirements:
|
59
|
+
- - ~>
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: '1.0'
|
62
|
+
- !ruby/object:Gem::Dependency
|
63
|
+
name: at
|
64
|
+
requirement: !ruby/object:Gem::Requirement
|
65
|
+
none: false
|
66
|
+
requirements:
|
67
|
+
- - ~>
|
68
|
+
- !ruby/object:Gem::Version
|
69
|
+
version: '0.1'
|
70
|
+
type: :development
|
71
|
+
prerelease: false
|
72
|
+
version_requirements: !ruby/object:Gem::Requirement
|
73
|
+
none: false
|
74
|
+
requirements:
|
75
|
+
- - ~>
|
76
|
+
- !ruby/object:Gem::Version
|
77
|
+
version: '0.1'
|
78
|
+
- !ruby/object:Gem::Dependency
|
79
|
+
name: rake
|
80
|
+
requirement: !ruby/object:Gem::Requirement
|
81
|
+
none: false
|
82
|
+
requirements:
|
83
|
+
- - ~>
|
84
|
+
- !ruby/object:Gem::Version
|
85
|
+
version: '10.0'
|
86
|
+
type: :development
|
87
|
+
prerelease: false
|
88
|
+
version_requirements: !ruby/object:Gem::Requirement
|
89
|
+
none: false
|
90
|
+
requirements:
|
91
|
+
- - ~>
|
92
|
+
- !ruby/object:Gem::Version
|
93
|
+
version: '10.0'
|
94
|
+
- !ruby/object:Gem::Dependency
|
95
|
+
name: guard-rspec
|
96
|
+
requirement: !ruby/object:Gem::Requirement
|
97
|
+
none: false
|
98
|
+
requirements:
|
99
|
+
- - ~>
|
100
|
+
- !ruby/object:Gem::Version
|
101
|
+
version: '2.1'
|
102
|
+
type: :development
|
103
|
+
prerelease: false
|
104
|
+
version_requirements: !ruby/object:Gem::Requirement
|
105
|
+
none: false
|
106
|
+
requirements:
|
107
|
+
- - ~>
|
108
|
+
- !ruby/object:Gem::Version
|
109
|
+
version: '2.1'
|
110
|
+
- !ruby/object:Gem::Dependency
|
111
|
+
name: guard-yard
|
112
|
+
requirement: !ruby/object:Gem::Requirement
|
113
|
+
none: false
|
114
|
+
requirements:
|
115
|
+
- - ~>
|
116
|
+
- !ruby/object:Gem::Version
|
117
|
+
version: '2.0'
|
118
|
+
type: :development
|
119
|
+
prerelease: false
|
120
|
+
version_requirements: !ruby/object:Gem::Requirement
|
121
|
+
none: false
|
122
|
+
requirements:
|
123
|
+
- - ~>
|
124
|
+
- !ruby/object:Gem::Version
|
125
|
+
version: '2.0'
|
126
|
+
- !ruby/object:Gem::Dependency
|
127
|
+
name: rb-fsevent
|
128
|
+
requirement: !ruby/object:Gem::Requirement
|
129
|
+
none: false
|
130
|
+
requirements:
|
131
|
+
- - ~>
|
132
|
+
- !ruby/object:Gem::Version
|
133
|
+
version: '0.9'
|
134
|
+
type: :development
|
135
|
+
prerelease: false
|
136
|
+
version_requirements: !ruby/object:Gem::Requirement
|
137
|
+
none: false
|
138
|
+
requirements:
|
139
|
+
- - ~>
|
140
|
+
- !ruby/object:Gem::Version
|
141
|
+
version: '0.9'
|
142
|
+
- !ruby/object:Gem::Dependency
|
143
|
+
name: fuubar
|
144
|
+
requirement: !ruby/object:Gem::Requirement
|
145
|
+
none: false
|
146
|
+
requirements:
|
147
|
+
- - ~>
|
148
|
+
- !ruby/object:Gem::Version
|
149
|
+
version: '1.1'
|
150
|
+
type: :development
|
151
|
+
prerelease: false
|
152
|
+
version_requirements: !ruby/object:Gem::Requirement
|
153
|
+
none: false
|
154
|
+
requirements:
|
155
|
+
- - ~>
|
156
|
+
- !ruby/object:Gem::Version
|
157
|
+
version: '1.1'
|
158
|
+
- !ruby/object:Gem::Dependency
|
159
|
+
name: redcarpet
|
160
|
+
requirement: !ruby/object:Gem::Requirement
|
161
|
+
none: false
|
162
|
+
requirements:
|
163
|
+
- - ~>
|
164
|
+
- !ruby/object:Gem::Version
|
165
|
+
version: 2.2.2
|
166
|
+
type: :development
|
167
|
+
prerelease: false
|
168
|
+
version_requirements: !ruby/object:Gem::Requirement
|
169
|
+
none: false
|
170
|
+
requirements:
|
171
|
+
- - ~>
|
172
|
+
- !ruby/object:Gem::Version
|
173
|
+
version: 2.2.2
|
174
|
+
- !ruby/object:Gem::Dependency
|
175
|
+
name: github-markup
|
176
|
+
requirement: !ruby/object:Gem::Requirement
|
177
|
+
none: false
|
178
|
+
requirements:
|
179
|
+
- - ~>
|
180
|
+
- !ruby/object:Gem::Version
|
181
|
+
version: '0.7'
|
182
|
+
type: :development
|
183
|
+
prerelease: false
|
184
|
+
version_requirements: !ruby/object:Gem::Requirement
|
185
|
+
none: false
|
186
|
+
requirements:
|
187
|
+
- - ~>
|
188
|
+
- !ruby/object:Gem::Version
|
189
|
+
version: '0.7'
|
190
|
+
description: ! "# Brainfucktt\n\nA [Brainfuck][brainfuck] interpreter built in [Ruby][ruby]
|
191
|
+
using [Treetop][treetop].\n\nBrainfuck is an eight-instruction turing-clomplete
|
192
|
+
programming language created in 1993\nby Urban Müller, based on the more formal
|
193
|
+
programming language [P′′][p''] created by Corrado\nBöhm in 1964.\n\nIt is designed
|
194
|
+
to challenge and amuse programmers, and is not made to be suitable for \npractical
|
195
|
+
use.\n\n## Install\n\n### Bundler: `gem 'brainfucktt'`\n\n### RubyGems: `gem install
|
196
|
+
brainfucktt`\n\n## Brainfuck Instructions\n\n`>` Increment the data pointer (to
|
197
|
+
point to the next cell to the right).\n\n`<` Decrement the data pointer (to point
|
198
|
+
to the next cell to the left).\n\n`+` Increment (increase by one) the byte at the
|
199
|
+
data pointer.\n\n`-` Decrement (decrease by one) the byte at the data pointer.\n\n`.`
|
200
|
+
Output the byte at the data pointer as an ASCII encoded character.\n\n`,` Accept
|
201
|
+
one byte of input, storing its value in the byte at the data pointer.\n\n`[` If
|
202
|
+
the byte at the data pointer is zero, then instead of moving the instruction pointer
|
203
|
+
forward to the next command, jump it forward to the command after the matching `]`
|
204
|
+
command.\n\n`]` If the byte at the data pointer is nonzero, then instead of moving
|
205
|
+
the instruction pointer forward to the next command, jump it back to the command
|
206
|
+
after the matching `[` command.\n\n### Comments\n\nAny character besides one of
|
207
|
+
the 8 instructions above is not parsed and will be regarded as a comment.\n\n##
|
208
|
+
Usage\n\n### Running\n\n```ruby\nrequire 'brainfucktt'\n\n# \"Hello World!\" written
|
209
|
+
in Brainfuck\ncode = '++++++++++[>+++++++>++++++++++>+++>+<<<<-]>++.>+.+++++++..+++.>++.<<+++++++++++++++.>.+++.------.--------.>+.>.'\n\nBrainfucktt.run(code)\n```\n\n###
|
210
|
+
Parsing\n\n```ruby\nrequire 'brainfucktt'\n\n# \"Hello World!\" written in Brainfuck\ncode
|
211
|
+
= '++++++++++[>+++++++>++++++++++>+++>+<<<<-]>++.>+.+++++++..+++.>++.<<+++++++++++++++.>.+++.------.--------.>+.>.'\nparser
|
212
|
+
= Brainfucktt.parse(code)\n\n# Print out the AST of the code\np parser.tree\n\n#
|
213
|
+
Run the code within Ruby\nparser.run\n```\n\n### StringIO\n\nSometimes you do now
|
214
|
+
want to use STDIN or STDOUT for the I/O of the Brainfuck program.\n\nTo do that,
|
215
|
+
you must use the stdlib `stringio`:\n\n```ruby\nrequire 'brainfucktt'\nrequire 'stringio'\n\n#
|
216
|
+
\"Hello World!\" written in Brainfuck\ncode = '++++++++++[>+++++++>++++++++++>+++>+<<<<-]>++.>+.+++++++..+++.>++.<<+++++++++++++++.>.+++.------.--------.>+.>.'\n\noutput
|
217
|
+
= StringIO.new\nBrainfucktt.run(code, output: output)\n\np output.string # => \"Hello
|
218
|
+
World!\\n\"\n```\n\n## Copyright\n\nCopyright © 2012 Ryan Scott Lewis <ryan@rynet.us>.\n\nThe
|
219
|
+
MIT License (MIT) - See LICENSE for further details.\n\n[brainfuck]: http://www.muppetlabs.com/~breadbox/bf/\n[ruby]:
|
220
|
+
http://ruby-lang.org\n[treetop]: http://treetop.rubyforge.org\n[p'']: http://en.wikipedia.org/wiki/P%E2%80%B2%E2%80%B2"
|
221
|
+
email: ryan@rynet.us
|
222
|
+
executables: []
|
223
|
+
extensions: []
|
224
|
+
extra_rdoc_files: []
|
225
|
+
files:
|
226
|
+
- Gemfile
|
227
|
+
- LICENSE
|
228
|
+
- README.md
|
229
|
+
- Rakefile
|
230
|
+
- VERSION
|
231
|
+
- brainfucktt.gemspec
|
232
|
+
- examples/hello_world.rb
|
233
|
+
- examples/hello_world_with_comments.rb
|
234
|
+
- examples/stringio.rb
|
235
|
+
- lib/brainfucktt.rb
|
236
|
+
- lib/brainfucktt/byte.rb
|
237
|
+
- lib/brainfucktt/conversion_helpers.rb
|
238
|
+
- lib/brainfucktt/data.rb
|
239
|
+
- lib/brainfucktt/errors.rb
|
240
|
+
- lib/brainfucktt/language.rb
|
241
|
+
- lib/brainfucktt/language/decrement_byte.rb
|
242
|
+
- lib/brainfucktt/language/decrement_pointer.rb
|
243
|
+
- lib/brainfucktt/language/increment_byte.rb
|
244
|
+
- lib/brainfucktt/language/increment_pointer.rb
|
245
|
+
- lib/brainfucktt/language/input_byte.rb
|
246
|
+
- lib/brainfucktt/language/loop.rb
|
247
|
+
- lib/brainfucktt/language/output_byte.rb
|
248
|
+
- lib/brainfucktt/language/tree.rb
|
249
|
+
- lib/brainfucktt/language_parser.treetop
|
250
|
+
- lib/brainfucktt/node.rb
|
251
|
+
- lib/brainfucktt/parser.rb
|
252
|
+
homepage: http://github.com/RyanScottLewis/brainfucktt
|
253
|
+
licenses: []
|
254
|
+
post_install_message:
|
255
|
+
rdoc_options: []
|
256
|
+
require_paths:
|
257
|
+
- lib
|
258
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
259
|
+
none: false
|
260
|
+
requirements:
|
261
|
+
- - ! '>='
|
262
|
+
- !ruby/object:Gem::Version
|
263
|
+
version: '0'
|
264
|
+
segments:
|
265
|
+
- 0
|
266
|
+
hash: -1616283130574261905
|
267
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
268
|
+
none: false
|
269
|
+
requirements:
|
270
|
+
- - ! '>='
|
271
|
+
- !ruby/object:Gem::Version
|
272
|
+
version: '0'
|
273
|
+
requirements: []
|
274
|
+
rubyforge_project:
|
275
|
+
rubygems_version: 1.8.24
|
276
|
+
signing_key:
|
277
|
+
specification_version: 3
|
278
|
+
summary: A Brainfuck interpreter built in Ruby using Treetop.
|
279
|
+
test_files: []
|