brainfuck-rb 1.0.0
Sign up to get free protection for your applications and to get access to all the features.
- 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: []
|