-
Notifications
You must be signed in to change notification settings - Fork 11
/
bfi.rb
executable file
·143 lines (116 loc) · 2.53 KB
/
bfi.rb
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
#!/usr/bin/env ruby
require './bfopt'
require './common'
class BFInt
def initialize(code, filename=nil)
@filename = filename
@code = code
@mp = 0
@mem = [0]
end
def check_bound
if @mp < 0
error(@loc, "memory pointer out of bound")
end
end
def alloc_mem
while @mp >= @mem.size
@mem << 0
end
end
def run
loop_stack = []
pc = 0
while @code[pc]
op, loc, args = @code[pc]
@op = op
@loc = loc
case op
when "+"
@mem[@mp] += 1
@mem[@mp] &= 255
when "-"
@mem[@mp] -= 1
@mem[@mp] &= 255
when ">"
@mp += 1
alloc_mem
when "<"
@mp -= 1
check_bound
when "["
if @mem[@mp] == 0
if args
pc = args
else
d = 1
while d > 0
pc += 1
case @code[pc][0]
when "["
d += 1
when "]"
d -= 1
when nil
error(@loc, "unmatched open paren")
end
end
end
else
loop_stack << pc
end
when "]"
if loop_stack.empty?
error(@loc, "unmatched close paren")
end
pc = loop_stack.pop - 1
when "."
putc @mem[@mp]
when ","
c = STDIN.read(1)
@mem[@mp] = c ? c.ord : 255
when "@"
if $verbose
a = []
[['PC', NPC], ['A', A], ['B', B], ['C', C], ['D', D],
['BP', BP], ['SP', SP]].each do |n, i|
v = @mem[i-1] * 65536 + @mem[i] * 256 + @mem[i+1]
if i == NPC
v -= 1
end
a << "#{n}=#{v}"
end
a << "mp=#{@mp}"
puts a * " "
mem = (-12..12).map{|i|
"#{i==0?"*":""}#{@mem[@mp+i]}"
}
puts mem * " "
STDOUT.flush
#wrks = (0..7).map{|i|@mem[WRK+i]}
#puts "mp=#{@mp} WRK=#{wrks*' '}"
#wrks = (0..7).map{|i|@mem[MEM+i]}
#puts "mp=#{@mp} MEM=#{wrks*' '}"
end
when :clear
@mem[@mp] = 0
when :add_mem
@mem[@mp] += args
@mem[@mp] &= 255
when :add_ptr
@mp += args
check_bound
alloc_mem
else
error(@loc, "unknown op: #{op}")
end
pc += 1
end
end
end
if $0 == __FILE__
filename = ARGV[0]
bfopt = BFOpt.new(File.read(filename), filename)
code = bfopt.optimize
BFInt.new(code, filename).run
end