brainfucktt 0.1.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.
- 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: []
|