brainfuck-rb 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/bin/brainfuck +11 -0
- data/lib/brainfuck-rb.rb +7 -0
- data/lib/lang/interpreter.rb +59 -0
- data/lib/lang/lexer.rb +26 -0
- data/lib/lang/nodes.rb +13 -0
- data/lib/lang/parser.rb +234 -0
- data/lib/lang/runtime.rb +40 -0
- metadata +51 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 61f75a20af1bb4192279cd1c93009d9fa54c91e9
|
4
|
+
data.tar.gz: 7d8a008799e664f0da54acee9ae7a4661c28ee1c
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: b1171d7277b7d96a441f78e2a778c235a03625491a1a8601ccc11705296f484a64b94859dd08ed2c4af3a330b1c3a31b1c2adfe1b925c89519d69961692937a1
|
7
|
+
data.tar.gz: 4b7f3805fa508659c7f7132c4d22bf90944ea8564aa6a49c4e666c50448b311cd5bfcbd20e7c221b51d146c9421b736aedbce1368985bef8de3084f8139cfffb
|
data/bin/brainfuck
ADDED
data/lib/brainfuck-rb.rb
ADDED
@@ -0,0 +1,59 @@
|
|
1
|
+
require "io/console"
|
2
|
+
require "lang/parser"
|
3
|
+
require "lang/runtime"
|
4
|
+
|
5
|
+
module Brainfuck
|
6
|
+
class Interpreter
|
7
|
+
def initialize
|
8
|
+
@parser = Parser.new
|
9
|
+
@runtime = Runtime.new
|
10
|
+
end
|
11
|
+
|
12
|
+
def eval(code, show_nodes = false)
|
13
|
+
nodes = @parser.parse(code)
|
14
|
+
p nodes if show_nodes
|
15
|
+
nodes.eval(@runtime)
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
class Nodes
|
20
|
+
def eval(runtime)
|
21
|
+
nodes.each do |node|
|
22
|
+
node.eval(runtime)
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
class ShiftNode
|
28
|
+
def eval(runtime)
|
29
|
+
runtime.shift(direction)
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
class OperationNode
|
34
|
+
def eval(runtime)
|
35
|
+
runtime.mutate(type)
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
class LoopNode
|
40
|
+
def eval(runtime)
|
41
|
+
loop do
|
42
|
+
loop_body.eval(runtime)
|
43
|
+
break if runtime.value == 0
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
class ReadNode
|
49
|
+
def eval(runtime)
|
50
|
+
runtime.value = $stdin.getch.ord
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
class PrintNode
|
55
|
+
def eval(runtime)
|
56
|
+
print runtime.value.chr
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
data/lib/lang/lexer.rb
ADDED
@@ -0,0 +1,26 @@
|
|
1
|
+
module Brainfuck
|
2
|
+
class Lexer
|
3
|
+
class << self
|
4
|
+
OPERATORS = ['>', '<', '+', '-', '[', ']', ',', '.']
|
5
|
+
def tokenize(code)
|
6
|
+
tokens = []
|
7
|
+
unless code && code.length > 0
|
8
|
+
tokens
|
9
|
+
end
|
10
|
+
i = 0
|
11
|
+
while i < code.length
|
12
|
+
case code[i..-1]
|
13
|
+
when /\A(\s+)/
|
14
|
+
i += $1.length # ignore whitespace
|
15
|
+
when /\A(.)/
|
16
|
+
if OPERATORS.include? $1
|
17
|
+
tokens << [$1, $1]
|
18
|
+
end # Comment is anything other than operators, so ignore
|
19
|
+
i += 1
|
20
|
+
end
|
21
|
+
end
|
22
|
+
tokens
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
data/lib/lang/nodes.rb
ADDED
@@ -0,0 +1,13 @@
|
|
1
|
+
module Brainfuck
|
2
|
+
class Nodes < Struct.new(:nodes)
|
3
|
+
def <<(node)
|
4
|
+
nodes << node
|
5
|
+
self
|
6
|
+
end
|
7
|
+
end
|
8
|
+
class ShiftNode < Struct.new(:direction); end
|
9
|
+
class OperationNode < Struct.new(:type); end
|
10
|
+
class LoopNode < Struct.new(:loop_body); end
|
11
|
+
class ReadNode; end
|
12
|
+
class PrintNode; end
|
13
|
+
end
|
data/lib/lang/parser.rb
ADDED
@@ -0,0 +1,234 @@
|
|
1
|
+
#
|
2
|
+
# DO NOT MODIFY!!!!
|
3
|
+
# This file is automatically generated by Racc 1.4.9
|
4
|
+
# from Racc grammer file "".
|
5
|
+
#
|
6
|
+
|
7
|
+
require 'racc/parser.rb'
|
8
|
+
|
9
|
+
require "lang/lexer"
|
10
|
+
require "lang/nodes"
|
11
|
+
|
12
|
+
module Brainfuck
|
13
|
+
|
14
|
+
class Parser < Racc::Parser
|
15
|
+
|
16
|
+
module_eval(<<'...end grammer.y/module_eval...', 'grammer.y', 46)
|
17
|
+
def parse(code, show_tokens = false)
|
18
|
+
@tokens = Lexer.tokenize(code)
|
19
|
+
p @tokens if show_tokens
|
20
|
+
do_parse
|
21
|
+
end
|
22
|
+
|
23
|
+
def next_token
|
24
|
+
@tokens.shift
|
25
|
+
end
|
26
|
+
...end grammer.y/module_eval...
|
27
|
+
##### State transition tables begin ###
|
28
|
+
|
29
|
+
racc_action_table = [
|
30
|
+
8, 9, 10, 18, 11, 12, 13, 14, 8, 9,
|
31
|
+
10, 19, 11, 12, 13, 14, 8, 9, 10, 15,
|
32
|
+
11, 12, 13, 14, 8, 9, 10, nil, 11, 12,
|
33
|
+
13, 14 ]
|
34
|
+
|
35
|
+
racc_action_check = [
|
36
|
+
0, 0, 0, 15, 0, 0, 0, 0, 17, 17,
|
37
|
+
17, 17, 17, 17, 17, 17, 2, 2, 2, 1,
|
38
|
+
2, 2, 2, 2, 10, 10, 10, nil, 10, 10,
|
39
|
+
10, 10 ]
|
40
|
+
|
41
|
+
racc_action_pointer = [
|
42
|
+
-2, 19, 14, nil, nil, nil, nil, nil, nil, nil,
|
43
|
+
22, nil, nil, nil, nil, 3, nil, 6, nil, nil ]
|
44
|
+
|
45
|
+
racc_action_default = [
|
46
|
+
-1, -16, -2, -3, -5, -6, -7, -8, -9, -10,
|
47
|
+
-16, -12, -13, -14, -15, -16, -4, -16, 20, -11 ]
|
48
|
+
|
49
|
+
racc_goto_table = [
|
50
|
+
16, 2, 1, nil, nil, nil, nil, nil, nil, nil,
|
51
|
+
nil, 17, nil, nil, nil, 16 ]
|
52
|
+
|
53
|
+
racc_goto_check = [
|
54
|
+
3, 2, 1, nil, nil, nil, nil, nil, nil, nil,
|
55
|
+
nil, 2, nil, nil, nil, 3 ]
|
56
|
+
|
57
|
+
racc_goto_pointer = [
|
58
|
+
nil, 2, 1, -2, nil, nil, nil, nil ]
|
59
|
+
|
60
|
+
racc_goto_default = [
|
61
|
+
nil, nil, nil, 3, 4, 5, 6, 7 ]
|
62
|
+
|
63
|
+
racc_reduce_table = [
|
64
|
+
0, 0, :racc_error,
|
65
|
+
0, 11, :_reduce_1,
|
66
|
+
1, 11, :_reduce_2,
|
67
|
+
1, 12, :_reduce_3,
|
68
|
+
2, 12, :_reduce_4,
|
69
|
+
1, 13, :_reduce_none,
|
70
|
+
1, 13, :_reduce_none,
|
71
|
+
1, 13, :_reduce_none,
|
72
|
+
1, 13, :_reduce_none,
|
73
|
+
1, 14, :_reduce_9,
|
74
|
+
1, 14, :_reduce_10,
|
75
|
+
3, 15, :_reduce_11,
|
76
|
+
1, 16, :_reduce_12,
|
77
|
+
1, 16, :_reduce_13,
|
78
|
+
1, 17, :_reduce_14,
|
79
|
+
1, 17, :_reduce_15 ]
|
80
|
+
|
81
|
+
racc_reduce_n = 16
|
82
|
+
|
83
|
+
racc_shift_n = 20
|
84
|
+
|
85
|
+
racc_token_table = {
|
86
|
+
false => 0,
|
87
|
+
:error => 1,
|
88
|
+
">" => 2,
|
89
|
+
"<" => 3,
|
90
|
+
"[" => 4,
|
91
|
+
"]" => 5,
|
92
|
+
"," => 6,
|
93
|
+
"." => 7,
|
94
|
+
"+" => 8,
|
95
|
+
"-" => 9 }
|
96
|
+
|
97
|
+
racc_nt_base = 10
|
98
|
+
|
99
|
+
racc_use_result_var = true
|
100
|
+
|
101
|
+
Racc_arg = [
|
102
|
+
racc_action_table,
|
103
|
+
racc_action_check,
|
104
|
+
racc_action_default,
|
105
|
+
racc_action_pointer,
|
106
|
+
racc_goto_table,
|
107
|
+
racc_goto_check,
|
108
|
+
racc_goto_default,
|
109
|
+
racc_goto_pointer,
|
110
|
+
racc_nt_base,
|
111
|
+
racc_reduce_table,
|
112
|
+
racc_token_table,
|
113
|
+
racc_shift_n,
|
114
|
+
racc_reduce_n,
|
115
|
+
racc_use_result_var ]
|
116
|
+
|
117
|
+
Racc_token_to_s_table = [
|
118
|
+
"$end",
|
119
|
+
"error",
|
120
|
+
"\">\"",
|
121
|
+
"\"<\"",
|
122
|
+
"\"[\"",
|
123
|
+
"\"]\"",
|
124
|
+
"\",\"",
|
125
|
+
"\".\"",
|
126
|
+
"\"+\"",
|
127
|
+
"\"-\"",
|
128
|
+
"$start",
|
129
|
+
"Program",
|
130
|
+
"Expressions",
|
131
|
+
"Expression",
|
132
|
+
"Shift",
|
133
|
+
"Loop",
|
134
|
+
"InputOutput",
|
135
|
+
"Operation" ]
|
136
|
+
|
137
|
+
Racc_debug_parser = false
|
138
|
+
|
139
|
+
##### State transition tables end #####
|
140
|
+
|
141
|
+
# reduce 0 omitted
|
142
|
+
|
143
|
+
module_eval(<<'.,.,', 'grammer.y', 4)
|
144
|
+
def _reduce_1(val, _values, result)
|
145
|
+
result = Nodes.new([])
|
146
|
+
result
|
147
|
+
end
|
148
|
+
.,.,
|
149
|
+
|
150
|
+
module_eval(<<'.,.,', 'grammer.y', 5)
|
151
|
+
def _reduce_2(val, _values, result)
|
152
|
+
result = val[0]
|
153
|
+
result
|
154
|
+
end
|
155
|
+
.,.,
|
156
|
+
|
157
|
+
module_eval(<<'.,.,', 'grammer.y', 9)
|
158
|
+
def _reduce_3(val, _values, result)
|
159
|
+
result = Nodes.new(val)
|
160
|
+
result
|
161
|
+
end
|
162
|
+
.,.,
|
163
|
+
|
164
|
+
module_eval(<<'.,.,', 'grammer.y', 10)
|
165
|
+
def _reduce_4(val, _values, result)
|
166
|
+
result = val[0] << val[1]
|
167
|
+
result
|
168
|
+
end
|
169
|
+
.,.,
|
170
|
+
|
171
|
+
# reduce 5 omitted
|
172
|
+
|
173
|
+
# reduce 6 omitted
|
174
|
+
|
175
|
+
# reduce 7 omitted
|
176
|
+
|
177
|
+
# reduce 8 omitted
|
178
|
+
|
179
|
+
module_eval(<<'.,.,', 'grammer.y', 21)
|
180
|
+
def _reduce_9(val, _values, result)
|
181
|
+
result = ShiftNode.new(:right)
|
182
|
+
result
|
183
|
+
end
|
184
|
+
.,.,
|
185
|
+
|
186
|
+
module_eval(<<'.,.,', 'grammer.y', 22)
|
187
|
+
def _reduce_10(val, _values, result)
|
188
|
+
result = ShiftNode.new(:left)
|
189
|
+
result
|
190
|
+
end
|
191
|
+
.,.,
|
192
|
+
|
193
|
+
module_eval(<<'.,.,', 'grammer.y', 26)
|
194
|
+
def _reduce_11(val, _values, result)
|
195
|
+
result = LoopNode.new(val[1])
|
196
|
+
result
|
197
|
+
end
|
198
|
+
.,.,
|
199
|
+
|
200
|
+
module_eval(<<'.,.,', 'grammer.y', 30)
|
201
|
+
def _reduce_12(val, _values, result)
|
202
|
+
result = ReadNode.new
|
203
|
+
result
|
204
|
+
end
|
205
|
+
.,.,
|
206
|
+
|
207
|
+
module_eval(<<'.,.,', 'grammer.y', 31)
|
208
|
+
def _reduce_13(val, _values, result)
|
209
|
+
result = PrintNode.new
|
210
|
+
result
|
211
|
+
end
|
212
|
+
.,.,
|
213
|
+
|
214
|
+
module_eval(<<'.,.,', 'grammer.y', 35)
|
215
|
+
def _reduce_14(val, _values, result)
|
216
|
+
result = OperationNode.new(:incr)
|
217
|
+
result
|
218
|
+
end
|
219
|
+
.,.,
|
220
|
+
|
221
|
+
module_eval(<<'.,.,', 'grammer.y', 36)
|
222
|
+
def _reduce_15(val, _values, result)
|
223
|
+
result = OperationNode.new(:decr)
|
224
|
+
result
|
225
|
+
end
|
226
|
+
.,.,
|
227
|
+
|
228
|
+
def _reduce_none(val, _values, result)
|
229
|
+
val[0]
|
230
|
+
end
|
231
|
+
|
232
|
+
end # class Parser
|
233
|
+
|
234
|
+
end # module Brainfuck
|
data/lib/lang/runtime.rb
ADDED
@@ -0,0 +1,40 @@
|
|
1
|
+
module Brainfuck
|
2
|
+
class Runtime
|
3
|
+
def initialize
|
4
|
+
@cells = [0]
|
5
|
+
@current_cell = 0
|
6
|
+
end
|
7
|
+
|
8
|
+
def shift(direction)
|
9
|
+
case direction
|
10
|
+
when :right
|
11
|
+
@current_cell += 1
|
12
|
+
if @current_cell > @cells.length - 1
|
13
|
+
@cells << 0
|
14
|
+
end
|
15
|
+
when :left
|
16
|
+
@current_cell -= 1
|
17
|
+
if @current_cell < 0
|
18
|
+
@current_cell = 0
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
def mutate(how)
|
24
|
+
case how
|
25
|
+
when :incr
|
26
|
+
@cells[@current_cell] += 1
|
27
|
+
when :decr
|
28
|
+
@cells[@current_cell] -= 1
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
def value
|
33
|
+
@cells[@current_cell]
|
34
|
+
end
|
35
|
+
|
36
|
+
def value=(value)
|
37
|
+
@cells[@current_cell] = value
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
metadata
ADDED
@@ -0,0 +1,51 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: brainfuck-rb
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 1.0.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Brandon Buck
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2013-07-22 00:00:00.000000000 Z
|
12
|
+
dependencies: []
|
13
|
+
description: Small and simple Brainfuck interpreter written in Ruby
|
14
|
+
email: lordizuriel@gmail.com
|
15
|
+
executables:
|
16
|
+
- brainfuck
|
17
|
+
extensions: []
|
18
|
+
extra_rdoc_files: []
|
19
|
+
files:
|
20
|
+
- lib/brainfuck-rb.rb
|
21
|
+
- lib/lang/lexer.rb
|
22
|
+
- lib/lang/parser.rb
|
23
|
+
- lib/lang/nodes.rb
|
24
|
+
- lib/lang/runtime.rb
|
25
|
+
- lib/lang/interpreter.rb
|
26
|
+
- bin/brainfuck
|
27
|
+
homepage: http://github.com/bbuck/brainfuck-rb
|
28
|
+
licenses:
|
29
|
+
- MIT
|
30
|
+
metadata: {}
|
31
|
+
post_install_message:
|
32
|
+
rdoc_options: []
|
33
|
+
require_paths:
|
34
|
+
- lib
|
35
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
36
|
+
requirements:
|
37
|
+
- - '>='
|
38
|
+
- !ruby/object:Gem::Version
|
39
|
+
version: '0'
|
40
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
41
|
+
requirements:
|
42
|
+
- - '>='
|
43
|
+
- !ruby/object:Gem::Version
|
44
|
+
version: '0'
|
45
|
+
requirements: []
|
46
|
+
rubyforge_project:
|
47
|
+
rubygems_version: 2.0.3
|
48
|
+
signing_key:
|
49
|
+
specification_version: 4
|
50
|
+
summary: Brainfuck interpreter written in Ruby
|
51
|
+
test_files: []
|