bfunj 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.tar.gz.sig +3 -0
- data/Manifest +14 -0
- data/README +24 -0
- data/Rakefile +10 -0
- data/bfunj.gemspec +31 -0
- data/data/test/10.bfunj +3 -0
- data/data/test/100.bfunj +1 -0
- data/data/test/120.bfunj +3 -0
- data/data/test/3.bfunj +1 -0
- data/data/test/4.bfunj +5 -0
- data/data/test/5.bfunj +1 -0
- data/data/test/5000.bfunj +1 -0
- data/data/test/7.bfunj +2 -0
- data/lib/bfunj.rb +190 -0
- data/spec/bfunj_spec.rb +30 -0
- data/spec/stack_spec.rb +10 -0
- metadata +97 -0
- metadata.gz.sig +0 -0
data.tar.gz.sig
ADDED
data/Manifest
ADDED
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
README
|
|
2
|
+
data/test/10.bfunj
|
|
3
|
+
data/test/100.bfunj
|
|
4
|
+
data/test/120.bfunj
|
|
5
|
+
data/test/3.bfunj
|
|
6
|
+
data/test/4.bfunj
|
|
7
|
+
data/test/5.bfunj
|
|
8
|
+
data/test/5000.bfunj
|
|
9
|
+
data/test/7.bfunj
|
|
10
|
+
lib/bfunj.rb
|
|
11
|
+
spec/bfunj_spec.rb
|
|
12
|
+
spec/stack_spec.rb
|
|
13
|
+
Rakefile
|
|
14
|
+
Manifest
|
data/README
ADDED
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
bfunj is a slightly altered Befunge-93 interpreter written in Ruby.
|
|
2
|
+
|
|
3
|
+
The official Befunge-93 specification can be found at http://catseye.tc/projects/befunge93/doc/website_befunge93.html
|
|
4
|
+
|
|
5
|
+
The differences between Befunge-93 and bfunj are listed below:
|
|
6
|
+
|
|
7
|
+
- " command is removed
|
|
8
|
+
- , command is removed
|
|
9
|
+
- ~ command is removed
|
|
10
|
+
- g command is removed
|
|
11
|
+
- p command is removed
|
|
12
|
+
|
|
13
|
+
How to use:
|
|
14
|
+
b = BFunj.new()
|
|
15
|
+
b.load_file 'filename.bfunj'
|
|
16
|
+
b.run
|
|
17
|
+
puts b.stack.inspect
|
|
18
|
+
|
|
19
|
+
Options that can be passed to #new:
|
|
20
|
+
|
|
21
|
+
:input_stream - Defines the input stream, must be a kind_of?(IO). Default is $stdin
|
|
22
|
+
:output_stream - Defines the output stream, must be a kind_of?(IO). Default is $stdout
|
|
23
|
+
:max_steps - The maximum number of steps to take before program is forced to halt. this prevents infinite loops if. Default is 0 (never force halt).
|
|
24
|
+
:filename - Auto-loads the given filename. Default is empty and you must manually load a file with #load_file.
|
data/Rakefile
ADDED
data/bfunj.gemspec
ADDED
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
|
2
|
+
|
|
3
|
+
Gem::Specification.new do |s|
|
|
4
|
+
s.name = %q{bfunj}
|
|
5
|
+
s.version = "0.1.0"
|
|
6
|
+
|
|
7
|
+
s.required_rubygems_version = Gem::Requirement.new(">= 1.2") if s.respond_to? :required_rubygems_version=
|
|
8
|
+
s.authors = ["Dave Havlicek"]
|
|
9
|
+
s.cert_chain = ["/home/dhavlicek/gem-public_cert.pem"]
|
|
10
|
+
s.date = %q{2011-04-11}
|
|
11
|
+
s.description = %q{A Befunge interpreter.}
|
|
12
|
+
s.email = %q{xens@comcast.net}
|
|
13
|
+
s.extra_rdoc_files = ["README", "lib/bfunj.rb"]
|
|
14
|
+
s.files = ["README", "data/test/10.bfunj", "data/test/100.bfunj", "data/test/120.bfunj", "data/test/3.bfunj", "data/test/4.bfunj", "data/test/5.bfunj", "data/test/5000.bfunj", "data/test/7.bfunj", "lib/bfunj.rb", "spec/bfunj_spec.rb", "spec/stack_spec.rb", "Rakefile", "Manifest", "bfunj.gemspec"]
|
|
15
|
+
s.homepage = %q{http://bfunj.github.com/bfunj/}
|
|
16
|
+
s.rdoc_options = ["--line-numbers", "--inline-source", "--title", "Bfunj", "--main", "README"]
|
|
17
|
+
s.require_paths = ["lib"]
|
|
18
|
+
s.rubyforge_project = %q{bfunj}
|
|
19
|
+
s.rubygems_version = %q{1.6.0}
|
|
20
|
+
s.signing_key = %q{/home/dhavlicek/gem-private_key.pem}
|
|
21
|
+
s.summary = %q{A Befunge interpreter.}
|
|
22
|
+
|
|
23
|
+
if s.respond_to? :specification_version then
|
|
24
|
+
s.specification_version = 3
|
|
25
|
+
|
|
26
|
+
if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then
|
|
27
|
+
else
|
|
28
|
+
end
|
|
29
|
+
else
|
|
30
|
+
end
|
|
31
|
+
end
|
data/data/test/10.bfunj
ADDED
data/data/test/100.bfunj
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
>1L@
|
data/data/test/120.bfunj
ADDED
data/data/test/3.bfunj
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
>12+@
|
data/data/test/5.bfunj
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
>&@
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
>1
|
data/data/test/7.bfunj
ADDED
data/lib/bfunj.rb
ADDED
|
@@ -0,0 +1,190 @@
|
|
|
1
|
+
class Stack < Array
|
|
2
|
+
|
|
3
|
+
def pop
|
|
4
|
+
return 0 if self.empty?
|
|
5
|
+
super
|
|
6
|
+
end
|
|
7
|
+
|
|
8
|
+
end
|
|
9
|
+
|
|
10
|
+
class BFunj
|
|
11
|
+
COMMAND_MAP = { '>' => :go_left,
|
|
12
|
+
'<' => :go_right,
|
|
13
|
+
'^' => :go_up,
|
|
14
|
+
'v' => :go_down,
|
|
15
|
+
'?' => :go_random,
|
|
16
|
+
'_' => :horizontal_if,
|
|
17
|
+
'|' => :vertical_if,
|
|
18
|
+
'+' => :add,
|
|
19
|
+
'-' => :subtract,
|
|
20
|
+
'*' => :multiply,
|
|
21
|
+
'/' => :divide,
|
|
22
|
+
'%' => :modulo,
|
|
23
|
+
'!' => :negate,
|
|
24
|
+
'`' => :test_greater_than,
|
|
25
|
+
':' => :duplicate,
|
|
26
|
+
'\\' => :swap,
|
|
27
|
+
'$' => :discard,
|
|
28
|
+
'#' => :skip,
|
|
29
|
+
'&' => :input,
|
|
30
|
+
'.' => :output,
|
|
31
|
+
'@' => :stop }.freeze
|
|
32
|
+
|
|
33
|
+
attr_reader :stack, :program
|
|
34
|
+
|
|
35
|
+
def initialize options = {}
|
|
36
|
+
@pc = { :row => 0, :col => 0 }
|
|
37
|
+
@direction = :left
|
|
38
|
+
@distance = 1
|
|
39
|
+
@stack = Stack.new
|
|
40
|
+
@max_steps = options[:max_steps] || 0
|
|
41
|
+
@input_stream = options[:input_stream] || $stdin
|
|
42
|
+
@output_stream = options[:output_stream] || $stdout
|
|
43
|
+
load_file(options[:filename]) if options[:filename]
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
def load_file filename
|
|
47
|
+
@program = File.open(filename).readlines.map { |l| l.chomp }
|
|
48
|
+
@height = @program.size
|
|
49
|
+
@width = @program[0].size
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
def run
|
|
53
|
+
steps = 0
|
|
54
|
+
@done = false
|
|
55
|
+
loop do
|
|
56
|
+
@distance = 1
|
|
57
|
+
command = @program[@pc[:row]][@pc[:col]]
|
|
58
|
+
process_command command
|
|
59
|
+
advance_pc
|
|
60
|
+
if @max_steps != 0
|
|
61
|
+
steps += 1
|
|
62
|
+
break if steps > @max_steps || @done
|
|
63
|
+
end
|
|
64
|
+
end
|
|
65
|
+
end
|
|
66
|
+
|
|
67
|
+
private
|
|
68
|
+
|
|
69
|
+
def process_command command
|
|
70
|
+
if COMMAND_MAP.include? command
|
|
71
|
+
self.send COMMAND_MAP[command]
|
|
72
|
+
elsif command =~ /\d/
|
|
73
|
+
@stack.push command.to_s.to_i
|
|
74
|
+
else
|
|
75
|
+
#do nothing
|
|
76
|
+
end
|
|
77
|
+
end
|
|
78
|
+
|
|
79
|
+
def go_left
|
|
80
|
+
@direction = :left
|
|
81
|
+
end
|
|
82
|
+
|
|
83
|
+
def go_right
|
|
84
|
+
@direction = :right
|
|
85
|
+
end
|
|
86
|
+
|
|
87
|
+
def go_up
|
|
88
|
+
@direction = :up
|
|
89
|
+
end
|
|
90
|
+
|
|
91
|
+
def go_down
|
|
92
|
+
@direction = :down
|
|
93
|
+
end
|
|
94
|
+
|
|
95
|
+
def go_random
|
|
96
|
+
@direction = case rand(4)
|
|
97
|
+
when 0 then :left
|
|
98
|
+
when 1 then :right
|
|
99
|
+
when 2 then :up
|
|
100
|
+
when 3 then :down
|
|
101
|
+
end
|
|
102
|
+
end
|
|
103
|
+
|
|
104
|
+
def horizontal_if
|
|
105
|
+
@direction = (@stack.pop == 0) ? :right : :left
|
|
106
|
+
end
|
|
107
|
+
|
|
108
|
+
def vertical_if
|
|
109
|
+
@direction = (@stack.pop == 0) ? :down : :up
|
|
110
|
+
end
|
|
111
|
+
|
|
112
|
+
def add
|
|
113
|
+
@stack.push( @stack.pop + @stack.pop )
|
|
114
|
+
end
|
|
115
|
+
|
|
116
|
+
def subtract
|
|
117
|
+
first = @stack.pop
|
|
118
|
+
second = @stack.pop
|
|
119
|
+
@stack.push( second - first )
|
|
120
|
+
end
|
|
121
|
+
|
|
122
|
+
def multiply
|
|
123
|
+
@stack.push( @stack.pop * @stack.pop )
|
|
124
|
+
end
|
|
125
|
+
|
|
126
|
+
def divide
|
|
127
|
+
first = @stack.pop
|
|
128
|
+
second = @stack.pop
|
|
129
|
+
@stack.push( (first == 0) ? 0 : second / first )
|
|
130
|
+
end
|
|
131
|
+
|
|
132
|
+
def modulo
|
|
133
|
+
first = @stack.pop
|
|
134
|
+
second = @stack.pop
|
|
135
|
+
@stack.push( (first == 0) ? 0 : second % first )
|
|
136
|
+
end
|
|
137
|
+
|
|
138
|
+
def negate
|
|
139
|
+
@stack.push( @stack.pop == 0 ? 1 : 0 )
|
|
140
|
+
end
|
|
141
|
+
|
|
142
|
+
def test_greater_than
|
|
143
|
+
@stack.push( (@stack.pop > @stack.pop) ? 1 : 0 )
|
|
144
|
+
end
|
|
145
|
+
|
|
146
|
+
def duplicate
|
|
147
|
+
@stack.push( @stack.last )
|
|
148
|
+
end
|
|
149
|
+
|
|
150
|
+
def swap
|
|
151
|
+
first = @stack.pop
|
|
152
|
+
second = @stack.pop
|
|
153
|
+
@stack.push( first )
|
|
154
|
+
@stack.push( second )
|
|
155
|
+
end
|
|
156
|
+
|
|
157
|
+
def discard
|
|
158
|
+
@stack.pop
|
|
159
|
+
end
|
|
160
|
+
|
|
161
|
+
def skip
|
|
162
|
+
@distance = 2
|
|
163
|
+
end
|
|
164
|
+
|
|
165
|
+
def input
|
|
166
|
+
@stack.push( @input_stream.getc.to_i )
|
|
167
|
+
end
|
|
168
|
+
|
|
169
|
+
def output
|
|
170
|
+
@output_stream.puts( @stack.pop )
|
|
171
|
+
end
|
|
172
|
+
|
|
173
|
+
def stop
|
|
174
|
+
@done = true
|
|
175
|
+
end
|
|
176
|
+
|
|
177
|
+
def advance_pc
|
|
178
|
+
case @direction
|
|
179
|
+
when :left
|
|
180
|
+
@pc[:col] = (@pc[:col] + @distance) % @width
|
|
181
|
+
when :right
|
|
182
|
+
@pc[:col] = (@pc[:col] - @distance) % @width
|
|
183
|
+
when :up
|
|
184
|
+
@pc[:row] = (@pc[:row] - @distance) % @height
|
|
185
|
+
when :down
|
|
186
|
+
@pc[:row] = (@pc[:row] + @distance) % @height
|
|
187
|
+
end
|
|
188
|
+
end
|
|
189
|
+
|
|
190
|
+
end
|
data/spec/bfunj_spec.rb
ADDED
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
require 'bfunj'
|
|
2
|
+
|
|
3
|
+
describe BFunj do
|
|
4
|
+
before :all do
|
|
5
|
+
@bfunj = BFunj.new
|
|
6
|
+
@testfiles = Dir.glob("data/test/*.bfunj")
|
|
7
|
+
end
|
|
8
|
+
|
|
9
|
+
describe BFunj, "#load_file" do
|
|
10
|
+
it "loads a bfunj file" do
|
|
11
|
+
@bfunj.load_file @testfiles[0]
|
|
12
|
+
program = File.open(@testfiles[0]).readlines.map { |l| l.chomp }
|
|
13
|
+
@bfunj.program.should == program
|
|
14
|
+
end
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
describe BFunj, "#run" do
|
|
18
|
+
it "runs a bfunj program" do
|
|
19
|
+
@testfiles.each do |test_file|
|
|
20
|
+
bfunj = BFunj.new( { :input_stream => IO.popen( 'echo 5' ),
|
|
21
|
+
:output_stream => IO.new( IO.sysopen( '/dev/null', 'w' ), 'w' ),
|
|
22
|
+
:max_steps => 10000,
|
|
23
|
+
:filename => test_file } )
|
|
24
|
+
expected_result = File.basename(test_file, '.bfunj').to_i
|
|
25
|
+
bfunj.run
|
|
26
|
+
bfunj.stack.inject { |sum, acc| sum += acc }.should == expected_result
|
|
27
|
+
end
|
|
28
|
+
end
|
|
29
|
+
end
|
|
30
|
+
end
|
data/spec/stack_spec.rb
ADDED
metadata
ADDED
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
|
2
|
+
name: bfunj
|
|
3
|
+
version: !ruby/object:Gem::Version
|
|
4
|
+
prerelease:
|
|
5
|
+
version: 0.1.0
|
|
6
|
+
platform: ruby
|
|
7
|
+
authors:
|
|
8
|
+
- Dave Havlicek
|
|
9
|
+
autorequire:
|
|
10
|
+
bindir: bin
|
|
11
|
+
cert_chain:
|
|
12
|
+
- |
|
|
13
|
+
-----BEGIN CERTIFICATE-----
|
|
14
|
+
MIIDLjCCAhagAwIBAgIBADANBgkqhkiG9w0BAQUFADA9MQ0wCwYDVQQDDAR4ZW5z
|
|
15
|
+
MRcwFQYKCZImiZPyLGQBGRYHY29tY2FzdDETMBEGCgmSJomT8ixkARkWA25ldDAe
|
|
16
|
+
Fw0xMTA0MTEyMDQ5MzFaFw0xMjA0MTAyMDQ5MzFaMD0xDTALBgNVBAMMBHhlbnMx
|
|
17
|
+
FzAVBgoJkiaJk/IsZAEZFgdjb21jYXN0MRMwEQYKCZImiZPyLGQBGRYDbmV0MIIB
|
|
18
|
+
IjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA0lol2bUxDy2uqmJKj5hMFegc
|
|
19
|
+
9DQDfqgHGeFCHXAIpdJky6w+CIasGIMgTuNaKiIOw0/5WUVSXQdSF2fkhZc/yZY0
|
|
20
|
+
IDW4BibAip3CDsqrp20rtPaiXxyRGXPHhJgIcATyIawQNZ7aA0nINDrRyReLl1QH
|
|
21
|
+
xCHsqzbel6AJkjd5uWUnwIxG7NOpkflsUfvX9JaV42qHSg1QwA6Q7rChjqAJGZlm
|
|
22
|
+
tyGaSzRUIN/OU94hwun0ZbzYA9gAD+HfGiL+9+XL3COvIdtZqhIaznw8hChY0Bme
|
|
23
|
+
ZYJmhxYV5GGBlSiAU53DeqrcEUFYnrZ2+XNDf5P+5rqs+ZpVaPxsLvThvu0YcwID
|
|
24
|
+
AQABozkwNzAJBgNVHRMEAjAAMB0GA1UdDgQWBBSHc4Wiy9nu0WN/I5jbTn7N0jfx
|
|
25
|
+
NDALBgNVHQ8EBAMCBLAwDQYJKoZIhvcNAQEFBQADggEBAIMCMRokV2ssyq5qHxNn
|
|
26
|
+
d5MTGi64Q7l6BEEkAxnBliQcRGswIvJmqgIT+CxiUP8b11drDXmCEuDcYtNbw51X
|
|
27
|
+
GlA7wkva6HsFSB6p24dNZ+FWs7nMP0wEd6n+fKuPiQbuYJLnFSa72hVIo685HEPk
|
|
28
|
+
Ih4IhJs9/mSqgxvqPBYTEfS8V7TTkQD4tfOceuRhoBS3+/0Ncn6kmaJKAPmWBQav
|
|
29
|
+
aRkM3yE4qqz2sgY064cnW4ckXIsId3eX2hvdvTBmL1y2mnp+THa3MY6zXr7yqVJw
|
|
30
|
+
RPqDJqKZopdM+pobhXvrc1ObTAD5F3RlY8iCi7fCgS0rYi0D3mI9Esa3aPGihZNK
|
|
31
|
+
gMo=
|
|
32
|
+
-----END CERTIFICATE-----
|
|
33
|
+
|
|
34
|
+
date: 2011-04-11 00:00:00 -05:00
|
|
35
|
+
default_executable:
|
|
36
|
+
dependencies: []
|
|
37
|
+
|
|
38
|
+
description: A Befunge interpreter.
|
|
39
|
+
email: xens@comcast.net
|
|
40
|
+
executables: []
|
|
41
|
+
|
|
42
|
+
extensions: []
|
|
43
|
+
|
|
44
|
+
extra_rdoc_files:
|
|
45
|
+
- README
|
|
46
|
+
- lib/bfunj.rb
|
|
47
|
+
files:
|
|
48
|
+
- README
|
|
49
|
+
- data/test/10.bfunj
|
|
50
|
+
- data/test/100.bfunj
|
|
51
|
+
- data/test/120.bfunj
|
|
52
|
+
- data/test/3.bfunj
|
|
53
|
+
- data/test/4.bfunj
|
|
54
|
+
- data/test/5.bfunj
|
|
55
|
+
- data/test/5000.bfunj
|
|
56
|
+
- data/test/7.bfunj
|
|
57
|
+
- lib/bfunj.rb
|
|
58
|
+
- spec/bfunj_spec.rb
|
|
59
|
+
- spec/stack_spec.rb
|
|
60
|
+
- Rakefile
|
|
61
|
+
- Manifest
|
|
62
|
+
- bfunj.gemspec
|
|
63
|
+
has_rdoc: true
|
|
64
|
+
homepage: http://bfunj.github.com/bfunj/
|
|
65
|
+
licenses: []
|
|
66
|
+
|
|
67
|
+
post_install_message:
|
|
68
|
+
rdoc_options:
|
|
69
|
+
- --line-numbers
|
|
70
|
+
- --inline-source
|
|
71
|
+
- --title
|
|
72
|
+
- Bfunj
|
|
73
|
+
- --main
|
|
74
|
+
- README
|
|
75
|
+
require_paths:
|
|
76
|
+
- lib
|
|
77
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
|
78
|
+
none: false
|
|
79
|
+
requirements:
|
|
80
|
+
- - ">="
|
|
81
|
+
- !ruby/object:Gem::Version
|
|
82
|
+
version: "0"
|
|
83
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
|
84
|
+
none: false
|
|
85
|
+
requirements:
|
|
86
|
+
- - ">="
|
|
87
|
+
- !ruby/object:Gem::Version
|
|
88
|
+
version: "1.2"
|
|
89
|
+
requirements: []
|
|
90
|
+
|
|
91
|
+
rubyforge_project: bfunj
|
|
92
|
+
rubygems_version: 1.6.0
|
|
93
|
+
signing_key:
|
|
94
|
+
specification_version: 3
|
|
95
|
+
summary: A Befunge interpreter.
|
|
96
|
+
test_files: []
|
|
97
|
+
|
metadata.gz.sig
ADDED
|
Binary file
|