-
Notifications
You must be signed in to change notification settings - Fork 11
/
Copy pathbfopt.rb
executable file
·128 lines (111 loc) · 2.33 KB
/
bfopt.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
#!/usr/bin/env ruby
class BFOpt
def initialize(code, filename=nil)
@filename = filename
@code = []
lineno = 1
column = 0
code.each_char{|b|
case b
when '+', '-', '>', '<', '[', ']', '.', ',', '@'
@code << [b, [@filename, lineno, column, 1]]
when "\n"
lineno += 1
column = -1
end
column += 1
}
match_loops
end
def match_loops
loop_stack = []
@code.each_with_index do |c, pc|
op, loc, *_ = *c
if op == '['
loop_stack << pc
elsif op == ']'
if loop_stack.empty?
error(loc, "unmatched close paren")
end
ppc = loop_stack.pop
c[2] = ppc
@code[ppc][2] = pc
end
end
if !loop_stack.empty?
error(@code[loop_stack.pop][1], "unmatched open paren")
end
end
def code
@code
end
def substr(st, ed)
code = @code[st...ed].map do |op, loc, *_|
if sym?(op)
error(loc, "cannot stringify internal operations: #{op}")
end
op
end * ''
loc = @code[st][1]
eloc = @code[ed-1][1]
loc[3] = eloc[2] + eloc[3] - loc[2]
[code, loc]
end
def optimize
optimize_loops
optimize_repetitions
match_loops
@code
end
def optimize_loops
optimized = []
i = 0
while @code[i]
c = @code[i]
if c[0] != '['
optimized << c
i += 1
next
end
loop_code, loc = substr(i, c[2]+1)
if loop_code == '[-]'
optimized << [:clear, loc]
i += loop_code.size
next
end
optimized << c
i += 1
end
@code = optimized
end
def optimize_repetitions
optimized = []
i = 0
while @code[i]
c = @code[i]
op, loc, args = c
done = false
[['+', '-', :add_mem],
['>', '<', :add_ptr]].each do |plus, minus, opt_op|
if op == plus || op == minus
j = i
while @code[j] && (@code[j][0] == plus || @code[j][0] == minus)
j += 1
end
code, loc = substr(i, j)
d = code.count(plus) - code.count(minus)
if d != 0
optimized << [opt_op, loc, d]
end
i += code.size
done = true
end
end
if !done
optimized << c
i += 1
end
end
@code = optimized
end
end