git @ Cat's Eye Technologies pibfi / rel_1_0_2003_0505
Initial import of pibfi version 1.0 revision 2003.0505 sources. catseye 12 years ago
57 changed file(s) with 4833 addition(s) and 0 deletion(s). Raw diff Collapse all Expand all
0 # erl -noshell -maxcell 65535 -wrapcell -xlatout #10#13=#nl -autopsy -statusevery 5m -run pibfi run http://www.people.fas.harvard.edu/~jafowler/pi/pi.b
1 pibfi: Platonic Ideal Brainf*ck Interpreter v2003.0505
2 Copyright (c)2003 Cat's Eye Technologies. All rights reserved.
3 Program file name: http://www.people.fas.harvard.edu/~jafowler/pi/pi.b
4 Parser options: heredoc=undefined statuscmd="#" optimize=1 dontstrip=[]
5 Tape options: wraptape=false mintape=0 maxtape=infinity wrapcell=true mincell=0 maxcell=65535 tapemodule=pibfi_tape_ets
6 I/O options: xlatin=["\n"="\n" ] xlatout=["\n\r"="\n" ] eof=0 wrapin=false minin=0 maxin=infinity wrapout=false minout=0 maxout=infinity outfile=tty infile=tty
7 Debug options: statusevery=300000
8 --------------BEGIN PROGRAM OUTPUT--------------
9 0
10 ===== STATUS REPORT ===== Mon May 5 2003, 20:38:42 =====
11 = Run began Mon May 5 2003, 20:33:42 duration 5 min 0 sec at mean kips 239
12 = Currently at line 162, col 15, instruction '[', whilelevel 6
13 = Exec tally: 5935215x(+) 5998202x(-) 22500864x(<) 22500870x(>)
14 = Exec tally: 0x(,) 3x(.) 7400131x([) 7400125x(])
15 + Tape head position: 7 cells right of start, cell contents: 105
16 + Tape observed head position: min 0, max 145, range 146
17 + Tape observed cell contents: min 0, max 65535, range 65536
18 + Tape contents (2 - 11 cells right of start):
19 #2 #3 #4 #5 #6 ->#7 #8 #9 #10 #11
20 312 20 22 1 1 105 376 43 0 0
21 ===== STATUS REPORT ===== Mon May 5 2003, 20:43:42 =====
22 = Run began Mon May 5 2003, 20:33:42 duration 10 min 0 sec at mean kips 209
23 = Currently at line 162, col 15, instruction '[', whilelevel 6
24 = Exec tally: 11857128x(+) 11920407x(-) 35868198x(<) 35868204x(>)
25 = Exec tally: 0x(,) 3x(.) 14814889x([) 14814883x(])
26 + Tape head position: 7 cells right of start, cell contents: 44
27 + Tape observed head position: min 0, max 145, range 146
28 + Tape observed cell contents: min 0, max 65535, range 65536
29 + Tape contents (2 - 11 cells right of start):
30 #2 #3 #4 #5 #6 ->#7 #8 #9 #10 #11
31 209 11 11 7 1 44 380 23 0 0
32 3
33 ===== STATUS REPORT ===== Mon May 5 2003, 20:48:42 =====
34 = Run began Mon May 5 2003, 20:33:42 duration 15 min 0 sec at mean kips 216
35 = Currently at line 162, col 15, instruction '[', whilelevel 6
36 = Exec tally: 17798122x(+) 17926744x(-) 57121132x(<) 57121138x(>)
37 = Exec tally: 0x(,) 6x(.) 22218742x([) 22218736x(])
38 + Tape head position: 7 cells right of start, cell contents: 142
39 + Tape observed head position: min 0, max 145, range 146
40 + Tape observed cell contents: min 0, max 65535, range 65536
41 + Tape contents (2 - 11 cells right of start):
42 #2 #3 #4 #5 #6 ->#7 #8 #9 #10 #11
43 161 9 47 3 1 142 378 57 0 0
44 ===== STATUS REPORT ===== Mon May 5 2003, 20:53:42 =====
45 = Run began Mon May 5 2003, 20:33:42 duration 20 min 0 sec at mean kips 206
46 = Currently at line 187, col 67, instruction '[', whilelevel 5
47 = Exec tally: 23789785x(+) 23917104x(-) 69978858x(<) 69978860x(>)
48 = Exec tally: 0x(,) 6x(.) 29710400x([) 29710395x(])
49 + Tape head position: 2 cells right of start, cell contents: 284
50 + Tape observed head position: min 0, max 145, range 146
51 + Tape observed cell contents: min 0, max 65535, range 65536
52 + Tape contents (0 - 6 cells right of start):
53 #0 #1 ->#2 #3 #4 #5 #6
54 0 7 284 38 12 10 0
55 ===== STATUS REPORT ===== Mon May 5 2003, 20:58:42 =====
56 = Run began Mon May 5 2003, 20:33:42 duration 25 min 0 sec at mean kips 200
57 = Currently at line 162, col 15, instruction '[', whilelevel 6
58 = Exec tally: 29783983x(+) 29912320x(-) 83278124x(<) 83278130x(>)
59 = Exec tally: 0x(,) 6x(.) 37211818x([) 37211812x(])
60 + Tape head position: 7 cells right of start, cell contents: 285
61 + Tape observed head position: min 0, max 145, range 146
62 + Tape observed cell contents: min 0, max 65535, range 65536
63 + Tape contents (2 - 11 cells right of start):
64 #2 #3 #4 #5 #6 ->#7 #8 #9 #10 #11
65 312 8 26 1 1 285 372 35 0 0
66 1
67 ===== STATUS REPORT ===== Mon May 5 2003, 21:03:42 =====
68 = Run began Mon May 5 2003, 20:33:42 duration 30 min 0 sec at mean kips 206
69 = Currently at line 188, col 5, instruction '[', whilelevel 5
70 = Exec tally: 35753100x(+) 35945090x(-) 104704284x(<) 104704285x(>)
71 = Exec tally: 0x(,) 9x(.) 44650879x([) 44650874x(])
72 + Tape head position: 1 cell right of start, cell contents: 394
73 + Tape observed head position: min 0, max 145, range 146
74 + Tape observed cell contents: min 0, max 65535, range 65536
75 + Tape contents (0 - 5 cells right of start):
76 #0 ->#1 #2 #3 #4 #5
77 0 394 119 45 17 5
78 ===== STATUS REPORT ===== Mon May 5 2003, 21:08:42 =====
79 = Run began Mon May 5 2003, 20:33:42 duration 35 min 0 sec at mean kips 202
80 = Currently at line 187, col 67, instruction '[', whilelevel 5
81 = Exec tally: 41735643x(+) 41928368x(-) 117617082x(<) 117617084x(>)
82 = Exec tally: 0x(,) 9x(.) 52135967x([) 52135962x(])
83 + Tape head position: 2 cells right of start, cell contents: 184
84 + Tape observed head position: min 0, max 145, range 146
85 + Tape observed cell contents: min 0, max 65535, range 65536
86 + Tape contents (0 - 6 cells right of start):
87 #0 #1 ->#2 #3 #4 #5 #6
88 0 164 184 4 50 7 0
89 ===== STATUS REPORT ===== Mon May 5 2003, 21:13:42 =====
90 = Run began Mon May 5 2003, 20:33:42 duration 40 min 0 sec at mean kips 198
91 = Currently at line 188, col 5, instruction '[', whilelevel 5
92 = Exec tally: 47717935x(+) 47910091x(-) 130253752x(<) 130253753x(>)
93 = Exec tally: 0x(,) 9x(.) 59617264x([) 59617259x(])
94 + Tape head position: 1 cell right of start, cell contents: 147
95 + Tape observed head position: min 0, max 145, range 146
96 + Tape observed cell contents: min 0, max 65535, range 65536
97 + Tape contents (0 - 5 cells right of start):
98 #0 ->#1 #2 #3 #4 #5
99 0 147 281 50 0 9
100 ===== STATUS REPORT ===== Mon May 5 2003, 21:18:42 =====
101 = Run began Mon May 5 2003, 20:33:42 duration 45 min 0 sec at mean kips 195
102 = Currently at line 188, col 22, instruction '[', whilelevel 6
103 = Exec tally: 53385479x(+) 53579121x(-) 142636196x(<) 142636202x(>)
104 = Exec tally: 0x(,) 9x(.) 66710778x([) 66710772x(])
105 + Tape head position: 7 cells right of start, cell contents: 36
106 + Tape observed head position: min 0, max 145, range 146
107 + Tape observed cell contents: min 0, max 65535, range 65536
108 + Tape contents (2 - 11 cells right of start):
109 #2 #3 #4 #5 #6 ->#7 #8 #9 #10 #11
110 343 17 23 5 1 36 533 41 0 0
111 ===== STATUS REPORT ===== Mon May 5 2003, 21:23:42 =====
112 = Run began Mon May 5 2003, 20:33:42 duration 50 min 0 sec at mean kips 196
113 = Currently at line 254, col 56, instruction '[', whilelevel 2
114 = Exec tally: 58965526x(+) 59108105x(-) 160883365x(<) 160883399x(>)
115 = Exec tally: 0x(,) 9x(.) 73574442x([) 73574440x(])
116 + Tape head position: 34 cells right of start, cell contents: 12244
117 + Tape observed head position: min 0, max 145, range 146
118 + Tape observed cell contents: min 0, max 65535, range 65536
119 + Tape contents (29 - 38 cells right of start):
120 #29 #30 #31 #32 #33 ->#34 #35 #36 #37 #38
121 0 1 15 0 4 12244 9 0 0 10
122 4
123 ===== STATUS REPORT ===== Mon May 5 2003, 21:28:42 =====
124 = Run began Mon May 5 2003, 20:33:42 duration 55 min 0 sec at mean kips 194
125 = Currently at line 188, col 22, instruction '[', whilelevel 6
126 = Exec tally: 64479186x(+) 64736496x(-) 175404374x(<) 175404380x(>)
127 = Exec tally: 0x(,) 12x(.) 80560848x([) 80560842x(])
128 + Tape head position: 7 cells right of start, cell contents: 729
129 + Tape observed head position: min 0, max 145, range 146
130 + Tape observed cell contents: min 0, max 65535, range 65536
131 + Tape contents (2 - 11 cells right of start):
132 #2 #3 #4 #5 #6 ->#7 #8 #9 #10 #11
133 784 20 36 0 1 729 798 57 0 0
134 ===== STATUS REPORT ===== Mon May 5 2003, 21:33:42 =====
135 = Run began Mon May 5 2003, 20:33:42 duration 1 hr 0 min 0 sec at mean kips 192
136 = Currently at line 187, col 67, instruction '[', whilelevel 5
137 = Exec tally: 70045030x(+) 70304600x(-) 187755052x(<) 187755054x(>)
138 = Exec tally: 0x(,) 12x(.) 87531501x([) 87531496x(])
139 + Tape head position: 2 cells right of start, cell contents: 152
140 + Tape observed head position: min 0, max 145, range 146
141 + Tape observed cell contents: min 0, max 65535, range 65536
142 + Tape contents (0 - 6 cells right of start):
143 #0 #1 ->#2 #3 #4 #5 #6
144 0 73 152 35 5 6 0
145 1
146 ===== STATUS REPORT ===== Mon May 5 2003, 21:38:42 =====
147 = Run began Mon May 5 2003, 20:33:42 duration 1 hr 5 min 0 sec at mean kips 194
148 = Currently at line 162, col 15, instruction '[', whilelevel 6
149 = Exec tally: 75614209x(+) 75938125x(-) 208594883x(<) 208594889x(>)
150 = Exec tally: 0x(,) 15x(.) 94472347x([) 94472341x(])
151 + Tape head position: 7 cells right of start, cell contents: 393
152 + Tape observed head position: min 0, max 145, range 146
153 + Tape observed cell contents: min 0, max 65535, range 65536
154 + Tape contents (2 - 11 cells right of start):
155 #2 #3 #4 #5 #6 ->#7 #8 #9 #10 #11
156 574 37 27 0 1 393 600 65 0 0
157 ===== STATUS REPORT ===== Mon May 5 2003, 21:43:42 =====
158 = Run began Mon May 5 2003, 20:33:42 duration 1 hr 10 min 0 sec at mean kips 192
159 = Currently at line 188, col 22, instruction '[', whilelevel 6
160 = Exec tally: 81182483x(+) 81507283x(-) 220985489x(<) 220985495x(>)
161 = Exec tally: 0x(,) 15x(.) 101443761x([) 101443755x(])
162 + Tape head position: 7 cells right of start, cell contents: 262
163 + Tape observed head position: min 0, max 145, range 146
164 + Tape observed cell contents: min 0, max 65535, range 65536
165 + Tape contents (2 - 11 cells right of start):
166 #2 #3 #4 #5 #6 ->#7 #8 #9 #10 #11
167 292 40 8 4 1 262 490 49 0 0
168 ===== STATUS REPORT ===== Mon May 5 2003, 21:48:42 =====
169 = Run began Mon May 5 2003, 20:33:42 duration 1 hr 15 min 0 sec at mean kips 191
170 = Currently at line 187, col 67, instruction '[', whilelevel 5
171 = Exec tally: 86759563x(+) 87084772x(-) 233715939x(<) 233715941x(>)
172 = Exec tally: 0x(,) 15x(.) 108426863x([) 108426858x(])
173 + Tape head position: 2 cells right of start, cell contents: 45
174 + Tape observed head position: min 0, max 145, range 146
175 + Tape observed cell contents: min 0, max 65535, range 65536
176 + Tape contents (0 - 6 cells right of start):
177 #0 #1 ->#2 #3 #4 #5 #6
178 0 313 45 21 3 0 0
179 ===== STATUS REPORT ===== Mon May 5 2003, 21:53:42 =====
180 = Run began Mon May 5 2003, 20:33:42 duration 1 hr 20 min 0 sec at mean kips 191
181 = Currently at line 161, col 60, instruction '[', whilelevel 5
182 = Exec tally: 92300725x(+) 92691104x(-) 250848885x(<) 250848887x(>)
183 = Exec tally: 0x(,) 15x(.) 115383433x([) 115383428x(])
184 + Tape head position: 2 cells right of start, cell contents: 107
185 + Tape observed head position: min 0, max 145, range 146
186 + Tape observed cell contents: min 0, max 65535, range 65536
187 + Tape contents (0 - 6 cells right of start):
188 #0 #1 ->#2 #3 #4 #5 #6
189 0 242 107 39 1 1 0
190 ===== STATUS REPORT ===== Mon May 5 2003, 21:58:42 =====
191 = Run began Mon May 5 2003, 20:33:42 duration 1 hr 25 min 0 sec at mean kips 190
192 = Currently at line 162, col 15, instruction '[', whilelevel 6
193 = Exec tally: 97850728x(+) 98241773x(-) 263441519x(<) 263441525x(>)
194 = Exec tally: 0x(,) 15x(.) 122333144x([) 122333138x(])
195 + Tape head position: 7 cells right of start, cell contents: 168
196 + Tape observed head position: min 0, max 145, range 146
197 + Tape observed cell contents: min 0, max 65535, range 65536
198 + Tape contents (2 - 11 cells right of start):
199 #2 #3 #4 #5 #6 ->#7 #8 #9 #10 #11
200 258 5 13 0 1 168 270 19 0 0
201 5
202 9
203 ===== STATUS REPORT ===== Mon May 5 2003, 22:03:42 =====
204 = Run began Mon May 5 2003, 20:33:42 duration 1 hr 30 min 0 sec at mean kips 191
205 = Currently at line 188, col 5, instruction '[', whilelevel 5
206 = Exec tally: 103421719x(+) 103875819x(-) 283773809x(<) 283773810x(>)
207 = Exec tally: 0x(,) 21x(.) 129269917x([) 129269912x(])
208 + Tape head position: 1 cell right of start, cell contents: 250
209 + Tape observed head position: min 0, max 145, range 146
210 + Tape observed cell contents: min 0, max 65535, range 65536
211 + Tape contents (0 - 5 cells right of start):
212 #0 ->#1 #2 #3 #4 #5
213 0 250 287 37 19 5
214 ===== STATUS REPORT ===== Mon May 5 2003, 22:08:42 =====
215 = Run began Mon May 5 2003, 20:33:42 duration 1 hr 35 min 0 sec at mean kips 190
216 = Currently at line 187, col 67, instruction '[', whilelevel 5
217 = Exec tally: 108954813x(+) 109408269x(-) 295520049x(<) 295520051x(>)
218 = Exec tally: 0x(,) 21x(.) 136188384x([) 136188379x(])
219 + Tape head position: 2 cells right of start, cell contents: 75
220 + Tape observed head position: min 0, max 145, range 146
221 + Tape observed cell contents: min 0, max 65535, range 65536
222 + Tape contents (0 - 6 cells right of start):
223 #0 #1 ->#2 #3 #4 #5 #6
224 0 739 75 46 6 2 0
225 ===== STATUS REPORT ===== Mon May 5 2003, 22:13:42 =====
226 = Run began Mon May 5 2003, 20:33:42 duration 1 hr 40 min 0 sec at mean kips 188
227 = Currently at line 187, col 67, instruction '[', whilelevel 5
228 = Exec tally: 114427622x(+) 114882129x(-) 307226669x(<) 307226671x(>)
229 = Exec tally: 0x(,) 21x(.) 143035985x([) 143035980x(])
230 + Tape head position: 2 cells right of start, cell contents: 107
231 + Tape observed head position: min 0, max 145, range 146
232 + Tape observed cell contents: min 0, max 65535, range 65536
233 + Tape contents (0 - 6 cells right of start):
234 #0 #1 ->#2 #3 #4 #5 #6
235 0 515 107 37 9 2 0
236 ===== STATUS REPORT ===== Mon May 5 2003, 22:18:42 =====
237 = Run began Mon May 5 2003, 20:33:42 duration 1 hr 45 min 0 sec at mean kips 187
238 = Currently at line 187, col 67, instruction '[', whilelevel 5
239 = Exec tally: 119902051x(+) 120358356x(-) 319041702x(<) 319041704x(>)
240 = Exec tally: 0x(,) 21x(.) 149888053x([) 149888048x(])
241 + Tape head position: 2 cells right of start, cell contents: 148
242 + Tape observed head position: min 0, max 145, range 146
243 + Tape observed cell contents: min 0, max 65535, range 65536
244 + Tape contents (0 - 6 cells right of start):
245 #0 #1 ->#2 #3 #4 #5 #6
246 0 140 148 33 5 2 0
247 2
248 ===== STATUS REPORT ===== Mon May 5 2003, 22:23:42 =====
249 = Run began Mon May 5 2003, 20:33:42 duration 1 hr 50 min 0 sec at mean kips 188
250 = Currently at line 188, col 5, instruction '[', whilelevel 5
251 = Exec tally: 125363050x(+) 125884129x(-) 339700934x(<) 339700935x(>)
252 = Exec tally: 0x(,) 24x(.) 156694446x([) 156694441x(])
253 + Tape head position: 1 cell right of start, cell contents: 201
254 + Tape observed head position: min 0, max 145, range 146
255 + Tape observed cell contents: min 0, max 65535, range 65536
256 + Tape contents (0 - 5 cells right of start):
257 #0 ->#1 #2 #3 #4 #5
258 0 201 212 34 28 0
259 ===== STATUS REPORT ===== Mon May 5 2003, 22:28:42 =====
260 = Run began Mon May 5 2003, 20:33:42 duration 1 hr 55 min 0 sec at mean kips 187
261 = Currently at line 187, col 67, instruction '[', whilelevel 5
262 = Exec tally: 130833914x(+) 131354874x(-) 351906329x(<) 351906331x(>)
263 = Exec tally: 0x(,) 24x(.) 163539106x([) 163539101x(])
264 + Tape head position: 2 cells right of start, cell contents: 464
265 + Tape observed head position: min 0, max 145, range 146
266 + Tape observed cell contents: min 0, max 65535, range 65536
267 + Tape contents (0 - 6 cells right of start):
268 #0 #1 ->#2 #3 #4 #5 #6
269 0 23 464 47 1 2 0
270 ===== STATUS REPORT ===== Mon May 5 2003, 22:33:42 =====
271 = Run began Mon May 5 2003, 20:33:42 duration 2 hr 0 min 0 sec at mean kips 186
272 = Currently at line 161, col 60, instruction '[', whilelevel 5
273 = Exec tally: 136287189x(+) 136809423x(-) 363865221x(<) 363865223x(>)
274 = Exec tally: 0x(,) 24x(.) 170365237x([) 170365232x(])
275 + Tape head position: 2 cells right of start, cell contents: 103
276 + Tape observed head position: min 0, max 145, range 146
277 + Tape observed cell contents: min 0, max 65535, range 65536
278 + Tape contents (0 - 6 cells right of start):
279 #0 #1 ->#2 #3 #4 #5 #6
280 0 68 103 12 24 2 0
281 6
282 ===== STATUS REPORT ===== Mon May 5 2003, 22:38:42 =====
283 = Run began Mon May 5 2003, 20:33:42 duration 2 hr 5 min 0 sec at mean kips 188
284 = Currently at line 188, col 22, instruction '[', whilelevel 6
285 = Exec tally: 141689012x(+) 142276109x(-) 384240054x(<) 384240060x(>)
286 = Exec tally: 0x(,) 27x(.) 177098770x([) 177098764x(])
287 + Tape head position: 7 cells right of start, cell contents: 24
288 + Tape observed head position: min 0, max 145, range 146
289 + Tape observed cell contents: min 0, max 65535, range 65536
290 + Tape contents (2 - 11 cells right of start):
291 #2 #3 #4 #5 #6 ->#7 #8 #9 #10 #11
292 82 35 29 6 1 24 455 65 0 0
293 ===== STATUS REPORT ===== Mon May 5 2003, 22:43:42 =====
294 = Run began Mon May 5 2003, 20:33:42 duration 2 hr 10 min 0 sec at mean kips 186
295 = Currently at line 188, col 22, instruction '[', whilelevel 6
296 = Exec tally: 147099275x(+) 147685307x(-) 395703128x(<) 395703134x(>)
297 = Exec tally: 0x(,) 27x(.) 183863387x([) 183863381x(])
298 + Tape head position: 7 cells right of start, cell contents: 100
299 + Tape observed head position: min 0, max 145, range 146
300 + Tape observed cell contents: min 0, max 65535, range 65536
301 + Tape contents (2 - 11 cells right of start):
302 #2 #3 #4 #5 #6 ->#7 #8 #9 #10 #11
303 244 49 11 9 1 100 793 61 0 0
304 ===== STATUS REPORT ===== Mon May 5 2003, 22:48:42 =====
305 = Run began Mon May 5 2003, 20:33:42 duration 2 hr 15 min 0 sec at mean kips 185
306 = Currently at line 162, col 15, instruction '[', whilelevel 6
307 = Exec tally: 152537435x(+) 153123412x(-) 407336323x(<) 407336329x(>)
308 = Exec tally: 0x(,) 27x(.) 190665199x([) 190665193x(])
309 + Tape head position: 7 cells right of start, cell contents: 73
310 + Tape observed head position: min 0, max 145, range 146
311 + Tape observed cell contents: min 0, max 65535, range 65536
312 + Tape contents (2 - 11 cells right of start):
313 #2 #3 #4 #5 #6 ->#7 #8 #9 #10 #11
314 427 32 22 6 1 73 778 55 0 0
315 ===== STATUS REPORT ===== Mon May 5 2003, 22:53:42 =====
316 = Run began Mon May 5 2003, 20:33:42 duration 2 hr 20 min 0 sec at mean kips 184
317 = Currently at line 187, col 67, instruction '[', whilelevel 5
318 = Exec tally: 157954886x(+) 158541517x(-) 418975842x(<) 418975844x(>)
319 = Exec tally: 0x(,) 27x(.) 197444652x([) 197444647x(])
320 + Tape head position: 2 cells right of start, cell contents: 51
321 + Tape observed head position: min 0, max 145, range 146
322 + Tape observed cell contents: min 0, max 65535, range 65536
323 + Tape contents (0 - 6 cells right of start):
324 #0 #1 ->#2 #3 #4 #5 #6
325 0 67 51 43 5 12 0
326 ===== STATUS REPORT ===== Mon May 5 2003, 22:58:42 =====
327 = Run began Mon May 5 2003, 20:33:42 duration 2 hr 25 min 0 sec at mean kips 184
328 = Currently at line 162, col 15, instruction '[', whilelevel 6
329 = Exec tally: 163368553x(+) 163956054x(-) 430676607x(<) 430676613x(>)
330 = Exec tally: 0x(,) 27x(.) 204216493x([) 204216487x(])
331 + Tape head position: 7 cells right of start, cell contents: 14
332 + Tape observed head position: min 0, max 145, range 146
333 + Tape observed cell contents: min 0, max 65535, range 65536
334 + Tape contents (2 - 11 cells right of start):
335 #2 #3 #4 #5 #6 ->#7 #8 #9 #10 #11
336 342 7 33 0 1 14 374 41 0 0
337 5
338 3
339 ---------------END PROGRAM OUTPUT---------------
340 ===== STATUS REPORT ===== Mon May 5 2003, 23:03:00 =====
341 = Run began Mon May 5 2003, 20:33:42 duration 2 hr 29 min 18 sec at mean kips 185
342 = Stopped at line 301, col 74, instruction '.', whilelevel 0
343 = Exec tally: 168003129x(+) 168657743x(-) 449388177x(<) 449388190x(>)
344 = Exec tally: 0x(,) 33x(.) 209994449x([) 209994449x(])
345 + Tape head position: 13 cells right of start, cell contents: 13
346 + Tape observed head position: min 0, max 145, range 146
347 + Tape observed cell contents: min 0, max 65535, range 65536
348 + Tape contents (8 - 17 cells right of start):
349 #8 #9 #10 #11 #12 ->#13 #14 #15 #16 #17
350 30 10 0 0 10 13 0 0 0 51
0 <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
1 <html>
2 <head>
3 <title>Module pibfi</title>
4
5 </head>
6 <body bgcolor="white">
7 <h1>Module pibfi</h1>
8 <ul><li>
9 <a href="#index">Function index</a></li><li>
10 <a href="#exported">Exported functions</a></li></ul>
11
12 <h2>Description</h2>
13 Platonic Ideal Brainf*ck Interpreter (<code>pibfi</code>).
14
15 <p>This application implements an interpreter for the language
16 Brainf*ck. It does not by default impose any limit on the maximum
17 length of the tape, nor the maximum value that can entered into
18 any of the cells in the tape (beyond those limits inescapably
19 imposed upon it by the underlying operating system and hardware.)
20 It can, however, be configured to simulate the limits imposed upon
21 the language by many other implementations which sacrifice
22 scaleability in order to achieve other goals (usually, to build an
23 astonishingly small compiler or interpreter.)</p>
24
25 <p>As such, <code>pibfi</code> may be in a position to one day
26 develop into a universal (or at least reference) interpreter for
27 the Brainf*ck language.</p>
28
29 <p>For a synopsis of the command-line options that can be used
30 with <code>pibfi</code>, see the
31 <code><a href="pibfi_options.html">pibfi_options</a></code>
32 documentation.</p>
33
34 <p>This module contains the interface to start <code>pibfi</code>
35 both from the command line, and programmatically. It also contains
36 common functions used by other <code>pibfi_*</code> modules.</p>
37
38 <p>Parts of this program were derived from the Erlang example
39 program <code>bf.erl</code>.</p>
40
41
42 <h2><a name="index">Function Index</a></h2>
43
44 <table width="100%" border="1"><tr><th colspan="2" align="left">Exported Functions</th></tr>
45 <tr><td><a href="#assert-2">assert/2</a></td><td>Asserts that the condition is true.</td></tr>
46 <tr><td><a href="#assert_in_bounds-4">assert_in_bounds/4</a></td><td/></tr>
47 <tr><td><a href="#os_eol-0">os_eol/0</a></td><td>Returns the native end-of-line convention, if it can be determined.</td></tr>
48 <tr><td><a href="#run-1">run/1</a></td><td>Starts <code>pibfi</code> for the purposes of running a Brainf*ck
49 program.</td></tr>
50 <tr><td><a href="#run-6">run/6</a></td><td>Runs a Brainf*ck program.</td></tr>
51 <tr><td><a href="#startup-2">startup/2</a></td><td/></tr>
52 <tr><td><a href="#whisper-1">whisper/1</a></td><td><a href="#whisper-2">See <code>whisper/2</code>.</a></td></tr>
53 <tr><td><a href="#whisper-2">whisper/2</a></td><td>Displays extra information.</td></tr>
54 <tr><td><a href="#wrap-3">wrap/3</a></td><td>Implements a generic modulus function.</td></tr>
55 </table>
56
57 <h2><a name="exported">Exported Functions</a></h2>
58
59 <h3><a name="assert-2">assert/2</a></h3>
60
61 <p><code>assert(Condition::<a href="#type-boolean">boolean()</a>, ErrorReason::term()) -> true</code></p>
62 <p>Asserts that the condition is true. If it is not, the
63 process crashes with the given reason.</p>
64
65 <h3><a name="assert_in_bounds-4">assert_in_bounds/4</a></h3>
66
67 <p><code>assert_in_bounds(Arg1, Arg2, Arg3, Arg4) -> term()</code></p>
68 <p> </p>
69
70 <h3><a name="os_eol-0">os_eol/0</a></h3>
71
72 <p><code>os_eol() -> string()</code></p>
73 <p>Returns the native end-of-line convention, if it can be determined.
74 If it cannot be determined, linefeed (ASCII character 10) is assumed.</p>
75
76 <h3><a name="run-1">run/1</a></h3>
77
78 <p><code>run(Args::[string()]) -> <a href="#type-halt">halt()</a></code></p>
79 <p>Starts <code>pibfi</code> for the purposes of running a Brainf*ck
80 program. This function is intended to be invoked
81 from the command line. When using <code>pibfi</code> from another Erlang
82 program, or from the Erlang shell, it is suggested you call
83 <code>run/6</code> instead.</p>
84
85 <h3><a name="run-6">run/6</a></h3>
86
87 <p><code>run(Supervisor::pid(), ProgramSource::binary(), ParserOptions::[{atom(), term()}], TapeOptions::[{atom(), term()}], IOOptions::[{atom(), term()}], DebugOptions::[{atom(), term()}]) -> <a href="#type-tape">tape()</a><ul><li><a name="type-program">program()</a> = string() | binary() | <a href="#type-tuple">tuple()</a></li></ul></code></p>
88 <p>Runs a Brainf*ck program.</p>
89
90 <h3><a name="startup-2">startup/2</a></h3>
91
92 <p><code>startup(Arg1, Arg2) -> term()</code></p>
93 <p> </p>
94
95 <h3><a name="whisper-1">whisper/1</a></h3>
96
97 <p><code>whisper(string()) -> ok</code></p>
98 <p>Equivalent to <a href="#whisper-2"><code>whisper(string(), [])</code></a>.</p>
99
100 <h3><a name="whisper-2">whisper/2</a></h3>
101
102 <p><code>whisper(string(), [term()]) -> ok</code></p>
103 <p>Displays extra information. The user can shut this off with
104 <code>-quiet</code>.</p>
105
106 <h3><a name="wrap-3">wrap/3</a></h3>
107
108 <p><code>wrap(Value::integer(), Max::integer(), Min::integer()) -> integer()</code></p>
109 <p>Implements a generic modulus function. Both the top and bottom
110 modulus limits may be specified.</p></body>
111 </html>
0 <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
1 <html>
2 <head>
3 <title>Module pibfi_filter</title>
4
5 </head>
6 <body bgcolor="white">
7 <h1>Module pibfi_filter</h1>
8 <ul><li>
9 <a href="#index">Function index</a></li><li>
10 <a href="#exported">Exported functions</a></li></ul>
11
12 <h2>Description</h2>
13 Stream filtering for the Platonic Ideal Brainf*ck Interpreter.
14
15
16 <h2><a name="index">Function Index</a></h2>
17
18 <table width="100%" border="1"><tr><th colspan="2" align="left">Exported Functions</th></tr>
19 <tr><td><a href="#notify-2">notify/2</a></td><td>Notifies the other end of the connection.</td></tr>
20 <tr><td><a href="#send-2">send/2</a></td><td>Sends a character or characters to a filter server for filtration.</td></tr>
21 <tr><td><a href="#server-5">server/5</a></td><td/></tr>
22 <tr><td><a href="#start-6">start/6</a></td><td>Creates and spawns a new stream filter.</td></tr>
23 </table>
24
25 <h2><a name="exported">Exported Functions</a></h2>
26
27 <h3><a name="notify-2">notify/2</a></h3>
28
29 <p><code>notify(<a href="#type-xlat">xlat()</a>, term()) -> ok</code></p>
30 <p>Notifies the other end of the connection.
31 They will receive a <code>{Filter::pid(), Notifier::pid(), message, term()}</code> message.</p>
32
33 <h3><a name="send-2">send/2</a></h3>
34
35 <p><code>send(<a href="#type-xlat">xlat()</a>, char() | string()) -> ok</code></p>
36 <p>Sends a character or characters to a filter server for filtration.</p>
37
38 <h3><a name="server-5">server/5</a></h3>
39
40 <p><code>server(Arg1, Arg2, Arg3, Arg4, Arg5) -> term()</code></p>
41 <p> </p>
42
43 <h3><a name="start-6">start/6</a></h3>
44
45 <p><code>start(Supervisor::pid(), Role::atom(), Dest::pid(), MaxThru::integer(), MinThru::integer(), WrapThru::integer()) -> pid()</code></p>
46 <p>Creates and spawns a new stream filter.</p></body>
47 </html>
0 <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
1 <html>
2 <head>
3 <title>Module pibfi_input</title>
4
5 </head>
6 <body bgcolor="white">
7 <h1>Module pibfi_input</h1>
8 <ul><li>
9 <a href="#index">Function index</a></li><li>
10 <a href="#exported">Exported functions</a></li></ul>
11
12 <h2>Description</h2>
13 Input subsystem of the Platonic Ideal Brainf*ck Interpreter.
14
15
16 <h2><a name="index">Function Index</a></h2>
17
18 <table width="100%" border="1"><tr><th colspan="2" align="left">Exported Functions</th></tr>
19 <tr><td><a href="#server-5">server/5</a></td><td/></tr>
20 <tr><td><a href="#start-6">start/6</a></td><td>Creates and spawns a new input subsystem.</td></tr>
21 </table>
22
23 <h2><a name="exported">Exported Functions</a></h2>
24
25 <h3><a name="server-5">server/5</a></h3>
26
27 <p><code>server(Arg1, Arg2, Arg3, Arg4, Arg5) -> term()</code></p>
28 <p> </p>
29
30 <h3><a name="start-6">start/6</a></h3>
31
32 <p><code>start(Supervisor::pid(), IoPid::pid(), Dest::pid(), Interactive::<a href="#type-boolean">boolean()</a>, Device, EOF) -> pid()</code></p>
33 <p>Creates and spawns a new input subsystem.</p></body>
34 </html>
0 <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
1 <html>
2 <head>
3 <title>Module pibfi_interpreter</title>
4
5 </head>
6 <body bgcolor="white">
7 <h1>Module pibfi_interpreter</h1>
8 <ul><li>
9 <a href="#index">Function index</a></li><li>
10 <a href="#exported">Exported functions</a></li><li>
11 <a href="#internal">Documented Internal Functions</a></li></ul>
12
13 <h2>Description</h2>
14 Interpreter for <code>pibfi</code>.
15
16
17 <h2><a name="index">Function Index</a></h2>
18
19 <table width="100%" border="1"><tr><th colspan="2" align="left">Exported Functions</th></tr>
20 <tr><td><a href="#interpret-4">interpret/4</a></td><td>Interprets a Brainf*ck program.</td></tr>
21 <tr><th colspan="2" align="left">Internal Documented Functions</th></tr>
22 <tr><td><a href="#execute-4">execute/4</a></td><td>Executes a single Brainf*ck instruction.</td></tr>
23 </table>
24
25 <h2><a name="exported">Exported Functions</a></h2>
26
27 <h3><a name="interpret-4">interpret/4</a></h3>
28
29 <p><code>interpret(<a href="#type-program">program()</a>, ParserOptions::[{atom(), term()}], Tape::pid(), IoPid::pid()) -> ok</code></p>
30 <p>Interprets a Brainf*ck program. If the program is given in
31 an unparsed (list or binary) form, it will be parsed into a
32 tuple form before proceeding.</p>
33
34 <h2><a name="internal">Documented Internal Functions</a></h2>
35
36 <h3><a name="execute-4">execute/4</a></h3>
37
38 <p><code>execute(<a href="#type-instruction">instruction()</a>, Tape::pid(), IO::pid(), StatusCmd) -> ok</code></p>
39 <p>Executes a single Brainf*ck instruction.</p></body>
40 </html>
0 <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
1 <html>
2 <head>
3 <title>Module pibfi_io</title>
4
5 </head>
6 <body bgcolor="white">
7 <h1>Module pibfi_io</h1>
8 <ul><li>
9 <a href="#index">Function index</a></li><li>
10 <a href="#exported">Exported functions</a></li><li>
11 <a href="#internal">Documented Internal Functions</a></li></ul>
12
13 <h2>Description</h2>
14 I/O subsystem of the Platonic Ideal Brainf*ck Interpreter.
15
16 <p>Deals with the input and output servers, their filters, and
17 their translators.</p>
18
19
20 <h2><a name="index">Function Index</a></h2>
21
22 <table width="100%" border="1"><tr><th colspan="2" align="left">Exported Functions</th></tr>
23 <tr><td><a href="#flush-1">flush/1</a></td><td>Flushes any pending output, even if it has not been translated yet.</td></tr>
24 <tr><td><a href="#input-1">input/1</a></td><td>Retrieves the next character value from the input stream.</td></tr>
25 <tr><td><a href="#output-2">output/2</a></td><td>Sends the given character value to the output stream.</td></tr>
26 <tr><td><a href="#server-1">server/1</a></td><td>Spawned by <code>start/1</code>.</td></tr>
27 <tr><td><a href="#start-3">start/3</a></td><td>Creates and spawns a new I/O subsystem.</td></tr>
28 <tr><td><a href="#stop-1">stop/1</a></td><td>Tells the I/O server to stop.</td></tr>
29 <tr><th colspan="2" align="left">Internal Documented Functions</th></tr>
30 <tr><td><a href="#config-2">config/2</a></td><td>Sets the various options of an I/O subsystem.</td></tr>
31 <tr><td><a href="#write-5">write/5</a></td><td>Writes a character to the output, within the given constraints.</td></tr>
32 </table>
33
34 <h2><a name="exported">Exported Functions</a></h2>
35
36 <h3><a name="flush-1">flush/1</a></h3>
37
38 <p><code>flush(pid()) -> ok</code></p>
39 <p>Flushes any pending output, even if it has not been translated yet.</p>
40
41 <h3><a name="input-1">input/1</a></h3>
42
43 <p><code>input(pid()) -> integer() | nop</code></p>
44 <p>Retrieves the next character value from the input stream.</p>
45
46 <h3><a name="output-2">output/2</a></h3>
47
48 <p><code>output(pid(), integer()) -> ok</code></p>
49 <p>Sends the given character value to the output stream.</p>
50
51 <h3><a name="server-1">server/1</a></h3>
52
53 <p><code>server(IO) -> <a href="#type-never_returns">never_returns()</a></code></p>
54 <p>Spawned by <code>start/1</code>.
55 Should not be called directly by user code.</p>
56
57 <h3><a name="start-3">start/3</a></h3>
58
59 <p><code>start(Supervisor::pid(), [<a href="#type-option">option()</a>], CannedInput::string()) -> pid()</code></p>
60 <p>Creates and spawns a new I/O subsystem.
61 For a description of the allowed options, see the documentation for
62 the <code><a href="pibfi_options.html">pibfi_options</a></code> module.</p>
63
64 <h3><a name="stop-1">stop/1</a></h3>
65
66 <p><code>stop(pid()) -> ok</code></p>
67 <p>Tells the I/O server to stop.</p>
68
69 <h2><a name="internal">Documented Internal Functions</a></h2>
70
71 <h3><a name="config-2">config/2</a></h3>
72
73 <p><code>config([<a href="#type-option">option()</a>], <a href="#type-tape">tape()</a>) -> <a href="#type-tape">tape()</a></code></p>
74 <p>Sets the various options of an I/O subsystem.</p>
75
76 <h3><a name="write-5">write/5</a></h3>
77
78 <p><code>write(<a href="#type-iodevice">iodevice()</a>, Max::integer(), Min::integer(), Wrap::<a href="#type-boolean">boolean()</a>, char()) -> ok</code></p>
79 <p>Writes a character to the output, within the given constraints.</p></body>
80 </html>
0 <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
1 <html>
2 <head>
3 <title>Module pibfi_optimizer</title>
4
5 </head>
6 <body bgcolor="white">
7 <h1>Module pibfi_optimizer</h1>
8 <ul><li>
9 <a href="#index">Function index</a></li><li>
10 <a href="#exported">Exported functions</a></li></ul>
11
12 <h2>Description</h2>
13 Optimizer for <code>pibfi</code>.
14
15 <p>Takes an internal format as generated by the parser and
16 returns a (hopefully) more efficient internal format.</p>
17
18
19 <h2><a name="index">Function Index</a></h2>
20
21 <table width="100%" border="1"><tr><th colspan="2" align="left">Exported Functions</th></tr>
22 <tr><td><a href="#optimize-1">optimize/1</a></td><td>Optimizes a Brainf*ck program.</td></tr>
23 </table>
24
25 <h2><a name="exported">Exported Functions</a></h2>
26
27 <h3><a name="optimize-1">optimize/1</a></h3>
28
29 <p><code>optimize(<a href="#type-program">program()</a>) -> <a href="#type-program">program()</a></code></p>
30 <p>Optimizes a Brainf*ck program.</p></body>
31 </html>
0 <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
1 <html>
2 <head>
3 <title>Module pibfi_options</title>
4
5 </head>
6 <body bgcolor="white">
7 <h1>Module pibfi_options</h1>
8 <ul><li>
9 <a href="#index">Function index</a></li><li>
10 <a href="#exported">Exported functions</a></li><li>
11 <a href="#internal">Documented Internal Functions</a></li></ul>
12
13 <h2>Description</h2>
14 Options parser for <code>pibfi</code>.
15
16 <h3>Synopsis</h3>
17
18 <p>This module implements collecting options
19 from the command line.</p>
20
21 <p>When invoking <code>pibfi</code> from the command line, the
22 following syntax can be used:</p>
23
24 <ul><code>erl -noshell <i>options</i> -run pibfi run <i>filename</i></code></ul>
25
26 <p>The following options are recognized.</p>
27
28 <ul>
29 <li>Options pertaining to the parser:
30
31 <ul>
32 <li><code>-dontstrip <i>s</i></code>, where <i>s</i> is a string of
33 characters, default null (empty), specifies the set of characters
34 (beyond the 8 basic Brainf*ck instructions)
35 which
36 will not be stripped from the parsed source prior to optimization.
37 Note that if this option if given without an argument, it is assumed
38 to be the set of all applicable characters - in other words, nothing
39 at all will be stripped.</li>
40
41 <li><code>-optimize <i>n</i></code>, where <i>n</i> is an integer,
42 default 1, sets the optimization level of the parser.
43 At optimization level 0, no optimization occurs.
44 At optimization level 1, run-length encoding is performed on the
45 instructions. Further optimization levels may be defined in the
46 future. Note that if this option if given without an argument,
47 it is assumed to be asking for the most thorough yet quickly
48 available optimization.</li>
49
50 <li><code>-statuscmd <i>c</i></code>, where <i>c</i> may be
51 any single-character string of the term <code>undefined</code>,
52 default "#" (octalthorpe), specifies
53 which symbol, when encountered, is treated
54 as a debugging instruction which displays a status report.</li>
55
56 <li><code>-heredoc <i>c</i></code>, where <i>c</i> may be
57 a single-character string or the term <code>undefined</code>,
58 default <code>undefined</code>, specifies which symbol when encountered,
59 is treated as the marker that signifies that input is embedded in
60 the program source code following it. This input will be stripped
61 from the source (even if it contains valid Brainf*ck instructions)
62 and will be made available to <code>-infile heredoc</code> (see
63 below.) Note that if this option is given with no argument,
64 "!" (exclamation point) is assumed.</li>
65
66 </ul>
67 </li>
68 <li>Options pertaining to the Brainf*ck tape:
69
70 <ul>
71 <li><code>-tapemodule <i>m</i></code>, where <i>n</i> is the name of
72 an Erlang module conforming to the <code>pibfi_tape</code> behaviour,
73 defaulting to whatever <code>pibfi</code> determines would be optimal
74 for the given sourcecode, (currently always <code>pibfi_tape_ets</code>),
75 names the module which implements the backing for the simulated tape.</li>
76
77 <li><code>-maxcell <i>n</i></code>, where <i>n</i> is any integer or the
78 term <code>infinity</code>, default <code>infinity</code>, sets the
79 highest value that can be placed into a cell on the tape.</li>
80
81 <li><code>-mincell <i>n</i></code>, where <i>n</i> is any integer or the
82 term <code>infinity</code>, default 0, sets the
83 lowest value that can be placed into a cell on the tape.
84 (Note that <code>infinity</code> actually represents negative infinity
85 here.)</li>
86
87 <li><code>-wrapcell <i>b</i></code>, where <i>b</i> is a boolean
88 (<code>true</code> or <code>false</code>), default <code>false</code>,
89 determines what happens when either limit of any cell in the tape is
90 exceeded. When <code>-wrapcell</code> is <code>true</code>, the limits
91 will be taken as modulus boundaries, and the value will 'wrap around'
92 to the opposite limit. When <code>-wrapcell</code> is <code>false</code>,
93 an exception will be generated. Note that if <i>b</i> is omitted
94 after <code>-wrapcell</code>, <code>true</code> is assumed.
95 Also note that <code>-wrapcell true</code> is not compatible with
96 either <code>-maxcell infinity</code> or <code>-mincell infinity</code>
97 (for what should be obvious reasons.)</li>
98
99 <li><code>-maxtape <i>n</i></code>, where <i>n</i> is any integer or the
100 term <code>infinity</code>, default <code>infinity</code>, sets the
101 rightmost position to which the tape head can move. Note that the initial
102 position of the tape head is considered position 0.</li>
103
104 <li><code>-mintape <i>n</i></code>, where <i>n</i> is any integer or the
105 term <code>infinity</code>, default 0, sets the
106 leftmost position to which the tape head can move.
107 (Note that <code>infinity</code> actually represents negative infinity
108 here.)</li>
109
110 <li><code>-wraptape <i>b</i></code>, where <i>b</i> is a boolean,
111 default <code>false</code>, determines what happens when either limit
112 of the tape head is exceeded. With <code>-wraptape true</code>,
113 the limits will be taken as modulus boundaries,
114 and the position of the tape head will 'wrap around' to the
115 opposite limit. With <code>-wraptape false</code>,
116 an exception will be generated when this happens.
117 Note that if <i>b</i> is omitted
118 after <code>-wraptape</code>, <code>true</code> is assumed. Also note
119 that <code>-wraptape true</code> is not compatible with either
120 <code>-maxtape infinity</code> or <code>-mintape infinity</code>.</li>
121 </ul>
122 </li>
123
124 <li>Options pertaining to input and output:
125
126 <ul>
127 <li><code>-infile <i>s</i></code>, where <i>s</i> is a filename or
128 one of the terms <code>tty</code> or <code>heredoc</code>,
129 default <code>tty</code>, sets the
130 source of the input to the Brainf*ck program.
131 <code>tty</code> indicates an interactive terminal session with
132 "standard input".
133 <code>heredoc</code> indicates input will come from the
134 "here-doc" portion of the program source code (note that the
135 <code>-heredoc</code> option must also be given to parse the
136 source code.)
137 Using this option is preferred
138 over redirecting standard I/O with the shell, as it is a hint to the
139 interpreter that the program is not being run interactively.</li>
140
141 <li><code>-outfile <i>s</i></code>, where <i>s</i> is a filename or
142 the term <code>tty</code>, default <code>tty</code>, sets the
143 destination of the output of the Brainf*ck program. This is preferred
144 to redirecting standard I/O with the shell, as it is a hint to the
145 interpreter that the program is not being run interactively.</li>
146
147 <li><code>-maxout <i>n</i></code>, where <i>n</i> is any integer or the
148 term <code>infinity</code>, default <code>infinity</code>, sets the
149 maximum character value which can be output.</li>
150
151 <li><code>-minout <i>n</i></code>, where <i>n</i> is any integer or the
152 term <code>infinity</code>, default 0, sets the minimum character
153 value which can be output.
154 (Note that <code>infinity</code> actually represents negative infinity
155 here.)</li>
156
157 <li><code>-wrapout <i>b</i></code>, where <i>b</i> is a boolean,
158 default <code>false</code>, determines what happens when either limit
159 of character output is exceeded. With <code>-wrapout true</code>,
160 the limits will be taken as modulus boundaries,
161 and the actual character output will be computed by 'wrapping around'
162 the rquested value to the opposite limit.
163 With <code>-wrapout false</code>,
164 an exception will be generated. Note that if <i>b</i> is omitted
165 after <code>-wrapout</code>, <code>true</code> is assumed. Also note
166 that <code>-wrapout true</code> is not compatible with either
167 <code>-maxout infinity</code> or <code>-minout infinity</code>.</li>
168
169 <li><code>-maxin <i>n</i></code>, where <i>n</i> is any integer or the
170 term <code>infinity</code>, default <code>infinity</code>, sets the
171 maximum character value which can be input.</li>
172
173 <li><code>-minin <i>n</i></code>, where <i>n</i> is any integer or the
174 term <code>infinity</code>, default 0, sets the minimum character
175 value which can be input.
176 (Note that <code>infinity</code> actually represents negative infinity
177 here.)</li>
178
179 <li><code>-wrapin <i>b</i></code>, where <i>b</i> is a boolean,
180 default <code>false</code>, determines what happens when either limit
181 of character input is exceeded. With <code>-wrapin true</code>,
182 the limits will be taken as modulus boundaries,
183 and the actual character input will be computed by 'wrapping around'
184 the rquested value to the opposite limit.
185 With <code>-wrapin false</code>,
186 an exception will be generated. Note that if <i>b</i> is omitted
187 after <code>-wrapin</code>, <code>true</code> is assumed. Also note
188 that <code>-wrapin true</code> is not compatible with either
189 <code>-maxin infinity</code> or <code>-minin infinity</code>.</li>
190
191 <li><code>-xlatout <i>s</i></code>, where <i>s</i> is string
192 in the form given below,
193 default value <tt>#10=#nl</tt>, specifies a mapping between
194 characters the Brainf*ck program sees itself as sending to output,
195 and the characters that the operating system actually receives.
196 The syntax for the mapping specification is described by this mini-grammar:
197 <ul><li>
198 <tt><i>string</i> "=" <i>string</i> ["," <i>string</i> "=" <i>string</i> ]</tt>
199 </li></ul>
200 Control and other characters can be embedded in this string by
201 giving their ASCII values in decimal preceded by a <tt>#</tt>
202 symbol. A single <tt>#</tt> symbol can be represented by the
203 sequence <tt>#35</tt>. A single <tt>=</tt> symbol can be
204 represented by the sequence <tt>#61</tt>.
205 A single <tt>,</tt> symbol can be
206 represented by the sequence <tt>#44</tt>.
207 The current operating system newline
208 sequence can be represented by <tt>#nl</tt>.
209 Note that whitespace is not allowed in this grammar,
210 and must be represented by <tt>#32</tt>, etc.
211 Note that if the <code>-xlatout</code> option is present
212 with no argument, this means that there should be <i>no</i> translation
213 mapping between Brainf*ck output and operating system output.</li>
214
215 <li><code>-xlatin <i>s</i></code>, where <i>s</i> is a string
216 in the form given above,
217 default value <tt>#nl=#10</tt>, specifies a complementary mapping between
218 characters on the operating system's input and
219 the Brainf*ck program's input.
220 Note that if the <code>-xlatin</code> option is present
221 with no argument, this means that there should be no translation
222 mapping of input.</li>
223
224 <li><code>-eof <i>i</i></code>, where <i>i</i> is any integer
225 or one of the terms <code>halt</code>, <code>stop</code>,
226 or <code>nop</code>, default 0,
227 determines the single ASCII character that will be given repeatedly to
228 the Brainf*ck program during execution of the <code>,</code> instruction
229 at and after the end of input is encountered.
230 If <code>halt</code> is given for <code>eof</code>, the Brainf*ck
231 program will be halted with an error
232 if it attempts to read past the end of user input.
233 If <code>stop</code> is given for <code>eof</code>, the Brainf*ck
234 program will be terminated normally if it attempts to read past
235 the end of user input.
236 If <code>nop</code> is given for <code>eof</code>, the Brainf*ck
237 program will act as if nothing at all happened if it attempts
238 to read past the end of user input (the tape will not be altered in
239 any way.)</li>
240 </ul>
241 </li>
242
243 <li>Debugging and other options:</li>
244 <ul>
245 <li><code>-quiet</code>, if given, suppresses all startup
246 output generated by the interpreter. It does not suppress
247 status reports.</li>
248 <li><code>-autopsy</code>, if given, causes the interpreter to
249 issue a status report after the program terminates normally.</li>
250 <li><code>-statusevery <i>n</i></code>, where <i>n</i> is an
251 integer specifying a duration or the term <code>undefined</code>,
252 default <code>undefined</code>, tells <code>pibfi</code>
253 to generate periodic status reports at the given interval,
254 if it is not <code>undefined</code>. If the duration is given
255 as a plain integer, units of milliseconds are assumed. The
256 duration may also be given as an integer followed immediately
257 by <code>s</code>, <code>m</code>, or <code>h</code>, in which
258 case the units of measurement will be taken to be seconds,
259 minutes, or hours, respectively.</li>
260 </ul>
261 </ul>
262
263
264 <h2><a name="index">Function Index</a></h2>
265
266 <table width="100%" border="1"><tr><th colspan="2" align="left">Exported Functions</th></tr>
267 <tr><td><a href="#get_flag-1">get_flag/1</a></td><td>Gets a switch from the command line.</td></tr>
268 <tr><td><a href="#get_option-3">get_option/3</a></td><td>Gets an option from a list of (already parsed) option tuples.</td></tr>
269 <tr><td><a href="#get_opts-1">get_opts/1</a></td><td>Gets a set of options from the command line.</td></tr>
270 <tr><th colspan="2" align="left">Internal Documented Functions</th></tr>
271 <tr><td><a href="#convert-2">convert/2</a></td><td>Converts an option value specified on the command line to a
272 term that <code>pibfi</code> can work with internally.</td></tr>
273 <tr><td><a href="#missing-1">missing/1</a></td><td>Gets the default value for an option specified with no value
274 on the command line.</td></tr>
275 <tr><td><a href="#unescape-1">unescape/1</a></td><td>Transforms escape codes in a string into embedded characters.</td></tr>
276 </table>
277
278 <h2><a name="exported">Exported Functions</a></h2>
279
280 <h3><a name="get_flag-1">get_flag/1</a></h3>
281
282 <p><code>get_flag(Switch::atom()) -> true | false</code></p>
283 <p>Gets a switch from the command line.</p>
284
285 <h3><a name="get_option-3">get_option/3</a></h3>
286
287 <p><code>get_option(Options::[{atom(), term()}], Option::atom(), Default::term()) -> term()</code></p>
288 <p>Gets an option from a list of (already parsed) option tuples.</p>
289
290 <h3><a name="get_opts-1">get_opts/1</a></h3>
291
292 <p><code>get_opts([atom()]) -> [{atom(), term()}]</code></p>
293 <p>Gets a set of options from the command line.</p>
294
295 <h2><a name="internal">Documented Internal Functions</a></h2>
296
297 <h3><a name="convert-2">convert/2</a></h3>
298
299 <p><code>convert(atom(), string()) -> term()</code></p>
300 <p>Converts an option value specified on the command line to a
301 term that <code>pibfi</code> can work with internally.</p>
302
303 <h3><a name="missing-1">missing/1</a></h3>
304
305 <p><code>missing(atom()) -> term()</code></p>
306 <p>Gets the default value for an option specified with no value
307 on the command line.</p>
308
309 <h3><a name="unescape-1">unescape/1</a></h3>
310
311 <p><code>unescape(string()) -> string()</code></p>
312 <p>Transforms escape codes in a string into embedded characters.
313 The escape code <tt>#<i>i</i></tt> where <tt><i>i</i></tt> is a
314 decimal integer of from one to three digits is converted into an
315 ASCII character of that value.</p></body>
316 </html>
0 <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
1 <html>
2 <head>
3 <title>Module pibfi_parser</title>
4
5 </head>
6 <body bgcolor="white">
7 <h1>Module pibfi_parser</h1>
8 <ul><li>
9 <a href="#index">Function index</a></li><li>
10 <a href="#exported">Exported functions</a></li></ul>
11
12 <h2>Description</h2>
13 Brainf*ck parser for <code>pibfi</code>.
14
15
16 <h2><a name="index">Function Index</a></h2>
17
18 <table width="100%" border="1"><tr><th colspan="2" align="left">Exported Functions</th></tr>
19 <tr><td><a href="#parse-2">parse/2</a></td><td>Transforms a string into a nested tuple data structure
20 suitable for interpretation.</td></tr>
21 </table>
22
23 <h2><a name="exported">Exported Functions</a></h2>
24
25 <h3><a name="parse-2">parse/2</a></h3>
26
27 <p><code>parse(string() | binary(), Options) -> {<a href="#type-tuple">tuple()</a>, string()}</code></p>
28 <p>Transforms a string into a nested tuple data structure
29 suitable for interpretation.</p></body>
30 </html>
0 <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
1 <html>
2 <head>
3 <title>Module pibfi_statistics</title>
4
5 </head>
6 <body bgcolor="white">
7 <h1>Module pibfi_statistics</h1>
8 <ul><li>
9 <a href="#index">Function index</a></li><li>
10 <a href="#exported">Exported functions</a></li></ul>
11
12 <h2>Description</h2>
13 Statistics collector for <code>pibfi</code>.
14
15
16 <h2><a name="index">Function Index</a></h2>
17
18 <table width="100%" border="1"><tr><th colspan="2" align="left">Exported Functions</th></tr>
19 <tr><td><a href="#dump-0">dump/0</a></td><td/></tr>
20 <tr><td><a href="#dump-1">dump/1</a></td><td/></tr>
21 <tr><td><a href="#server-2">server/2</a></td><td/></tr>
22 <tr><td><a href="#start-3">start/3</a></td><td/></tr>
23 <tr><td><a href="#update_program-3">update_program/3</a></td><td/></tr>
24 </table>
25
26 <h2><a name="exported">Exported Functions</a></h2>
27
28 <h3><a name="dump-0">dump/0</a></h3>
29
30 <p><code>dump() -> term()</code></p>
31 <p> </p>
32
33 <h3><a name="dump-1">dump/1</a></h3>
34
35 <p><code>dump(Arg1) -> term()</code></p>
36 <p> </p>
37
38 <h3><a name="server-2">server/2</a></h3>
39
40 <p><code>server(Arg1, Arg2) -> term()</code></p>
41 <p> </p>
42
43 <h3><a name="start-3">start/3</a></h3>
44
45 <p><code>start(Arg1, Arg2, Arg3) -> term()</code></p>
46 <p> </p>
47
48 <h3><a name="update_program-3">update_program/3</a></h3>
49
50 <p><code>update_program(Arg1, Arg2, Arg3) -> term()</code></p>
51 <p> </p></body>
52 </html>
0 <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
1 <html>
2 <head>
3 <title>Module pibfi_stripper</title>
4
5 </head>
6 <body bgcolor="white">
7 <h1>Module pibfi_stripper</h1>
8 <ul><li>
9 <a href="#index">Function index</a></li><li>
10 <a href="#exported">Exported functions</a></li></ul>
11
12 <h2>Description</h2>
13 Stripper for <code>pibfi</code>.
14
15 <p>Takes the internal format as generated by the parser and
16 takes out everything non-essential.</p>
17
18
19
20 <h2><a name="index">Function Index</a></h2>
21
22 <table width="100%" border="1"><tr><th colspan="2" align="left">Exported Functions</th></tr>
23 <tr><td><a href="#strip-2">strip/2</a></td><td>Strips a Brainf*ck program.</td></tr>
24 </table>
25
26 <h2><a name="exported">Exported Functions</a></h2>
27
28 <h3><a name="strip-2">strip/2</a></h3>
29
30 <p><code>strip(<a href="#type-program">program()</a>, Exclude::string()) -> <a href="#type-program">program()</a></code></p>
31 <p>Strips a Brainf*ck program.
32 </p></body>
33 </html>
0 <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
1 <html>
2 <head>
3 <title>Module pibfi_supervisor</title>
4
5 </head>
6 <body bgcolor="white">
7 <h1>Module pibfi_supervisor</h1>
8 <ul><li>
9 <a href="#index">Function index</a></li><li>
10 <a href="#exported">Exported functions</a></li></ul>
11
12 <h2>Description</h2>
13 Supervisor process for <code>pibfi</code>.
14
15 <p>All error handling is done here. This allows the other processes
16 to be coded in a more direct, laissez-crash style. The centralization
17 of error-handling code in this process allows for minimal
18 error-handling code in the other processes, which makes their code
19 clearer and easier to follow.</p>
20
21
22 <h2><a name="index">Function Index</a></h2>
23
24 <table width="100%" border="1"><tr><th colspan="2" align="left">Exported Functions</th></tr>
25 <tr><td><a href="#link-3">link/3</a></td><td/></tr>
26 <tr><td><a href="#server-0">server/0</a></td><td/></tr>
27 <tr><td><a href="#spawn_link-6">spawn_link/6</a></td><td/></tr>
28 <tr><td><a href="#start-0">start/0</a></td><td/></tr>
29 </table>
30
31 <h2><a name="exported">Exported Functions</a></h2>
32
33 <h3><a name="link-3">link/3</a></h3>
34
35 <p><code>link(Arg1, Arg2, Arg3) -> term()</code></p>
36 <p> </p>
37
38 <h3><a name="server-0">server/0</a></h3>
39
40 <p><code>server() -> term()</code></p>
41 <p> </p>
42
43 <h3><a name="spawn_link-6">spawn_link/6</a></h3>
44
45 <p><code>spawn_link(Arg1, Arg2, Arg3, Arg4, Arg5, Arg6) -> term()</code></p>
46 <p> </p>
47
48 <h3><a name="start-0">start/0</a></h3>
49
50 <p><code>start() -> term()</code></p>
51 <p> </p></body>
52 </html>
0 <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
1 <html>
2 <head>
3 <title>Module pibfi_tape</title>
4
5 </head>
6 <body bgcolor="white">
7 <h1>Module pibfi_tape</h1>
8 <ul><li>
9 <a href="#index">Function index</a></li><li>
10 <a href="#exported">Exported functions</a></li></ul>
11
12 <h2>Description</h2>
13 Tape ADT for the Platonic Ideal Brainf*ck Interpreter.
14
15 <p>Now a behaviour.</p>
16
17
18 <h2><a name="index">Function Index</a></h2>
19
20 <table width="100%" border="1"><tr><th colspan="2" align="left">Exported Functions</th></tr>
21 <tr><td><a href="#behaviour_info-1">behaviour_info/1</a></td><td/></tr>
22 <tr><td><a href="#decrement-1">decrement/1</a></td><td>Decrements the value at the current position on the tape.</td></tr>
23 <tr><td><a href="#decrement-2">decrement/2</a></td><td>Decrements the value at the current position on the tape N times.</td></tr>
24 <tr><td><a href="#examine-1">examine/1</a></td><td>Examines the state of the tape.</td></tr>
25 <tr><td><a href="#increment-1">increment/1</a></td><td>Increments the value at the current position on the tape.</td></tr>
26 <tr><td><a href="#increment-2">increment/2</a></td><td>Increments the value at the current position on the tape N times.</td></tr>
27 <tr><td><a href="#left-1">left/1</a></td><td>Moves the read/write head one position left on the tape.</td></tr>
28 <tr><td><a href="#left-2">left/2</a></td><td>Moves the read/write head N positions left on the tape.</td></tr>
29 <tr><td><a href="#read-1">read/1</a></td><td>Returns the value at the current position on the tape.</td></tr>
30 <tr><td><a href="#right-1">right/1</a></td><td>Moves the read/write head one position right on the tape.</td></tr>
31 <tr><td><a href="#right-2">right/2</a></td><td>Moves the read/write head N positions right on the tape.</td></tr>
32 <tr><td><a href="#server-2">server/2</a></td><td/></tr>
33 <tr><td><a href="#start-3">start/3</a></td><td>Starts and returns the pid of a new tape server.</td></tr>
34 <tr><td><a href="#write-2">write/2</a></td><td>Places the given value at the current position on the tape.</td></tr>
35 </table>
36
37 <h2><a name="exported">Exported Functions</a></h2>
38
39 <h3><a name="behaviour_info-1">behaviour_info/1</a></h3>
40
41 <p><code>behaviour_info(Arg1) -> term()</code></p>
42 <p> </p>
43
44 <h3><a name="decrement-1">decrement/1</a></h3>
45
46 <p><code>decrement(<a href="#type-tape">tape()</a>) -> ok | {error, Reason}</code></p>
47 <p>Decrements the value at the current position on the tape.</p>
48
49 <h3><a name="decrement-2">decrement/2</a></h3>
50
51 <p><code>decrement(<a href="#type-tape">tape()</a>, N::integer()) -> ok | {error, Reason}</code></p>
52 <p>Decrements the value at the current position on the tape N times.</p>
53
54 <h3><a name="examine-1">examine/1</a></h3>
55
56 <p><code>examine(TapePid::pid()) -> ok | {error, Reason}</code></p>
57 <p>Examines the state of the tape.</p>
58
59 <h3><a name="increment-1">increment/1</a></h3>
60
61 <p><code>increment(<a href="#type-tape">tape()</a>) -> ok | {error, Reason}</code></p>
62 <p>Increments the value at the current position on the tape.</p>
63
64 <h3><a name="increment-2">increment/2</a></h3>
65
66 <p><code>increment(<a href="#type-tape">tape()</a>, N::integer()) -> ok | {error, Reason}</code></p>
67 <p>Increments the value at the current position on the tape N times.</p>
68
69 <h3><a name="left-1">left/1</a></h3>
70
71 <p><code>left(pid()) -> ok</code></p>
72 <p>Moves the read/write head one position left on the tape.</p>
73
74 <h3><a name="left-2">left/2</a></h3>
75
76 <p><code>left(pid(), N::integer()) -> ok</code></p>
77 <p>Moves the read/write head N positions left on the tape.</p>
78
79 <h3><a name="read-1">read/1</a></h3>
80
81 <p><code>read(pid()) -> integer()</code></p>
82 <p>Returns the value at the current position on the tape.</p>
83
84 <h3><a name="right-1">right/1</a></h3>
85
86 <p><code>right(pid()) -> ok</code></p>
87 <p>Moves the read/write head one position right on the tape.</p>
88
89 <h3><a name="right-2">right/2</a></h3>
90
91 <p><code>right(pid(), N::integer()) -> ok</code></p>
92 <p>Moves the read/write head N positions right on the tape.</p>
93
94 <h3><a name="server-2">server/2</a></h3>
95
96 <p><code>server(Arg1, Arg2) -> term()</code></p>
97 <p> </p>
98
99 <h3><a name="start-3">start/3</a></h3>
100
101 <p><code>start(<a href="#type-module">module()</a>, Supervisor::pid(), [<a href="#type-option">option()</a>]) -> pid()<ul><li><a name="type-option">option()</a> = {atom(), term()}</li></ul></code></p>
102 <p>Starts and returns the pid of a new tape server.
103 For a description of the allowed options, see the documentation for
104 the <code><a href="pibfi.html">pibfi</a></code> module.</p>
105
106 <h3><a name="write-2">write/2</a></h3>
107
108 <p><code>write(<a href="#type-tape">tape()</a>, integer()) -> {ok, integer()} | {error, Reason}</code></p>
109 <p>Places the given value at the current position on the tape.</p></body>
110 </html>
0 <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
1 <html>
2 <head>
3 <title>Module pibfi_tape_dict</title>
4
5 </head>
6 <body bgcolor="white">
7 <h1>Module pibfi_tape_dict</h1>
8 <ul><li>
9 <a href="#index">Function index</a></li><li>
10 <a href="#exported">Exported functions</a></li></ul>
11
12 <h2>Description</h2>
13 Dict backend for tape ADT for the Platonic Ideal Brainf*ck Interpreter.
14
15
16 <h2><a name="index">Function Index</a></h2>
17
18 <table width="100%" border="1"><tr><th colspan="2" align="left">Exported Functions</th></tr>
19 <tr><td><a href="#head-1">head/1</a></td><td/></tr>
20 <tr><td><a href="#left-2">left/2</a></td><td>Moves the read/write head N positions left on the tape.</td></tr>
21 <tr><td><a href="#new-1">new/1</a></td><td>Creates and returns a new tape.</td></tr>
22 <tr><td><a href="#peek-2">peek/2</a></td><td/></tr>
23 <tr><td><a href="#poke-3">poke/3</a></td><td/></tr>
24 <tr><td><a href="#read-1">read/1</a></td><td>Returns the value at the current position on the tape.</td></tr>
25 <tr><td><a href="#right-2">right/2</a></td><td>Moves the read/write head N positions right on the tape.</td></tr>
26 <tr><td><a href="#write-2">write/2</a></td><td>Places the given value at the current position on the tape.</td></tr>
27 </table>
28
29 <h2><a name="exported">Exported Functions</a></h2>
30
31 <h3><a name="head-1">head/1</a></h3>
32
33 <p><code>head(Arg1) -> term()</code></p>
34 <p> </p>
35
36 <h3><a name="left-2">left/2</a></h3>
37
38 <p><code>left(<a href="#type-tape">tape()</a>, N::integer()) -> {<a href="#type-tape">tape()</a>, integer()}</code></p>
39 <p>Moves the read/write head N positions left on the tape.</p>
40
41 <h3><a name="new-1">new/1</a></h3>
42
43 <p><code>new([<a href="#type-option">option()</a>]) -> <a href="#type-tape">tape()</a><ul><li><a name="type-option">option()</a> = {atom(), term()}</li><li><a name="type-tape">tape()</a> = <a href="#type-tape">tape()</a></li></ul></code></p>
44 <p>Creates and returns a new tape.
45 For a description of the allowed options, see the documentation for
46 the <code><a href="pibfi.html">pibfi</a></code> module.</p>
47
48 <h3><a name="peek-2">peek/2</a></h3>
49
50 <p><code>peek(Arg1, Arg2) -> term()</code></p>
51 <p> </p>
52
53 <h3><a name="poke-3">poke/3</a></h3>
54
55 <p><code>poke(Arg1, Arg2, Arg3) -> term()</code></p>
56 <p> </p>
57
58 <h3><a name="read-1">read/1</a></h3>
59
60 <p><code>read(<a href="#type-tape">tape()</a>) -> integer()</code></p>
61 <p>Returns the value at the current position on the tape.</p>
62
63 <h3><a name="right-2">right/2</a></h3>
64
65 <p><code>right(<a href="#type-tape">tape()</a>, N::integer()) -> {<a href="#type-tape">tape()</a>, integer()}</code></p>
66 <p>Moves the read/write head N positions right on the tape.</p>
67
68 <h3><a name="write-2">write/2</a></h3>
69
70 <p><code>write(<a href="#type-tape">tape()</a>, integer()) -> {<a href="#type-tape">tape()</a>, integer()}</code></p>
71 <p>Places the given value at the current position on the tape.</p></body>
72 </html>
0 <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
1 <html>
2 <head>
3 <title>Module pibfi_tape_dynarray</title>
4
5 </head>
6 <body bgcolor="white">
7 <h1>Module pibfi_tape_dynarray</h1>
8 <ul><li>
9 <a href="#index">Function index</a></li><li>
10 <a href="#exported">Exported functions</a></li></ul>
11
12 <h2>Description</h2>
13 dynarray backend for tape ADT for <code>pibfi</code>.
14
15
16 <h2><a name="index">Function Index</a></h2>
17
18 <table width="100%" border="1"><tr><th colspan="2" align="left">Exported Functions</th></tr>
19 <tr><td><a href="#decrement-2">decrement/2</a></td><td>Decrements the value at the current position on the tape N times.</td></tr>
20 <tr><td><a href="#head-1">head/1</a></td><td/></tr>
21 <tr><td><a href="#increment-2">increment/2</a></td><td>Increments the value at the current position on the tape N times.</td></tr>
22 <tr><td><a href="#left-2">left/2</a></td><td>Moves the read/write head N positions left on the tape.</td></tr>
23 <tr><td><a href="#new-1">new/1</a></td><td>Creates and returns a new dynarray-backed tape.</td></tr>
24 <tr><td><a href="#peek-2">peek/2</a></td><td/></tr>
25 <tr><td><a href="#poke-3">poke/3</a></td><td/></tr>
26 <tr><td><a href="#read-1">read/1</a></td><td>Returns the value at the current position on the tape.</td></tr>
27 <tr><td><a href="#right-2">right/2</a></td><td>Moves the read/write head N positions right on the tape.</td></tr>
28 <tr><td><a href="#write-2">write/2</a></td><td>Places the given value at the current position on the tape.</td></tr>
29 </table>
30
31 <h2><a name="exported">Exported Functions</a></h2>
32
33 <h3><a name="decrement-2">decrement/2</a></h3>
34
35 <p><code>decrement(<a href="#type-tape">tape()</a>, N::integer()) -> <a href="#type-tape">tape()</a></code></p>
36 <p>Decrements the value at the current position on the tape N times.</p>
37
38 <h3><a name="head-1">head/1</a></h3>
39
40 <p><code>head(Arg1) -> term()</code></p>
41 <p> </p>
42
43 <h3><a name="increment-2">increment/2</a></h3>
44
45 <p><code>increment(<a href="#type-tape">tape()</a>, N::integer()) -> <a href="#type-tape">tape()</a></code></p>
46 <p>Increments the value at the current position on the tape N times.</p>
47
48 <h3><a name="left-2">left/2</a></h3>
49
50 <p><code>left(<a href="#type-tape">tape()</a>, N::integer()) -> {<a href="#type-tape">tape()</a>, integer()}</code></p>
51 <p>Moves the read/write head N positions left on the tape.</p>
52
53 <h3><a name="new-1">new/1</a></h3>
54
55 <p><code>new([<a href="#type-option">option()</a>]) -> <a href="#type-tape">tape()</a><ul><li><a name="type-option">option()</a> = {atom(), term()}</li><li><a name="type-tape">tape()</a> = <a href="#type-tape">tape()</a></li></ul></code></p>
56 <p>Creates and returns a new dynarray-backed tape.</p>
57
58 <h3><a name="peek-2">peek/2</a></h3>
59
60 <p><code>peek(Arg1, Arg2) -> term()</code></p>
61 <p> </p>
62
63 <h3><a name="poke-3">poke/3</a></h3>
64
65 <p><code>poke(Arg1, Arg2, Arg3) -> term()</code></p>
66 <p> </p>
67
68 <h3><a name="read-1">read/1</a></h3>
69
70 <p><code>read(<a href="#type-tape">tape()</a>) -> integer()</code></p>
71 <p>Returns the value at the current position on the tape.</p>
72
73 <h3><a name="right-2">right/2</a></h3>
74
75 <p><code>right(<a href="#type-tape">tape()</a>, N::integer()) -> {<a href="#type-tape">tape()</a>, integer()}</code></p>
76 <p>Moves the read/write head N positions right on the tape.</p>
77
78 <h3><a name="write-2">write/2</a></h3>
79
80 <p><code>write(<a href="#type-tape">tape()</a>, integer()) -> {<a href="#type-tape">tape()</a>, integer()}</code></p>
81 <p>Places the given value at the current position on the tape.</p></body>
82 </html>
0 <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
1 <html>
2 <head>
3 <title>Module pibfi_tape_ets</title>
4
5 </head>
6 <body bgcolor="white">
7 <h1>Module pibfi_tape_ets</h1>
8 <ul><li>
9 <a href="#index">Function index</a></li><li>
10 <a href="#exported">Exported functions</a></li></ul>
11
12 <h2>Description</h2>
13 ETS backend for tape ADT for the Platonic Ideal Brainf*ck Interpreter.
14
15
16 <h2><a name="index">Function Index</a></h2>
17
18 <table width="100%" border="1"><tr><th colspan="2" align="left">Exported Functions</th></tr>
19 <tr><td><a href="#head-1">head/1</a></td><td/></tr>
20 <tr><td><a href="#left-2">left/2</a></td><td>Moves the read/write head N positions left on the tape.</td></tr>
21 <tr><td><a href="#new-1">new/1</a></td><td>Creates and returns a new ETS-backed tape.</td></tr>
22 <tr><td><a href="#peek-2">peek/2</a></td><td/></tr>
23 <tr><td><a href="#poke-3">poke/3</a></td><td/></tr>
24 <tr><td><a href="#read-1">read/1</a></td><td>Returns the value at the current position on the tape.</td></tr>
25 <tr><td><a href="#right-2">right/2</a></td><td>Moves the read/write head N positions right on the tape.</td></tr>
26 <tr><td><a href="#write-2">write/2</a></td><td>Places the given value at the current position on the tape.</td></tr>
27 </table>
28
29 <h2><a name="exported">Exported Functions</a></h2>
30
31 <h3><a name="head-1">head/1</a></h3>
32
33 <p><code>head(Arg1) -> term()</code></p>
34 <p> </p>
35
36 <h3><a name="left-2">left/2</a></h3>
37
38 <p><code>left(<a href="#type-tape">tape()</a>, N::integer()) -> {<a href="#type-tape">tape()</a>, integer()}</code></p>
39 <p>Moves the read/write head N positions left on the tape.</p>
40
41 <h3><a name="new-1">new/1</a></h3>
42
43 <p><code>new([<a href="#type-option">option()</a>]) -> <a href="#type-tape">tape()</a><ul><li><a name="type-option">option()</a> = {atom(), term()}</li><li><a name="type-tape">tape()</a> = <a href="#type-tape">tape()</a></li></ul></code></p>
44 <p>Creates and returns a new ETS-backed tape.</p>
45
46 <h3><a name="peek-2">peek/2</a></h3>
47
48 <p><code>peek(Arg1, Arg2) -> term()</code></p>
49 <p> </p>
50
51 <h3><a name="poke-3">poke/3</a></h3>
52
53 <p><code>poke(Arg1, Arg2, Arg3) -> term()</code></p>
54 <p> </p>
55
56 <h3><a name="read-1">read/1</a></h3>
57
58 <p><code>read(<a href="#type-tape">tape()</a>) -> integer()</code></p>
59 <p>Returns the value at the current position on the tape.</p>
60
61 <h3><a name="right-2">right/2</a></h3>
62
63 <p><code>right(<a href="#type-tape">tape()</a>, N::integer()) -> {<a href="#type-tape">tape()</a>, integer()}</code></p>
64 <p>Moves the read/write head N positions right on the tape.</p>
65
66 <h3><a name="write-2">write/2</a></h3>
67
68 <p><code>write(<a href="#type-tape">tape()</a>, integer()) -> {<a href="#type-tape">tape()</a>, integer()}</code></p>
69 <p>Places the given value at the current position on the tape.</p></body>
70 </html>
0 <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
1 <html>
2 <head>
3 <title>Module pibfi_tape_tuple</title>
4
5 </head>
6 <body bgcolor="white">
7 <h1>Module pibfi_tape_tuple</h1>
8 <ul><li>
9 <a href="#index">Function index</a></li><li>
10 <a href="#exported">Exported functions</a></li></ul>
11
12 <h2>Description</h2>
13 Tuple backend for tape ADT for <code>pibfi</code>.
14
15
16 <h2><a name="index">Function Index</a></h2>
17
18 <table width="100%" border="1"><tr><th colspan="2" align="left">Exported Functions</th></tr>
19 <tr><td><a href="#decrement-2">decrement/2</a></td><td>Decrements the value at the current position on the tape N times.</td></tr>
20 <tr><td><a href="#head-1">head/1</a></td><td/></tr>
21 <tr><td><a href="#increment-2">increment/2</a></td><td>Increments the value at the current position on the tape N times.</td></tr>
22 <tr><td><a href="#left-2">left/2</a></td><td>Moves the read/write head N positions left on the tape.</td></tr>
23 <tr><td><a href="#new-1">new/1</a></td><td>Creates and returns a new tuple-backed tape.</td></tr>
24 <tr><td><a href="#peek-2">peek/2</a></td><td/></tr>
25 <tr><td><a href="#poke-3">poke/3</a></td><td/></tr>
26 <tr><td><a href="#read-1">read/1</a></td><td>Returns the value at the current position on the tape.</td></tr>
27 <tr><td><a href="#right-2">right/2</a></td><td>Moves the read/write head N positions right on the tape.</td></tr>
28 <tr><td><a href="#write-2">write/2</a></td><td>Places the given value at the current position on the tape.</td></tr>
29 </table>
30
31 <h2><a name="exported">Exported Functions</a></h2>
32
33 <h3><a name="decrement-2">decrement/2</a></h3>
34
35 <p><code>decrement(<a href="#type-tape">tape()</a>, N::integer()) -> <a href="#type-tape">tape()</a></code></p>
36 <p>Decrements the value at the current position on the tape N times.</p>
37
38 <h3><a name="head-1">head/1</a></h3>
39
40 <p><code>head(Arg1) -> term()</code></p>
41 <p> </p>
42
43 <h3><a name="increment-2">increment/2</a></h3>
44
45 <p><code>increment(<a href="#type-tape">tape()</a>, N::integer()) -> <a href="#type-tape">tape()</a></code></p>
46 <p>Increments the value at the current position on the tape N times.</p>
47
48 <h3><a name="left-2">left/2</a></h3>
49
50 <p><code>left(<a href="#type-tape">tape()</a>, N::integer()) -> {<a href="#type-tape">tape()</a>, integer()}</code></p>
51 <p>Moves the read/write head N positions left on the tape.</p>
52
53 <h3><a name="new-1">new/1</a></h3>
54
55 <p><code>new([<a href="#type-option">option()</a>]) -> <a href="#type-tape">tape()</a><ul><li><a name="type-option">option()</a> = {atom(), term()}</li><li><a name="type-tape">tape()</a> = <a href="#type-tape">tape()</a></li></ul></code></p>
56 <p>Creates and returns a new tuple-backed tape.</p>
57
58 <h3><a name="peek-2">peek/2</a></h3>
59
60 <p><code>peek(Arg1, Arg2) -> term()</code></p>
61 <p> </p>
62
63 <h3><a name="poke-3">poke/3</a></h3>
64
65 <p><code>poke(Arg1, Arg2, Arg3) -> term()</code></p>
66 <p> </p>
67
68 <h3><a name="read-1">read/1</a></h3>
69
70 <p><code>read(<a href="#type-tape">tape()</a>) -> integer()</code></p>
71 <p>Returns the value at the current position on the tape.</p>
72
73 <h3><a name="right-2">right/2</a></h3>
74
75 <p><code>right(<a href="#type-tape">tape()</a>, N::integer()) -> {<a href="#type-tape">tape()</a>, integer()}</code></p>
76 <p>Moves the read/write head N positions right on the tape.</p>
77
78 <h3><a name="write-2">write/2</a></h3>
79
80 <p><code>write(<a href="#type-tape">tape()</a>, integer()) -> {<a href="#type-tape">tape()</a>, integer()}</code></p>
81 <p>Places the given value at the current position on the tape.</p></body>
82 </html>
0 <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
1 <html>
2 <head>
3 <title>Module pibfi_xlat</title>
4
5 </head>
6 <body bgcolor="white">
7 <h1>Module pibfi_xlat</h1>
8 <ul><li>
9 <a href="#index">Function index</a></li><li>
10 <a href="#exported">Exported functions</a></li></ul>
11
12 <h2>Description</h2>
13 Character translation server for <code>pibfi</code>.
14
15 <p>This is not efficient. An efficient implementation would compile
16 the candidates into a finite-state machine first. This doesn't do that.</p>
17
18
19 <h2><a name="index">Function Index</a></h2>
20
21 <table width="100%" border="1"><tr><th colspan="2" align="left">Exported Functions</th></tr>
22 <tr><td><a href="#flush-1">flush/1</a></td><td>Causes the xlat server to flush all its characters to the output,
23 even ones in the process of matching candidate strings.</td></tr>
24 <tr><td><a href="#notify-2">notify/2</a></td><td>Notifies the other end of the connection.</td></tr>
25 <tr><td><a href="#send-2">send/2</a></td><td>Sends a character or characters to an xlat server for translation.</td></tr>
26 <tr><td><a href="#server-2">server/2</a></td><td>Spawned by <code>start/2</code>, should not be called
27 directly by user code.</td></tr>
28 <tr><td><a href="#start-2">start/2</a></td><td>Starts an xlat server.</td></tr>
29 <tr><td><a href="#test-0">test/0</a></td><td/></tr>
30 </table>
31
32 <h2><a name="exported">Exported Functions</a></h2>
33
34 <h3><a name="flush-1">flush/1</a></h3>
35
36 <p><code>flush(<a href="#type-xlat">xlat()</a>) -> ok</code></p>
37 <p>Causes the xlat server to flush all its characters to the output,
38 even ones in the process of matching candidate strings. Typically
39 this is called before the output is closed.</p>
40
41 <h3><a name="notify-2">notify/2</a></h3>
42
43 <p><code>notify(<a href="#type-xlat">xlat()</a>, term()) -> ok</code></p>
44 <p>Notifies the other end of the connection.
45 They will receive a <code>{Xlat::pid(), Notifier::pid(), message, term()}</code> message.</p>
46
47 <h3><a name="send-2">send/2</a></h3>
48
49 <p><code>send(<a href="#type-xlat">xlat()</a>, char() | string()) -> ok</code></p>
50 <p>Sends a character or characters to an xlat server for translation.</p>
51
52 <h3><a name="server-2">server/2</a></h3>
53
54 <p><code>server(<a href="#type-candidates">candidates()</a>, Dest::pid()) -> <a href="#type-never_returns">never_returns()</a></code></p>
55 <p>Spawned by <code>start/2</code>, should not be called
56 directly by user code.</p>
57
58 <h3><a name="start-2">start/2</a></h3>
59
60 <p><code>start(<a href="#type-candidates">candidates()</a>, Dest::pid()) -> <a href="#type-xlat">xlat()</a><ul><li><a name="type-candidates">candidates()</a> = [{string(), string()}]</li><li><a name="type-xlat">xlat()</a> = pid()</li><li><a name="type-string">string()</a> = [char()]</li><li><a name="type-char">char()</a> = integer()</li></ul></code></p>
61 <p>Starts an xlat server. Candidates is a list of pairs of strings.
62 Characters are sent to the xlat server with the <code>send/2</code>
63 function. When they match the left
64 string of a candidate, the right string is sent to Dest instead.
65 If they do not match any candidates, they are sent through unaltered.
66 Characters are sent to Dest in the form
67 <code>{xlat(), xlat_char, char()}</code>.
68 Note that if two candidates have the same left string, the result of
69 the translation is undefined. Also note that if one candidate has
70 a left string that is a prefix of another candidate's left string,
71 that second candidate will never match (the shorter one will always
72 be matched first.)</p>
73
74 <h3><a name="test-0">test/0</a></h3>
75
76 <p><code>test() -> term()</code></p>
77 <p> </p></body>
78 </html>
Binary diff not shown
Binary diff not shown
Binary diff not shown
Binary diff not shown
Binary diff not shown
Binary diff not shown
Binary diff not shown
Binary diff not shown
Binary diff not shown
Binary diff not shown
Binary diff not shown
Binary diff not shown
Binary diff not shown
Binary diff not shown
Binary diff not shown
0 ,[.#,]>++++++++++.
1 |Oh look, a here-doc.
0 >+++++++++++++++++++++++++++++++++++<+[[,.----------]>.<+]
0 +[,----------]
0 >+++++++++[<++++++++>-]<.>+++++++[<++++>-]<+.+++++++..+++.[-]>++++++++[<++++>-]
1 <.>+++++++++++[<+++++>-]<.>++++++++[<+++>-]<.+++.------.--------.[-]>++++++++[
2 <++++>-]<+.[-]++++++++++.
0 %%% BEGIN bf.erl %%%
1 %%%
2 %%% bf - pedantic Brainf*ck interpreter in Erlang
3 %%% Copyright (c)2002 Cat's Eye Technologies. All rights reserved.
4 %%%
5 %%% Redistribution and use in source and binary forms, with or without
6 %%% modification, are permitted provided that the following conditions
7 %%% are met:
8 %%%
9 %%% Redistributions of source code must retain the above copyright
10 %%% notice, this list of conditions and the following disclaimer.
11 %%%
12 %%% Redistributions in binary form must reproduce the above copyright
13 %%% notice, this list of conditions and the following disclaimer in
14 %%% the documentation and/or other materials provided with the
15 %%% distribution.
16 %%%
17 %%% Neither the name of Cat's Eye Technologies nor the names of its
18 %%% contributors may be used to endorse or promote products derived
19 %%% from this software without specific prior written permission.
20 %%%
21 %%% THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
22 %%% CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
23 %%% INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
24 %%% MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
25 %%% DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE
26 %%% LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
27 %%% OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
28 %%% PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
29 %%% OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
30 %%% ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
31 %%% OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
32 %%% OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
33 %%% POSSIBILITY OF SUCH DAMAGE.
34
35 %% @doc Cat's Eye Technologies' Erlang Brainf*ck Interpreter.
36 %%
37 %% <p>An implementation of the world's most beautifulest langugage
38 %% in the world's second most beautifulest language.</p>
39 %% <p>This program demonstrates:</p>
40 %% <ul>
41 %% <li> sequential programming in Erlang </li>
42 %% <li> simulating Brainf*ck's updatable store by passing arguments </li>
43 %% </ul>
44 %% <p>Variable names used in this program:</p>
45 %% <ul>
46 %% <li> I = Instruction pointer </li>
47 %% <li> B = Brainf*ck program </li>
48 %% <li> D = Data pointer (tape head position) </li>
49 %% <li> M = Memory (Brainf*ck tape) </li>
50 %% </ul>
51 %%
52 %% @end
53
54 -module(bf).
55 -vsn('2002.1208').
56 -copyright('Copyright (c)2002 Cat`s Eye Technologies. All rights reserved.').
57
58 -export([interpret/1, interpret/2, test/1]).
59
60 %% @spec interpret(B::[instruction()], StorageSize::integer()) ->
61 %% {integer(), tuple()}
62 %% instruction() = integer()
63 %% @doc The main user interface to the Brainf*ck interpreter.
64 %% The user generally passes a list, which is parsed into a tuple.
65 %% In this tuple, each Brainf*ck instruction represented by
66 %% an atom, except for <code>[</code> and <code>]</code>,
67 %% which are represented by a nested tuple to make interpretation simpler.
68 %% The return value is a tuple containing the data pointer and
69 %% another tuple representing the state of the Brainf*ck tape
70 %% after all is said and done.
71
72 interpret(B, N) when tuple(B) -> interpret(1, B, 1, erlang:make_tuple(N, 0));
73 interpret(B, N) when list(B) -> interpret(parse(B), N).
74
75 %% @spec interpret(B::[instruction()]) -> {integer(), tuple()}
76 %% @equiv interpret(Program, 512)
77
78 interpret(B) -> interpret(B, 512). % default memsize, use interpret/2 to specify
79
80 %% @spec interpret(I::integer(), B::[instruction()], D::integer(), M::tuple) -> {integer(), tuple()}
81 %% @doc The internal driver which implements the execution loop.
82 %% When the I pointer is at the end of the program, processing is finished.
83 %% But more usually, I will be travelling forward through B.
84
85 interpret(I, B, D, M) when I > size(B) -> {D, M};
86 interpret(I, B, D, M) ->
87 {D2, M2} = execute(element(I, B), D, M),
88 interpret(I + 1, B, D2, M2).
89
90 %% @spec execute(instruction(), D::integer(), M::tuple) -> {integer(), tuple()}
91 %% @doc Executes specific, individual instructions. Erlang doesn't have an
92 %% updatable store like Brainf*ck (unless you count the process dictionary
93 %% (which you probably shouldn't,)) so instead we approach the problem by
94 %% continually deriving new stores from old stores, returning the new
95 %% store to the caller each time this function is called.
96
97 execute($>, D, M) -> {D + 1, M};
98 execute($<, D, M) -> {D - 1, M};
99 execute($+, D, M) -> {D, setelement(D, M, element(D, M) + 1)};
100 execute($-, D, M) -> {D, setelement(D, M, element(D, M) - 1)};
101
102 %% <p>I/O is fairly crude, and could stand to be improved.</p>
103
104 execute($., D, M) -> io:put_chars([element(D, M)]), {D, M};
105 execute($,, D, M) -> {D, setelement(D, M, hd(io:get_chars('bf> ', 1)))};
106
107 %% <p>The 'while' loop. A tuple represents a [...] structure; if
108 %% the data pointer points to a non-zero, the nested Brainf*ck
109 %% subprogram is executed, and the check is repeated.</p>
110
111 execute(B, D, M) when tuple(B), element(D, M) == 0 -> {D, M};
112 execute(B, D, M) when tuple(B) ->
113 {D2, M2} = interpret(1, B, D, M),
114 execute(B, D2, M2);
115
116 %% <p>Finally, comments and other line noise are ignored.</p>
117
118 execute(_, D, M) -> {D, M}.
119
120 %% @spec parse([instruction()]) -> tuple()
121 %% @doc Takes a string (list of ASCII values) and butchers
122 %% it into a nested tuple data structure, suitable for interpretation.
123 %% Writing this function elegantly
124 %% was much trickier than writing the imperative processing engine above.
125
126 parse(L) -> parse({}, L). % default is to add to fresh tuple
127
128 parse(U, []) -> U;
129 parse(U, [$]|T]) -> {U, T};
130 parse(U, [$[|T]) ->
131 {V, L} = parse({}, T),
132 parse(erlang:append_element(U, V), L);
133 parse(U, [H |T]) ->
134 parse(erlang:append_element(U, H), T).
135
136 %% @spec test(Test::integer()) -> {integer(), tuple()}
137 %% @doc Test functions, numbered from 1 upwards. They implement two of the
138 %% programs from the original Brainf*ck archive (hello and atoi).
139
140 test(1) -> test(hello);
141 test(hello) -> interpret("
142 >+++++++++[<++++++++>-]<.>+++++++[<++++>-]<+.+++++++..+++.[-]>++++++++[<++++>-]
143 <.>+++++++++++[<+++++>-]<.>++++++++[<+++>-]<.+++.------.--------.[-]>++++++++[
144 <++++>-]<+.[-]++++++++++."
145 );
146
147 test(2) -> test(atoi);
148 test(atoi) -> interpret("
149 ==== ==== ====
150 cont digi num
151 ==== ==== ====
152
153 +
154 [
155 - cont=0
156 >,
157 ======SUB10======
158 ----------
159
160 [ not 10
161 <+> cont=1
162 =====SUB38======
163 ----------
164 ----------
165 ----------
166 --------
167
168 >
169 =====MUL10=======
170 [>+>+<<-]>>[<<+>>-]< dup
171
172 >>>+++++++++
173 [
174 <<<
175 [>+>+<<-]>>[<<+>>-]< dup
176 [<<+>>-]
177 >>-
178 ]
179 <<<[-]<
180 ======RMOVE1======
181 <
182 [>+<-]
183 ]
184 <
185 ]
186 >>[<<+>>-]<<
187 #"
188 ).
189
190 %%% END of bf.erl %%%
0 %%% BEGIN pibfi.erl %%%
1 %%%
2 %%% pibfi - Platonic Ideal Brainf*ck Interpreter
3 %%% Copyright (c)2003 Cat's Eye Technologies. All rights reserved.
4 %%%
5 %%% Redistribution and use in source and binary forms, with or without
6 %%% modification, are permitted provided that the following conditions
7 %%% are met:
8 %%%
9 %%% Redistributions of source code must retain the above copyright
10 %%% notice, this list of conditions and the following disclaimer.
11 %%%
12 %%% Redistributions in binary form must reproduce the above copyright
13 %%% notice, this list of conditions and the following disclaimer in
14 %%% the documentation and/or other materials provided with the
15 %%% distribution.
16 %%%
17 %%% Neither the name of Cat's Eye Technologies nor the names of its
18 %%% contributors may be used to endorse or promote products derived
19 %%% from this software without specific prior written permission.
20 %%%
21 %%% THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
22 %%% CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
23 %%% INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
24 %%% MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
25 %%% DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE
26 %%% LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
27 %%% OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
28 %%% PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
29 %%% OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
30 %%% ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
31 %%% OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
32 %%% OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
33 %%% POSSIBILITY OF SUCH DAMAGE.
34
35 %% @doc Platonic Ideal Brainf*ck Interpreter (<code>pibfi</code>).
36 %%
37 %% <p>This application implements an interpreter for the language
38 %% Brainf*ck. It does not by default impose any limit on the maximum
39 %% length of the tape, nor the maximum value that can entered into
40 %% any of the cells in the tape (beyond those limits inescapably
41 %% imposed upon it by the underlying operating system and hardware.)
42 %% It can, however, be configured to simulate the limits imposed upon
43 %% the language by many other implementations which sacrifice
44 %% scaleability in order to achieve other goals (usually, to build an
45 %% astonishingly small compiler or interpreter.)</p>
46 %%
47 %% <p>As such, <code>pibfi</code> may be in a position to one day
48 %% develop into a universal (or at least reference) interpreter for
49 %% the Brainf*ck language.</p>
50 %%
51 %% <p>For a synopsis of the command-line options that can be used
52 %% with <code>pibfi</code>, see the
53 %% <code><a href="pibfi_options.html">pibfi_options</a></code>
54 %% documentation.</p>
55 %%
56 %% <p>This module contains the interface to start <code>pibfi</code>
57 %% both from the command line, and programmatically. It also contains
58 %% common functions used by other <code>pibfi_*</code> modules.</p>
59 %%
60 %% <p>Parts of this program were derived from the Erlang example
61 %% program <code>bf.erl</code>.</p>
62 %%
63 %% @end
64
65 -module(pibfi).
66 -vsn('2003.0505').
67 -copyright('Copyright (c)2003 Cat`s Eye Technologies. All rights reserved.').
68
69 -export([run/1, startup/2, run/6]).
70 -export([wrap/3, assert/2, assert_in_bounds/4]).
71 -export([whisper/1, whisper/2]).
72 -export([os_eol/0]).
73
74 %% @spec run(Args::[string()]) -> halt()
75 %% @doc Starts <code>pibfi</code> for the purposes of running a Brainf*ck
76 %% program. This function is intended to be invoked
77 %% from the command line. When using <code>pibfi</code> from another Erlang
78 %% program, or from the Erlang shell, it is suggested you call
79 %% <code>run/6</code> instead.
80
81 run([Filename]) ->
82 Supervisor = pibfi_supervisor:start(),
83 pibfi_supervisor:spawn_link(Supervisor, "startup", critical,
84 ?MODULE, startup, [Supervisor, Filename]).
85
86 startup(Supervisor, Filename) ->
87 ParserOptions = pibfi_options:get_opts(
88 [
89 {dontstrip, ""},
90 {optimize, 1},
91 {statuscmd, "#"},
92 {heredoc, undefined}
93 ]),
94 TapeOptions = pibfi_options:get_opts(
95 [
96 {tapemodule, pibfi_tape_ets},
97 {maxcell, infinity},
98 {mincell, 0},
99 {wrapcell, false},
100 {maxtape, infinity},
101 {mintape, 0},
102 {wraptape, false}
103 ]),
104 IOOptions = pibfi_options:get_opts(
105 [
106 {infile, tty},
107 {outfile, tty},
108 {maxout, infinity},
109 {minout, 0},
110 {wrapout, false},
111 {maxin, infinity},
112 {minin, 0},
113 {wrapin, false},
114 {eof, 0},
115 {xlatout, [{"\n", os_eol()}]},
116 {xlatin, [{os_eol(), "\n"}]}
117 ]),
118 DebugOptions = pibfi_options:get_opts(
119 [
120 {statusevery, undefined}
121 ]),
122
123 {ok, {B, [Version]}} = beam_lib:version(code:which(?MODULE)),
124 VersionString = atom_to_list(Version),
125 whisper("pibfi: Platonic Ideal Brainf*ck Interpreter v~s", [VersionString]),
126 whisper("Copyright (c)2003 Cat's Eye Technologies. All rights reserved."),
127 whisper("Program file name: ~s", [Filename]),
128 whisper("Parser options: ~s", [map_format(ParserOptions)]),
129 whisper("Tape options: ~s", [map_format(TapeOptions)]),
130 whisper("I/O options: ~s", [map_format(IOOptions)]),
131 whisper("Debug options: ~s", [map_format(DebugOptions)]),
132 whisper("--------------BEGIN PROGRAM OUTPUT--------------"),
133
134 Program = case read_source_file(Filename) of
135 {ok, FileContents} ->
136 pibfi_supervisor:spawn_link(Supervisor, "interpreter", critical,
137 ?MODULE, run, [Supervisor, FileContents,
138 ParserOptions, TapeOptions, IOOptions, DebugOptions]);
139 Else ->
140 exit({could_not_read_file, Filename})
141 end.
142
143 %% @spec run(Supervisor::pid(), ProgramSource::binary(),
144 %% ParserOptions::[{atom(), term()}],
145 %% TapeOptions::[{atom(), term()}],
146 %% IOOptions::[{atom(), term()}],
147 %% DebugOptions::[{atom(), term()}]) -> tape()
148 %% program() = string() | binary() | tuple()
149 %% @doc Runs a Brainf*ck program.
150
151 run(Supervisor, ProgramSource, ParserOptions, TapeOptions, IOOptions, DebugOptions) ->
152 {Program, HereDoc} = pibfi_parser:parse(ProgramSource, ParserOptions),
153 CannedInput = case pibfi_options:get_option(IOOptions, infile, undefined) of
154 heredoc ->
155 HereDoc;
156 _ ->
157 ""
158 end,
159 IoPid = pibfi_io:start(Supervisor, IOOptions, CannedInput),
160 Module = pibfi_options:get_option(TapeOptions, tapemodule, pibfi_tape_dict),
161 TapePid = pibfi_tape:start(Module, Supervisor, TapeOptions),
162 pibfi_statistics:start(Supervisor, TapePid, DebugOptions),
163 pibfi_interpreter:interpret(Program, ParserOptions, TapePid, IoPid),
164 pibfi_io:flush(IoPid),
165 pibfi_io:stop(IoPid),
166 TapePid.
167
168 map_format(List) ->
169 lists:map(fun
170 ({Atom, Term}) when Atom == xlatin; Atom == xlatout ->
171 io_lib:fwrite("~p=[~s] ", [Atom, map_format(Term)]);
172 ({Atom, Term}) ->
173 io_lib:fwrite("~p=~p ", [Atom, Term])
174 end, List).
175
176 read_source_file("http://" ++ RestOfURL) ->
177 case http:request_sync(get, {"http://" ++ RestOfURL, []}) of
178 {200, Headers, Body} ->
179 {ok, list_to_binary(Body)};
180 {Response, Headers, Body} ->
181 {error, {unexpected_response_code, Response}}
182 end;
183 read_source_file(Filename) ->
184 file:read_file(Filename).
185
186 %% @spec wrap(Value::integer(), Max::integer(), Min::integer()) -> integer()
187 %% @doc Implements a generic modulus function. Both the top and bottom
188 %% modulus limits may be specified.
189
190 wrap(X, Min, Max) ->
191 case (X - Min) rem ((Max - Min) + 1) of
192 Y when Y < 0 ->
193 Max + 1 + Y;
194 Y when Y >= 0 ->
195 Y + Min
196 end.
197
198 %% @spec assert(Condition::boolean(), ErrorReason::term()) -> true
199 %% @doc Asserts that the condition is true. If it is not, the
200 %% process crashes with the given reason.
201
202 assert(true, _) ->
203 true;
204 assert(false, Reason) ->
205 exit(Reason).
206
207 assert_in_bounds(Type, Min, Test, Max) ->
208 Reason = {out_of_bounds, {{Type, Test}, {Min, Max}}},
209 case {Max, Min} of
210 {infinity, infinity} ->
211 true;
212 {infinity, _} ->
213 assert(Test >= Min, Reason);
214 {_, infinity} ->
215 assert(Test =< Max, Reason);
216 {_, _} ->
217 assert(Test >= Min andalso Test =< Max, Reason)
218 end.
219
220 %% @spec whisper(string()) -> ok
221 %% @equiv whisper(string(), [])
222
223 whisper(String) ->
224 whisper(String, []).
225
226 %% @spec whisper(string(), [term()]) -> ok
227 %% @doc Displays extra information. The user can shut this off with
228 %% <code>-quiet</code>.
229
230 whisper(FmtString, Args) ->
231 case pibfi_options:get_flag(quiet) of
232 false ->
233 io:fwrite(FmtString ++ "~n", Args);
234 true ->
235 ok
236 end.
237
238 %% @spec os_eol() -> string()
239 %% @doc Returns the native end-of-line convention, if it can be determined.
240 %% If it cannot be determined, linefeed (ASCII character 10) is assumed.
241
242 os_eol() ->
243 case os:type() of
244 {win32, _} ->
245 [13, 10];
246 _ ->
247 [10]
248 end.
249
250 %%% END of pibfi.erl %%%
0 %%% BEGIN pibfi_fliter.erl %%%
1 %%%
2 %%% pibfi - Platonic Ideal Brainf*ck Interpreter
3 %%% Copyright (c)2003 Cat's Eye Technologies. All rights reserved.
4 %%%
5 %%% Redistribution and use in source and binary forms, with or without
6 %%% modification, are permitted provided that the following conditions
7 %%% are met:
8 %%%
9 %%% Redistributions of source code must retain the above copyright
10 %%% notice, this list of conditions and the following disclaimer.
11 %%%
12 %%% Redistributions in binary form must reproduce the above copyright
13 %%% notice, this list of conditions and the following disclaimer in
14 %%% the documentation and/or other materials provided with the
15 %%% distribution.
16 %%%
17 %%% Neither the name of Cat's Eye Technologies nor the names of its
18 %%% contributors may be used to endorse or promote products derived
19 %%% from this software without specific prior written permission.
20 %%%
21 %%% THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
22 %%% CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
23 %%% INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
24 %%% MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
25 %%% DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE
26 %%% LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
27 %%% OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
28 %%% PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
29 %%% OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
30 %%% ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
31 %%% OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
32 %%% OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
33 %%% POSSIBILITY OF SUCH DAMAGE.
34
35 %% @doc Stream filtering for the Platonic Ideal Brainf*ck Interpreter.
36 %%
37 %% @end
38
39 -module(pibfi_filter).
40 -vsn('2003.0427').
41 -copyright('Copyright (c)2003 Cat`s Eye Technologies. All rights reserved.').
42
43 -export([start/6, server/5]).
44 -export([send/2, notify/2]).
45
46 %% @spec start(Supervisor::pid(), Role::atom(), Dest::pid(),
47 %% MaxThru::integer(), MinThru::integer(), WrapThru::integer()) -> pid()
48 %% @doc Creates and spawns a new stream filter.
49
50 start(Supervisor, Role, Dest, MaxThru, MinThru, WrapThru) ->
51 Name = atom_to_list(Role) ++ " filter",
52 pibfi_supervisor:spawn_link(Supervisor, Name, noncritical,
53 ?MODULE, server, [Dest, Role, MaxThru, MinThru, WrapThru]).
54
55 server(Dest, Role, MaxThru, MinThru, WrapThru) ->
56 receive
57 {Pid, Originator, message, Term} ->
58 Dest ! {self(), Originator, message, Term},
59 server(Dest, Role, MaxThru, MinThru, WrapThru);
60 {Pid, notify, Term} ->
61 Dest ! {self(), Pid, message, Term},
62 server(Dest, Role, MaxThru, MinThru, WrapThru);
63 {Pid, xlat_char, Char} ->
64 Dest ! {self(), xlat_char, filter(Role, MaxThru, MinThru, WrapThru, Char)},
65 server(Dest, Role, MaxThru, MinThru, WrapThru)
66 end.
67
68 filter(Role, MaxIn, MinIn, false, Char) ->
69 pibfi:assert_in_bounds({Role, character}, MinIn, Char, MaxIn),
70 Char;
71 filter(Role, MaxIn, MinIn, true, Char) ->
72 pibfi:wrap(Char, MinIn, MaxIn).
73
74 %% @spec send(xlat(), char() | string()) -> ok
75 %% @doc Sends a character or characters to a filter server for filtration.
76
77 send(Pid, Chars) when is_list(Chars) ->
78 lists:foreach(fun(Char) ->
79 % timer:sleep(100),
80 Pid ! {self(), xlat_char, Char}
81 end, Chars),
82 ok;
83
84 send(Pid, Char) ->
85 Pid ! {self(), xlat_char, Char},
86 ok.
87
88 %% @spec notify(xlat(), term()) -> ok
89 %% @doc Notifies the other end of the connection.
90 %% They will receive a <code>{Filter::pid(), Notifier::pid(), message, term()}</code> message.
91
92 notify(Pid, Term) ->
93 Pid ! {self(), notify, Term},
94 ok.
95
96 %%% END of pibfi_input.erl %%%
0 %%% BEGIN pibfi_input.erl %%%
1 %%%
2 %%% pibfi - Platonic Ideal Brainf*ck Interpreter
3 %%% Copyright (c)2003 Cat's Eye Technologies. All rights reserved.
4 %%%
5 %%% Redistribution and use in source and binary forms, with or without
6 %%% modification, are permitted provided that the following conditions
7 %%% are met:
8 %%%
9 %%% Redistributions of source code must retain the above copyright
10 %%% notice, this list of conditions and the following disclaimer.
11 %%%
12 %%% Redistributions in binary form must reproduce the above copyright
13 %%% notice, this list of conditions and the following disclaimer in
14 %%% the documentation and/or other materials provided with the
15 %%% distribution.
16 %%%
17 %%% Neither the name of Cat's Eye Technologies nor the names of its
18 %%% contributors may be used to endorse or promote products derived
19 %%% from this software without specific prior written permission.
20 %%%
21 %%% THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
22 %%% CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
23 %%% INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
24 %%% MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
25 %%% DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE
26 %%% LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
27 %%% OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
28 %%% PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
29 %%% OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
30 %%% ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
31 %%% OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
32 %%% OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
33 %%% POSSIBILITY OF SUCH DAMAGE.
34
35 %% @doc Input subsystem of the Platonic Ideal Brainf*ck Interpreter.
36 %%
37 %% @end
38
39 -module(pibfi_input).
40 -vsn('2003.0427').
41 -copyright('Copyright (c)2003 Cat`s Eye Technologies. All rights reserved.').
42
43 -export([start/6, server/5]).
44
45 %% @spec start(Supervisor::pid(), IoPid::pid(), Dest::pid(),
46 %% Interactive::boolean(),
47 %% Device, EOF) -> pid()
48 %% @doc Creates and spawns a new input subsystem.
49
50 start(Supervisor, IoPid, Dest, Interactive, Device, EOF) ->
51 pibfi_supervisor:spawn_link(Supervisor, "input", noncritical,
52 ?MODULE, server, [IoPid, Dest, Interactive, Device, EOF]).
53
54 server(IoPid, Dest, Interactive, Device, EOF) ->
55 % note that this is synchronous - we are essentially a send-only server.
56 % we can't react to messages until the user enters input - so we won't.
57 case io:get_chars(Device, '', 1) of
58 [10] ->
59 % we will always get 10 for an interactive incoming EOL, no matter
60 % what the operating system above us thinks
61 case Interactive of
62 false ->
63 pibfi_xlat:send(Dest, 10);
64 true ->
65 % so we actually have to simulate the action of the OS here
66 lists:foreach(fun(EOLChar) ->
67 pibfi_xlat:send(Dest, EOLChar)
68 end, pibfi:os_eol())
69 end,
70 server(IoPid, Dest, Interactive, Device, EOF);
71 [Char] ->
72 pibfi_xlat:send(Dest, Char),
73 server(IoPid, Dest, Interactive, Device, EOF);
74 eof ->
75 % ce_log:write("~p", [eof]),
76 case EOF of
77 halt ->
78 exit(halted_due_to_eof);
79 stop ->
80 pibfi_xlat:notify(Dest, stop);
81 nop ->
82 pibfi_xlat:notify(Dest, nop);
83 _ ->
84 pibfi_xlat:notify(Dest, EOF)
85 end,
86 exit(normal);
87 {error, terminated} ->
88 % IoPid ! {self(), direct, stop},
89 exit(normal);
90 Else ->
91 exit({halted_due_to_input_error, Else})
92 end.
93
94 %%% END of pibfi_input.erl %%%
0 %%% BEGIN pibfi_interpreter.erl %%%
1 %%%
2 %%% pibfi - Platonic Ideal Brainf*ck Interpreter
3 %%% Copyright (c)2003 Cat's Eye Technologies. All rights reserved.
4 %%%
5 %%% Redistribution and use in source and binary forms, with or without
6 %%% modification, are permitted provided that the following conditions
7 %%% are met:
8 %%%
9 %%% Redistributions of source code must retain the above copyright
10 %%% notice, this list of conditions and the following disclaimer.
11 %%%
12 %%% Redistributions in binary form must reproduce the above copyright
13 %%% notice, this list of conditions and the following disclaimer in
14 %%% the documentation and/or other materials provided with the
15 %%% distribution.
16 %%%
17 %%% Neither the name of Cat's Eye Technologies nor the names of its
18 %%% contributors may be used to endorse or promote products derived
19 %%% from this software without specific prior written permission.
20 %%%
21 %%% THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
22 %%% CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
23 %%% INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
24 %%% MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
25 %%% DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE
26 %%% LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
27 %%% OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
28 %%% PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
29 %%% OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
30 %%% ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
31 %%% OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
32 %%% OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
33 %%% POSSIBILITY OF SUCH DAMAGE.
34
35 %% @doc Interpreter for <code>pibfi</code>.
36 %%
37 %% @end
38
39 -module(pibfi_interpreter).
40 -vsn('2003.0427').
41 -copyright('Copyright (c)2003 Cat`s Eye Technologies. All rights reserved.').
42
43 -export([interpret/4]).
44
45 %% @spec interpret(program(), ParserOptions::[{atom(), term()}],
46 %% Tape::pid(), IoPid::pid()) -> ok
47 %% @doc Interprets a Brainf*ck program. If the program is given in
48 %% an unparsed (list or binary) form, it will be parsed into a
49 %% tuple form before proceeding.
50
51 interpret(Program, ParserOptions, TapePid, IoPid) when is_binary(Program) ->
52 interpret(pibfi_parser:parse(Program, ParserOptions), 1, TapePid, IoPid);
53 interpret(Program, ParserOptions, TapePid, IoPid) when is_list(Program) ->
54 interpret(pibfi_parser:parse(Program, ParserOptions), 1, TapePid, IoPid);
55 interpret(Program, ParserOptions, TapePid, IoPid) ->
56 [StatusCmd] = pibfi_options:get_option(ParserOptions, statuscmd, "#"),
57 interpret(Program, 1, TapePid, IoPid, StatusCmd).
58
59 interpret(Program, IP, TapePid, IoPid, StatusCmd) when IP > size(Program) ->
60 ok;
61 interpret(Program, IP, TapePid, IoPid, StatusCmd) ->
62 Instruction = element(IP, Program),
63 case Instruction of
64 {instruction, Row, Col, Ins} ->
65 pibfi_statistics:update_program(Row, Col, Ins);
66 {while, Row, Col, Block} ->
67 ok
68 end,
69 case execute(Instruction, TapePid, IoPid, StatusCmd) of
70 stop ->
71 stop;
72 _ ->
73 interpret(Program, IP + 1, TapePid, IoPid, StatusCmd)
74 end.
75
76 %% @spec execute(instruction(), Tape::pid(), IO::pid(), StatusCmd) -> ok
77 %% @doc Executes a single Brainf*ck instruction.
78
79 execute({instruction, Row, Column, $>}=I, TapePid, IoPid, StatusCmd) ->
80 pibfi_tape:right(TapePid);
81 execute({instruction, Row, Column, $<}=I, TapePid, IoPid, StatusCmd) ->
82 pibfi_tape:left(TapePid);
83 execute({instruction, Row, Column, $+}=I, TapePid, IoPid, StatusCmd) ->
84 pibfi_tape:increment(TapePid);
85 execute({instruction, Row, Column, $-}=I, TapePid, IoPid, StatusCmd) ->
86 pibfi_tape:decrement(TapePid);
87
88 execute({instruction, Row, Column, {$>, N}}=I, TapePid, IoPid, StatusCmd) ->
89 pibfi_tape:right(TapePid, N);
90 execute({instruction, Row, Column, {$<, N}}=I, TapePid, IoPid, StatusCmd) ->
91 pibfi_tape:left(TapePid, N);
92 execute({instruction, Row, Column, {$+, N}}=I, TapePid, IoPid, StatusCmd) ->
93 pibfi_tape:increment(TapePid, N);
94 execute({instruction, Row, Column, {$-, N}}=I, TapePid, IoPid, StatusCmd) ->
95 pibfi_tape:decrement(TapePid, N);
96
97 execute({instruction, Row, Column, $.}=I, TapePid, IoPid, StatusCmd) ->
98 Cell = pibfi_tape:read(TapePid),
99 pibfi_io:output(IoPid, Cell),
100 ok;
101 execute({instruction, Row, Column, $,}=I, TapePid, IoPid, StatusCmd) ->
102 % ce_log:write("input"),
103 case pibfi_io:input(IoPid) of
104 nop ->
105 ok;
106 stop ->
107 stop;
108 Character when is_integer(Character) ->
109 % ce_log:write("input ~c", [Character]),
110 pibfi_tape:write(TapePid, Character),
111 % ce_log:write("input stored as ~p", [pibfi_tape:read(TapePid)]),
112 ok
113 end;
114 execute({instruction, Row, Column, StatusCmd}=I, TapePid, IoPid, StatusCmd) ->
115 pibfi_statistics:dump(),
116 ok;
117 execute({while, Row, Column, SubProgram}=I, TapePid, IoPid, StatusCmd)
118 when tuple(SubProgram) ->
119 pibfi_statistics:update_program(Row, Column, $[),
120 case pibfi_tape:read(TapePid) of
121 0 ->
122 pibfi_statistics:update_program(Row, Column, $]),
123 ok;
124 _ ->
125 case interpret(SubProgram, 1, TapePid, IoPid, StatusCmd) of
126 stop ->
127 stop;
128 _ ->
129 pibfi_statistics:update_program(Row, Column, $]),
130 execute(I, TapePid, IoPid, StatusCmd)
131 end
132 end;
133 execute(_, TapePid, IoPid, StatusCmd) ->
134 ok.
135
136 %%% END of pibfi_interpreter.erl %%%
0 %%% BEGIN pibfi_io.erl %%%
1 %%%
2 %%% pibfi - Platonic Ideal Brainf*ck Interpreter
3 %%% Copyright (c)2003 Cat's Eye Technologies. All rights reserved.
4 %%%
5 %%% Redistribution and use in source and binary forms, with or without
6 %%% modification, are permitted provided that the following conditions
7 %%% are met:
8 %%%
9 %%% Redistributions of source code must retain the above copyright
10 %%% notice, this list of conditions and the following disclaimer.
11 %%%
12 %%% Redistributions in binary form must reproduce the above copyright
13 %%% notice, this list of conditions and the following disclaimer in
14 %%% the documentation and/or other materials provided with the
15 %%% distribution.
16 %%%
17 %%% Neither the name of Cat's Eye Technologies nor the names of its
18 %%% contributors may be used to endorse or promote products derived
19 %%% from this software without specific prior written permission.
20 %%%
21 %%% THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
22 %%% CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
23 %%% INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
24 %%% MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
25 %%% DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE
26 %%% LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
27 %%% OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
28 %%% PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
29 %%% OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
30 %%% ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
31 %%% OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
32 %%% OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
33 %%% POSSIBILITY OF SUCH DAMAGE.
34
35 %% @doc I/O subsystem of the Platonic Ideal Brainf*ck Interpreter.
36 %%
37 %% <p>Deals with the input and output servers, their filters, and
38 %% their translators.</p>
39 %%
40 %% @end
41
42 % ---> input translator ---> input filter --->
43 % terminal i/o <-> Brainf*ck
44 % or file subsys program
45 % <--- output translator <--- output filter <---
46
47 -module(pibfi_io).
48 -vsn('2003.0427').
49 -copyright('Copyright (c)2003 Cat`s Eye Technologies. All rights reserved.').
50
51 -export([start/3, stop/1, server/1]).
52 -export([input/1, output/2, flush/1]).
53
54 -record(io,
55 {
56 device = standard_io,
57 maxout = infinity,
58 minout = 0,
59 wrapout = false,
60 maxin = infinity,
61 minin = 0,
62 wrapin = false,
63 outxlat = [],
64 inxlat = [],
65 eof = 0
66 }).
67
68 %% @spec start(Supervisor::pid(), [option()], CannedInput::string()) -> pid()
69 %% @doc Creates and spawns a new I/O subsystem.
70 %% For a description of the allowed options, see the documentation for
71 %% the <code><a href="pibfi_options.html">pibfi_options</a></code> module.
72
73 start(Supervisor, Options, CannedInput) ->
74 IO = config(#io{}, Options),
75
76 % start i/o server
77 IoPid = pibfi_supervisor:spawn_link(Supervisor, "i/o subsystem",
78 critical, ?MODULE, server, [IO]),
79
80 % start filters & translators
81 InFilter = pibfi_filter:start(Supervisor, input, IoPid,
82 IO#io.maxin, IO#io.minin, IO#io.wrapin),
83
84 OutXlat = pibfi_xlat:start(IO#io.outxlat, IoPid),
85 pibfi_supervisor:link(Supervisor, "output translator", OutXlat),
86
87 InXlat = pibfi_xlat:start(IO#io.inxlat, InFilter),
88 pibfi_supervisor:link(Supervisor, "input translator", InXlat),
89
90 % start input server
91 InFile = pibfi_options:get_option(Options, infile, tty),
92 Interactive = InFile == tty,
93 IoDevice = case InFile of
94 tty ->
95 standard_io; % IO#io.device;
96 heredoc ->
97 undefined;
98 Filename ->
99 {ok, I} = file:open(Filename, [read, read_ahead]),
100 I
101 end,
102 case IoDevice of
103 undefined ->
104 % don't start an input server, do send canned input
105 lists:foreach(fun(Char) ->
106 % ce_log:write("sending canned ~c", [Char]),
107 pibfi_xlat:send(InXlat, Char)
108 end, CannedInput),
109 pibfi_xlat:notify(InXlat, IO#io.eof);
110 _ ->
111 InputPid = pibfi_input:start(Supervisor, IoPid, InXlat, Interactive,
112 IoDevice, IO#io.eof)
113 end,
114 % notify I/O server of who to talk to
115 IoPid ! {self(), hello, {OutXlat, InFilter}},
116 IoPid.
117
118 %% @spec server(IO) -> never_returns()
119 %% @doc Spawned by <code>start/1</code>.
120 %% Should not be called directly by user code.
121
122 server(IO) ->
123 receive
124 {Spawner, hello, {OutXlat, InFrom}} ->
125 loop(IO, OutXlat, InFrom)
126 end.
127
128 loop(IO, OutXlat, InFrom) ->
129 #io{
130 device = Device,
131 maxout = MaxOut,
132 minout = MinOut,
133 wrapout = WrapOut,
134 maxin = MaxIn,
135 minin = MinIn,
136 wrapin = WrapIn,
137 eof = EOF
138 } = IO,
139 % ce_log:write("looping"),
140 receive
141 {Pid, output, [Output]} ->
142 % ce_log:write("handling output request"),
143 pibfi_xlat:send(OutXlat, Output),
144 loop(IO, OutXlat, InFrom);
145 {OutXlat, xlat_char, Char} ->
146 % ce_log:write("handling xlated output ~c", [Char]),
147 write(Device, MaxOut, MinOut, WrapOut, Char),
148 loop(IO, OutXlat, InFrom);
149 {Pid, input, []} ->
150 case EOF of
151 % first check to see if we noticed the input server go down.
152 {eof, Char} when is_integer(Char) ->
153 Pid ! {self(), input, Char},
154 loop(IO, OutXlat, InFrom);
155 _ ->
156 input_loop(Pid, IO, OutXlat, InFrom)
157 end;
158 {Pid, flush} ->
159 pibfi_xlat:flush(OutXlat),
160 Result = flush_loop(IO, OutXlat, InFrom),
161 Pid ! {self(), flush, Result},
162 loop(IO, OutXlat, InFrom);
163 {Pid, stop} ->
164 % ce_log:write("stopping"),
165 Pid ! {self(), stop, ok}
166 end.
167
168 input_loop(Pid, IO, OutXlat, InFrom) ->
169 #io{
170 device = Device,
171 maxout = MaxOut,
172 minout = MinOut,
173 wrapout = WrapOut,
174 maxin = MaxIn,
175 minin = MinIn,
176 wrapin = WrapIn,
177 eof = EOF
178 } = IO,
179 receive
180 % in case the translation system decides to output something
181 % while we're waiting for input, we have to react to the
182 % output translator's messages here, too.
183 {OutXlat, xlat_char, Char} ->
184 % ce_log:write("handling xlated output ~c", [Char]),
185 write(Device, MaxOut, MinOut, WrapOut, Char),
186 input_loop(Pid, IO, OutXlat, InFrom);
187
188 % Receive messages from the input_server (possibly via the
189 % input translator / filter.)
190 {InFrom, xlat_char, Char} ->
191 % ce_log:write("input xlatted ~p", [Char]),
192 Pid ! {self(), input, Char},
193 loop(IO, OutXlat, InFrom);
194 {InFrom, _, message, X} ->
195 % direct, non-xlated msg from input server
196 % this means the input server has kicked the bucket
197 % and that we must know that for future input requests
198 % ce_log:write("direct input ~p", [X]),
199 Pid ! {self(), input, X},
200 IO0 = IO#io{ eof = {eof, IO#io.eof}},
201 loop(IO0, OutXlat, InFrom)
202 end.
203
204 flush_loop(IO, OutXlat, InXlat) ->
205 #io{
206 device = Device,
207 maxout = MaxOut,
208 minout = MinOut,
209 wrapout = WrapOut,
210 maxin = MaxIn,
211 minin = MinIn,
212 wrapin = WrapIn,
213 eof = EOF
214 } = IO,
215 receive
216 {OutXlat, xlat_char, Char} ->
217 % ce_log:write("flushing xlated output"),
218 write(Device, MaxOut, MinOut, WrapOut, Char),
219 flush_loop(IO, OutXlat, InXlat)
220 after 200 ->
221 ok
222 end.
223
224 %% @spec write(iodevice(), Max::integer(), Min::integer(), Wrap::boolean(),
225 %% char()) -> ok
226 %% @doc Writes a character to the output, within the given constraints.
227
228 write(Device, MaxOut, MinOut, false, Char) ->
229 pibfi:assert_in_bounds(output_character, MinOut, Char, MaxOut),
230 put_char(Device, Char);
231 write(Device, MaxOut, MinOut, true, Char) ->
232 put_char(Device, pibfi:wrap(Char, MinOut, MaxOut)).
233
234 put_char(Device, Char) when Char >= 0, Char < 256 ->
235 io:put_chars(Device, [Char]);
236 put_char(Device, Char) ->
237 CharString = "&#" ++ integer_to_list(Char) ++ ";",
238 io:put_chars(Device, CharString).
239
240 %% @spec config([option()], tape()) -> tape()
241 %% @doc Sets the various options of an I/O subsystem.
242
243 config(IO, []) ->
244 IO;
245 config(IO, [Head | Tail]) ->
246 config(config(IO, Head), Tail);
247
248 config(IO, {outfile, tty}) ->
249 IO#io{ device = standard_io };
250 config(IO, {outfile, OutFile}) ->
251 {ok, Device} = file:open(OutFile, [write, delayed_write]),
252 IO#io{ device = Device };
253 config(IO, {infile, InFile}) ->
254 IO;
255 config(IO, {device, Device})
256 when is_pid(Device); Device == standard_io ->
257 IO#io{ device = Device };
258 config(IO, {eof, EOF})
259 when is_integer(EOF); EOF == halt; EOF == nop; EOF == stop ->
260 IO#io{ eof = EOF };
261 config(IO, {maxout, MaxOut})
262 when is_integer(MaxOut); MaxOut == infinity ->
263 IO#io{ maxout = MaxOut };
264 config(IO, {minout, MinOut})
265 when is_integer(MinOut); MinOut == infinity ->
266 IO#io{ minout = MinOut };
267 config(IO, {wrapout, WrapOut})
268 when WrapOut == true; WrapOut == false ->
269 IO#io{ wrapout = WrapOut };
270 config(IO, {maxin, MaxIn})
271 when is_integer(MaxIn); MaxIn == infinity ->
272 IO#io{ maxin = MaxIn };
273 config(IO, {minin, MinIn})
274 when is_integer(MinIn); MinIn == infinity ->
275 IO#io{ minin = MinIn };
276 config(IO, {wrapin, WrapIn})
277 when WrapIn == true; WrapIn == false ->
278 IO#io{ wrapin = WrapIn };
279 config(IO, {xlatin, InXlat}) when is_list(InXlat) ->
280 IO#io{ inxlat = InXlat };
281 config(IO, {xlatout, OutXlat}) when is_list(OutXlat) ->
282 IO#io{ outxlat = OutXlat }.
283
284 %%% interface
285
286 %% @spec output(pid(), integer()) -> ok
287 %% @doc Sends the given character value to the output stream.
288
289 output(IoPid, Output) ->
290 % ce_log:write("~p", [Output]),
291 IoPid ! {self(), output, [Output]},
292 ok.
293
294 %% @spec input(pid()) -> integer() | nop
295 %% @doc Retrieves the next character value from the input stream.
296
297 input(IoPid) ->
298 % ce_log:write("input"),
299 IoPid ! {self(), input, []},
300 Result = receive
301 {IoPid, input, nop} ->
302 nop;
303 {IoPid, input, stop} ->
304 stop;
305 {IoPid, input, Input} when is_integer(Input) ->
306 Input
307 end,
308 % ce_log:write("input ~p", [Result]),
309 Result.
310
311 %% @spec flush(pid()) -> ok
312 %% @doc Flushes any pending output, even if it has not been translated yet.
313
314 flush(IoPid) ->
315 IoPid ! {self(), flush},
316 receive
317 {IoPid, flush, ok} ->
318 ok
319 end.
320
321 %% @spec stop(pid()) -> ok
322 %% @doc Tells the I/O server to stop.
323
324 stop(IoPid) ->
325 IoPid ! {self(), stop},
326 receive
327 {IoPid, stop, ok} ->
328 ok
329 end.
330
331 %%% END of pibfi_io.erl %%%
0 %%% BEGIN pibfi_optimizer.erl %%%
1 %%%
2 %%% pibfi - Platonic Ideal Brainf*ck Interpreter
3 %%% Copyright (c)2003 Cat's Eye Technologies. All rights reserved.
4 %%%
5 %%% Redistribution and use in source and binary forms, with or without
6 %%% modification, are permitted provided that the following conditions
7 %%% are met:
8 %%%
9 %%% Redistributions of source code must retain the above copyright
10 %%% notice, this list of conditions and the following disclaimer.
11 %%%
12 %%% Redistributions in binary form must reproduce the above copyright
13 %%% notice, this list of conditions and the following disclaimer in
14 %%% the documentation and/or other materials provided with the
15 %%% distribution.
16 %%%
17 %%% Neither the name of Cat's Eye Technologies nor the names of its
18 %%% contributors may be used to endorse or promote products derived
19 %%% from this software without specific prior written permission.
20 %%%
21 %%% THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
22 %%% CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
23 %%% INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
24 %%% MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
25 %%% DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE
26 %%% LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
27 %%% OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
28 %%% PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
29 %%% OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
30 %%% ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
31 %%% OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
32 %%% OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
33 %%% POSSIBILITY OF SUCH DAMAGE.
34
35 %% @doc Optimizer for <code>pibfi</code>.
36 %%
37 %% <p>Takes an internal format as generated by the parser and
38 %% returns a (hopefully) more efficient internal format.</p>
39 %%
40 %% @end
41
42 -module(pibfi_optimizer).
43 -vsn('2003.0425').
44 -copyright('Copyright (c)2003 Cat`s Eye Technologies. All rights reserved.').
45
46 -export([optimize/1]).
47
48 %% @spec optimize(program()) -> program()
49 %% @doc Optimizes a Brainf*ck program.
50
51 optimize(Program) ->
52 list_to_tuple(lists:reverse(optimize(Program, 1, undefined, 0, []))).
53
54 optimize(Program, Pos, Current, Count, Acc) when Pos > size(Program) ->
55 Acc;
56 optimize(Program, Pos, Current, Count, Acc) ->
57 Element = element(Pos, Program),
58 NewElement = case Element of
59 {instruction, R0, C0, Current} ->
60 Acc0 = [{instruction, R0, C0, {Current, Count + 1}} | tl(Acc)],
61 optimize(Program, Pos + 1, Current, Count + 1, Acc0);
62 {instruction, R0, C0, Instruction}=I
63 when Instruction == $<; Instruction == $>;
64 Instruction == $+; Instruction == $- ->
65 optimize(Program, Pos + 1, Instruction, 1, [I | Acc]);
66 {instruction, R0, C0, Other}=I ->
67 optimize(Program, Pos + 1, undefined, 1, [I | Acc]);
68 {while, R0, C0, Block} ->
69 optimize(Program, Pos + 1, undefined, 1,
70 [{while, R0, C0, optimize(Block)} | Acc])
71 end.
72
73 %%% END of pibfi_optimizer.erl %%%
0 %%% BEGIN pibfi_options.erl %%%
1 %%%
2 %%% pibfi - Platonic Ideal Brainf*ck Interpreter
3 %%% Copyright (c)2003 Cat's Eye Technologies. All rights reserved.
4 %%%
5 %%% Redistribution and use in source and binary forms, with or without
6 %%% modification, are permitted provided that the following conditions
7 %%% are met:
8 %%%
9 %%% Redistributions of source code must retain the above copyright
10 %%% notice, this list of conditions and the following disclaimer.
11 %%%
12 %%% Redistributions in binary form must reproduce the above copyright
13 %%% notice, this list of conditions and the following disclaimer in
14 %%% the documentation and/or other materials provided with the
15 %%% distribution.
16 %%%
17 %%% Neither the name of Cat's Eye Technologies nor the names of its
18 %%% contributors may be used to endorse or promote products derived
19 %%% from this software without specific prior written permission.
20 %%%
21 %%% THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
22 %%% CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
23 %%% INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
24 %%% MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
25 %%% DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE
26 %%% LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
27 %%% OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
28 %%% PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
29 %%% OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
30 %%% ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
31 %%% OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
32 %%% OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
33 %%% POSSIBILITY OF SUCH DAMAGE.
34
35 %% @doc Options parser for <code>pibfi</code>.
36 %%
37 %% <h3>Synopsis</h3>
38 %%
39 %% <p>This module implements collecting options
40 %% from the command line.</p>
41 %%
42 %% <p>When invoking <code>pibfi</code> from the command line, the
43 %% following syntax can be used:</p>
44 %%
45 %% <ul><code>erl -noshell <i>options</i> -run pibfi run <i>filename</i></code></ul>
46 %%
47 %% <p>The following options are recognized.</p>
48 %%
49 %% <ul>
50 %% <li>Options pertaining to the parser:
51 %%
52 %% <ul>
53 %% <li><code>-dontstrip <i>s</i></code>, where <i>s</i> is a string of
54 %% characters, default null (empty), specifies the set of characters
55 %% (beyond the 8 basic Brainf*ck instructions)
56 %% which
57 %% will not be stripped from the parsed source prior to optimization.
58 %% Note that if this option if given without an argument, it is assumed
59 %% to be the set of all applicable characters - in other words, nothing
60 %% at all will be stripped.</li>
61 %%
62 %% <li><code>-optimize <i>n</i></code>, where <i>n</i> is an integer,
63 %% default 1, sets the optimization level of the parser.
64 %% At optimization level 0, no optimization occurs.
65 %% At optimization level 1, run-length encoding is performed on the
66 %% instructions. Further optimization levels may be defined in the
67 %% future. Note that if this option if given without an argument,
68 %% it is assumed to be asking for the most thorough yet quickly
69 %% available optimization.</li>
70 %%
71 %% <li><code>-statuscmd <i>c</i></code>, where <i>c</i> may be
72 %% any single-character string of the term <code>undefined</code>,
73 %% default "#" (octalthorpe), specifies
74 %% which symbol, when encountered, is treated
75 %% as a debugging instruction which displays a status report.</li>
76 %%
77 %% <li><code>-heredoc <i>c</i></code>, where <i>c</i> may be
78 %% a single-character string or the term <code>undefined</code>,
79 %% default <code>undefined</code>, specifies which symbol when encountered,
80 %% is treated as the marker that signifies that input is embedded in
81 %% the program source code following it. This input will be stripped
82 %% from the source (even if it contains valid Brainf*ck instructions)
83 %% and will be made available to <code>-infile heredoc</code> (see
84 %% below.) Note that if this option is given with no argument,
85 %% "!" (exclamation point) is assumed.</li>
86 %%
87 %% </ul>
88 %% </li>
89 %% <li>Options pertaining to the Brainf*ck tape:
90 %%
91 %% <ul>
92 %% <li><code>-tapemodule <i>m</i></code>, where <i>n</i> is the name of
93 %% an Erlang module conforming to the <code>pibfi_tape</code> behaviour,
94 %% defaulting to whatever <code>pibfi</code> determines would be optimal
95 %% for the given sourcecode, (currently always <code>pibfi_tape_ets</code>),
96 %% names the module which implements the backing for the simulated tape.</li>
97 %%
98 %% <li><code>-maxcell <i>n</i></code>, where <i>n</i> is any integer or the
99 %% term <code>infinity</code>, default <code>infinity</code>, sets the
100 %% highest value that can be placed into a cell on the tape.</li>
101 %%
102 %% <li><code>-mincell <i>n</i></code>, where <i>n</i> is any integer or the
103 %% term <code>infinity</code>, default 0, sets the
104 %% lowest value that can be placed into a cell on the tape.
105 %% (Note that <code>infinity</code> actually represents negative infinity
106 %% here.)</li>
107 %%
108 %% <li><code>-wrapcell <i>b</i></code>, where <i>b</i> is a boolean
109 %% (<code>true</code> or <code>false</code>), default <code>false</code>,
110 %% determines what happens when either limit of any cell in the tape is
111 %% exceeded. When <code>-wrapcell</code> is <code>true</code>, the limits
112 %% will be taken as modulus boundaries, and the value will 'wrap around'
113 %% to the opposite limit. When <code>-wrapcell</code> is <code>false</code>,
114 %% an exception will be generated. Note that if <i>b</i> is omitted
115 %% after <code>-wrapcell</code>, <code>true</code> is assumed.
116 %% Also note that <code>-wrapcell true</code> is not compatible with
117 %% either <code>-maxcell infinity</code> or <code>-mincell infinity</code>
118 %% (for what should be obvious reasons.)</li>
119 %%
120 %% <li><code>-maxtape <i>n</i></code>, where <i>n</i> is any integer or the
121 %% term <code>infinity</code>, default <code>infinity</code>, sets the
122 %% rightmost position to which the tape head can move. Note that the initial
123 %% position of the tape head is considered position 0.</li>
124 %%
125 %% <li><code>-mintape <i>n</i></code>, where <i>n</i> is any integer or the
126 %% term <code>infinity</code>, default 0, sets the
127 %% leftmost position to which the tape head can move.
128 %% (Note that <code>infinity</code> actually represents negative infinity
129 %% here.)</li>
130 %%
131 %% <li><code>-wraptape <i>b</i></code>, where <i>b</i> is a boolean,
132 %% default <code>false</code>, determines what happens when either limit
133 %% of the tape head is exceeded. With <code>-wraptape true</code>,
134 %% the limits will be taken as modulus boundaries,
135 %% and the position of the tape head will 'wrap around' to the
136 %% opposite limit. With <code>-wraptape false</code>,
137 %% an exception will be generated when this happens.
138 %% Note that if <i>b</i> is omitted
139 %% after <code>-wraptape</code>, <code>true</code> is assumed. Also note
140 %% that <code>-wraptape true</code> is not compatible with either
141 %% <code>-maxtape infinity</code> or <code>-mintape infinity</code>.</li>
142 %% </ul>
143 %% </li>
144 %%
145 %% <li>Options pertaining to input and output:
146 %%
147 %% <ul>
148 %% <li><code>-infile <i>s</i></code>, where <i>s</i> is a filename or
149 %% one of the terms <code>tty</code> or <code>heredoc</code>,
150 %% default <code>tty</code>, sets the
151 %% source of the input to the Brainf*ck program.
152 %% <code>tty</code> indicates an interactive terminal session with
153 %% "standard input".
154 %% <code>heredoc</code> indicates input will come from the
155 %% "here-doc" portion of the program source code (note that the
156 %% <code>-heredoc</code> option must also be given to parse the
157 %% source code.)
158 %% Using this option is preferred
159 %% over redirecting standard I/O with the shell, as it is a hint to the
160 %% interpreter that the program is not being run interactively.</li>
161 %%
162 %% <li><code>-outfile <i>s</i></code>, where <i>s</i> is a filename or
163 %% the term <code>tty</code>, default <code>tty</code>, sets the
164 %% destination of the output of the Brainf*ck program. This is preferred
165 %% to redirecting standard I/O with the shell, as it is a hint to the
166 %% interpreter that the program is not being run interactively.</li>
167 %%
168 %% <li><code>-maxout <i>n</i></code>, where <i>n</i> is any integer or the
169 %% term <code>infinity</code>, default <code>infinity</code>, sets the
170 %% maximum character value which can be output.</li>
171 %%
172 %% <li><code>-minout <i>n</i></code>, where <i>n</i> is any integer or the
173 %% term <code>infinity</code>, default 0, sets the minimum character
174 %% value which can be output.
175 %% (Note that <code>infinity</code> actually represents negative infinity
176 %% here.)</li>
177 %%
178 %% <li><code>-wrapout <i>b</i></code>, where <i>b</i> is a boolean,
179 %% default <code>false</code>, determines what happens when either limit
180 %% of character output is exceeded. With <code>-wrapout true</code>,
181 %% the limits will be taken as modulus boundaries,
182 %% and the actual character output will be computed by 'wrapping around'
183 %% the rquested value to the opposite limit.
184 %% With <code>-wrapout false</code>,
185 %% an exception will be generated. Note that if <i>b</i> is omitted
186 %% after <code>-wrapout</code>, <code>true</code> is assumed. Also note
187 %% that <code>-wrapout true</code> is not compatible with either
188 %% <code>-maxout infinity</code> or <code>-minout infinity</code>.</li>
189 %%
190 %% <li><code>-maxin <i>n</i></code>, where <i>n</i> is any integer or the
191 %% term <code>infinity</code>, default <code>infinity</code>, sets the
192 %% maximum character value which can be input.</li>
193 %%
194 %% <li><code>-minin <i>n</i></code>, where <i>n</i> is any integer or the
195 %% term <code>infinity</code>, default 0, sets the minimum character
196 %% value which can be input.
197 %% (Note that <code>infinity</code> actually represents negative infinity
198 %% here.)</li>
199 %%
200 %% <li><code>-wrapin <i>b</i></code>, where <i>b</i> is a boolean,
201 %% default <code>false</code>, determines what happens when either limit
202 %% of character input is exceeded. With <code>-wrapin true</code>,
203 %% the limits will be taken as modulus boundaries,
204 %% and the actual character input will be computed by 'wrapping around'
205 %% the rquested value to the opposite limit.
206 %% With <code>-wrapin false</code>,
207 %% an exception will be generated. Note that if <i>b</i> is omitted
208 %% after <code>-wrapin</code>, <code>true</code> is assumed. Also note
209 %% that <code>-wrapin true</code> is not compatible with either
210 %% <code>-maxin infinity</code> or <code>-minin infinity</code>.</li>
211 %%
212 %% <li><code>-xlatout <i>s</i></code>, where <i>s</i> is string
213 %% in the form given below,
214 %% default value <tt>#10=#nl</tt>, specifies a mapping between
215 %% characters the Brainf*ck program sees itself as sending to output,
216 %% and the characters that the operating system actually receives.
217 %% The syntax for the mapping specification is described by this mini-grammar:
218 %% <ul><li>
219 %% <tt><i>string</i> "=" <i>string</i> ["," <i>string</i> "=" <i>string</i> ]</tt>
220 %% </li></ul>
221 %% Control and other characters can be embedded in this string by
222 %% giving their ASCII values in decimal preceded by a <tt>#</tt>
223 %% symbol. A single <tt>#</tt> symbol can be represented by the
224 %% sequence <tt>#35</tt>. A single <tt>=</tt> symbol can be
225 %% represented by the sequence <tt>#61</tt>.
226 %% A single <tt>,</tt> symbol can be
227 %% represented by the sequence <tt>#44</tt>.
228 %% The current operating system newline
229 %% sequence can be represented by <tt>#nl</tt>.
230 %% Note that whitespace is not allowed in this grammar,
231 %% and must be represented by <tt>#32</tt>, etc.
232 %% Note that if the <code>-xlatout</code> option is present
233 %% with no argument, this means that there should be <i>no</i> translation
234 %% mapping between Brainf*ck output and operating system output.</li>
235 %%
236 %% <li><code>-xlatin <i>s</i></code>, where <i>s</i> is a string
237 %% in the form given above,
238 %% default value <tt>#nl=#10</tt>, specifies a complementary mapping between
239 %% characters on the operating system's input and
240 %% the Brainf*ck program's input.
241 %% Note that if the <code>-xlatin</code> option is present
242 %% with no argument, this means that there should be no translation
243 %% mapping of input.</li>
244 %%
245 %% <li><code>-eof <i>i</i></code>, where <i>i</i> is any integer
246 %% or one of the terms <code>halt</code>, <code>stop</code>,
247 %% or <code>nop</code>, default 0,
248 %% determines the single ASCII character that will be given repeatedly to
249 %% the Brainf*ck program during execution of the <code>,</code> instruction
250 %% at and after the end of input is encountered.
251 %% If <code>halt</code> is given for <code>eof</code>, the Brainf*ck
252 %% program will be halted with an error
253 %% if it attempts to read past the end of user input.
254 %% If <code>stop</code> is given for <code>eof</code>, the Brainf*ck
255 %% program will be terminated normally if it attempts to read past
256 %% the end of user input.
257 %% If <code>nop</code> is given for <code>eof</code>, the Brainf*ck
258 %% program will act as if nothing at all happened if it attempts
259 %% to read past the end of user input (the tape will not be altered in
260 %% any way.)</li>
261 %% </ul>
262 %% </li>
263 %%
264 %% <li>Debugging and other options:</li>
265 %% <ul>
266 %% <li><code>-quiet</code>, if given, suppresses all startup
267 %% output generated by the interpreter. It does not suppress
268 %% status reports.</li>
269 %% <li><code>-autopsy</code>, if given, causes the interpreter to
270 %% issue a status report after the program terminates normally.</li>
271 %% <li><code>-statusevery <i>n</i></code>, where <i>n</i> is an
272 %% integer specifying a duration or the term <code>undefined</code>,
273 %% default <code>undefined</code>, tells <code>pibfi</code>
274 %% to generate periodic status reports at the given interval,
275 %% if it is not <code>undefined</code>. If the duration is given
276 %% as a plain integer, units of milliseconds are assumed. The
277 %% duration may also be given as an integer followed immediately
278 %% by <code>s</code>, <code>m</code>, or <code>h</code>, in which
279 %% case the units of measurement will be taken to be seconds,
280 %% minutes, or hours, respectively.</li>
281 %% </ul>
282 %% </ul>
283 %%
284 %% @end
285
286 -module(pibfi_options).
287 -vsn('2003.0505').
288 -copyright('Copyright (c)2003 Cat`s Eye Technologies. All rights reserved.').
289
290 -export([get_flag/1, get_opts/1]).
291 -export([get_option/3]).
292
293 %% @spec get_flag(Switch::atom()) -> true | false
294 %% @doc Gets a switch from the command line.
295
296 get_flag(Option) ->
297 case init:get_argument(Option) of
298 {ok, [X]} ->
299 true;
300 error ->
301 false
302 end.
303
304 %% @spec get_opts([atom()]) -> [{atom(), term()}]
305 %% @doc Gets a set of options from the command line.
306
307 get_opts(Options) ->
308 lists:foldl(fun(Option, Acc) when is_atom(Option) ->
309 case init:get_argument(Option) of
310 error ->
311 Acc;
312 {ok, [[]]} ->
313 [{Option, missing(Option)} | Acc];
314 {ok, [[Arg | _] | _]} ->
315 [{Option, convert(Option, Arg)} | Acc]
316 end;
317 ({Option, Default}, Acc) ->
318 case init:get_argument(Option) of
319 error ->
320 [{Option, Default} | Acc];
321 {ok, [[]]} ->
322 [{Option, missing(Option)} | Acc];
323 {ok, [[Arg | _] | _]} ->
324 [{Option, convert(Option, Arg)} | Acc]
325 end
326 end, [], Options).
327
328 %% @spec missing(atom()) -> term()
329 %% @doc Gets the default value for an option specified with no value
330 %% on the command line.
331
332 missing(wrapcell) -> true;
333 missing(wraptape) -> true;
334 missing(wrapout) -> true;
335 missing(wrapin) -> true;
336 missing(xlatin) -> [];
337 missing(xlatout) -> [];
338 missing(dontstrip) -> lists:seq(0, 255);
339 missing(optimize) -> 1;
340 missing(statuscmd) -> "#";
341 missing(heredoc) -> "!";
342 missing(Else) -> exit({missing_parameter_for, Else}).
343
344 %% @spec convert(atom(), string()) -> term()
345 %% @doc Converts an option value specified on the command line to a
346 %% term that <code>pibfi</code> can work with internally.
347
348 convert(dontstrip, String) -> unescape(String);
349 convert(optimize, Integer) -> list_to_integer(Integer);
350 convert(statuscmd, "undefined") -> undefined;
351 convert(statuscmd, String) -> unescape(String);
352 convert(heredoc, "undefined") -> undefined;
353 convert(heredoc, String) -> unescape(String);
354
355 convert(tapemodule, String) -> list_to_atom(String);
356 convert(maxcell, "infinity") -> infinity;
357 convert(maxcell, Else) -> list_to_integer(Else);
358 convert(mincell, "infinity") -> infinity;
359 convert(mincell, Else) -> list_to_integer(Else);
360 convert(wrapcell, "true") -> true;
361 convert(wrapcell, "false") -> false;
362 convert(maxtape, "infinity") -> infinity;
363 convert(maxtape, Else) -> list_to_integer(Else);
364 convert(mintape, "infinity") -> infinity;
365 convert(mintape, Else) -> list_to_integer(Else);
366 convert(wraptape, "true") -> true;
367 convert(wraptape, "false") -> false;
368
369 convert(infile, "tty") -> tty;
370 convert(infile, "heredoc") -> heredoc;
371 convert(infile, Else) -> Else;
372 convert(outfile, "tty") -> tty;
373 convert(outfile, Else) -> Else;
374 convert(maxout, "infinity") -> infinity;
375 convert(maxout, Else) -> list_to_integer(Else);
376 convert(minout, "infinity") -> infinity;
377 convert(minout, Else) -> list_to_integer(Else);
378 convert(wrapout, "true") -> true;
379 convert(wrapout, "false") -> false;
380 convert(maxin, "infinity") -> infinity;
381 convert(maxin, Else) -> list_to_integer(Else);
382 convert(minin, "infinity") -> infinity;
383 convert(minin, Else) -> list_to_integer(Else);
384 convert(wrapin, "true") -> true;
385 convert(wrapin, "false") -> false;
386 convert(xlatin, String) -> parse_xlat(String, []);
387 convert(xlatout, String) -> parse_xlat(String, []);
388 convert(eof, "halt") -> halt;
389 convert(eof, "nop") -> nop;
390 convert(eof, "stop") -> stop;
391 convert(eof, Else) -> list_to_integer(Else);
392
393 convert(statusevery, "undefined") -> undefined;
394 convert(statusevery, Else) ->
395 Factor = case lists:last(Else) of
396 $s -> 1000;
397 $m -> 60*1000;
398 $h -> 60*60*1000;
399 _ -> 1
400 end,
401 Root = case Factor of
402 1 -> Else;
403 _ -> lists:reverse(tl(lists:reverse(Else)))
404 end,
405 % ce_log:write("~p ~p", [Root, Factor]),
406 list_to_integer(Root) * Factor.
407
408 parse_xlat(String, Acc) ->
409 {First, String0} = parse_lstring(String, ""),
410 {Second, String1} = parse_rstring(String0, ""),
411 pibfi:assert(First =/= "", {lefthand_string_in_xlat_may_not_be_null, String}),
412 Acc0 = [{unescape(First), unescape(Second)} | Acc],
413 case String1 of
414 "," ++ String2 ->
415 parse_xlat(String2, Acc0);
416 _ ->
417 Acc0
418 end.
419
420 parse_lstring("=" ++ Tail, Acc) ->
421 {lists:reverse(Acc), Tail};
422 parse_lstring([Head | Tail], Acc) ->
423 parse_lstring(Tail, [Head | Acc]).
424
425 parse_rstring("", Acc) ->
426 {lists:reverse(Acc), ""};
427 parse_rstring("," ++ Tail, Acc) ->
428 {lists:reverse(Acc), "," ++ Tail};
429 parse_rstring([Head | Tail], Acc) ->
430 parse_rstring(Tail, [Head | Acc]).
431
432 %% @spec unescape(string()) -> string()
433 %% @doc Transforms escape codes in a string into embedded characters.
434 %% The escape code <tt>#<i>i</i></tt> where <tt><i>i</i></tt> is a
435 %% decimal integer of from one to three digits is converted into an
436 %% ASCII character of that value.
437
438 unescape(String) ->
439 unescape(String, []).
440 unescape([], Acc) ->
441 lists:reverse(Acc);
442 unescape([$#, $n, $l | Tail], Acc) ->
443 unescape(Tail, lists:reverse(pibfi:os_eol()) ++ Acc);
444 unescape([$#, D1, D2, D3 | Tail], Acc)
445 when D1 >= $0, D1 =< $9, D2 >= $0, D2 =< $9, D3 >= $0, D3 =< $9 ->
446 unescape(Tail, [(D1 - $0) * 100 + (D2 - $0) * 10 + (D3 - $0) | Acc]);
447 unescape([$#, D1, D2 | Tail], Acc)
448 when D1 >= $0, D1 =< $9, D2 >= $0, D2 =< $9 ->
449 unescape(Tail, [(D1 - $0) * 10 + (D2 - $0) | Acc]);
450 unescape([$#, D | Tail], Acc)
451 when D >= $0, D =< $9 ->
452 unescape(Tail, [(D - $0) | Acc]);
453 unescape([Head | Tail], Acc) ->
454 unescape(Tail, [Head | Acc]).
455
456 %% @spec get_option(Options::[{atom(), term()}], Option::atom(), Default::term()) -> term()
457 %% @doc Gets an option from a list of (already parsed) option tuples.
458
459 get_option(TupleList, Option, Default) ->
460 case lists:keysearch(Option, 1, TupleList) of
461 {value, {Option, Value}} ->
462 Value;
463 _ ->
464 Default
465 end.
466
467 %%% END of pibfi_options.erl %%%
0 %%% BEGIN pibfi_parser.erl %%%
1 %%%
2 %%% pibfi - Platonic Ideal Brainf*ck Interpreter
3 %%% Copyright (c)2003 Cat's Eye Technologies. All rights reserved.
4 %%%
5 %%% Redistribution and use in source and binary forms, with or without
6 %%% modification, are permitted provided that the following conditions
7 %%% are met:
8 %%%
9 %%% Redistributions of source code must retain the above copyright
10 %%% notice, this list of conditions and the following disclaimer.
11 %%%
12 %%% Redistributions in binary form must reproduce the above copyright
13 %%% notice, this list of conditions and the following disclaimer in
14 %%% the documentation and/or other materials provided with the
15 %%% distribution.
16 %%%
17 %%% Neither the name of Cat's Eye Technologies nor the names of its
18 %%% contributors may be used to endorse or promote products derived
19 %%% from this software without specific prior written permission.
20 %%%
21 %%% THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
22 %%% CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
23 %%% INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
24 %%% MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
25 %%% DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE
26 %%% LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
27 %%% OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
28 %%% PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
29 %%% OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
30 %%% ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
31 %%% OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
32 %%% OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
33 %%% POSSIBILITY OF SUCH DAMAGE.
34
35 %% @doc Brainf*ck parser for <code>pibfi</code>.
36 %%
37 %% @end
38
39 -module(pibfi_parser).
40 -vsn('2003.0426').
41 -copyright('Copyright (c)2003 Cat`s Eye Technologies. All rights reserved.').
42
43 -export([parse/2]).
44
45 %% @spec parse(string() | binary(), Options) -> {tuple(), string()}
46 %% @doc Transforms a string into a nested tuple data structure
47 %% suitable for interpretation.
48
49 parse(Binary, Options) when is_binary(Binary) ->
50 parse(binary_to_list(Binary), Options);
51 parse(Source, Options) ->
52 {DocBody, Source0} =
53 case pibfi_options:get_option(Options, heredoc, undefined) of
54 undefined ->
55 {"", Source};
56 [Marker] ->
57 extract_heredoc(Source, Marker, false, [], [])
58 end,
59 Program = parse0(Source0),
60 Exclude = pibfi_options:get_option(Options, dontstrip, ""),
61 Program0 = pibfi_stripper:strip(Program, Exclude),
62 Program1 = case pibfi_options:get_option(Options, optimize, 1) of
63 0 ->
64 Program0;
65 1 ->
66 pibfi_optimizer:optimize(Program0)
67 end,
68 % ce_log:write("~p", [Program1]),
69 {Program1, DocBody}.
70
71 parse0(String) ->
72 TupleList = annotate(String),
73 parse0({}, TupleList).
74
75 parse0(Tuple, []) -> Tuple;
76 parse0(Tuple, [{$], R, C} | Tail]) -> {Tuple, Tail};
77 parse0(Tuple, [{$[, R, C} | Tail]) ->
78 {NewTuple, NewTail} = parse0({}, Tail),
79 parse0(erlang:append_element(Tuple, {while, R, C, NewTuple}), NewTail);
80 parse0(Tuple, [{Head, R, C} | Tail]) ->
81 parse0(erlang:append_element(Tuple, {instruction, R, C, Head}), Tail).
82
83 annotate(String) ->
84 annotate(String, 1, 1, []).
85
86 annotate("", R, C, Acc) ->
87 lists:reverse(Acc);
88 annotate("\n" ++ Tail, R, C, Acc) ->
89 annotate(Tail, R+1, 1, Acc);
90 annotate([Head | Tail], R, C, Acc) ->
91 annotate(Tail, R, C+1, [{Head, R, C} | Acc]).
92
93 extract_heredoc("", Marker, Found, AccD, AccS) ->
94 {lists:reverse(AccD), lists:reverse(AccS)};
95 extract_heredoc([Marker | Tail], Marker, Found, AccD, AccS) ->
96 extract_heredoc(Tail, Marker, true, AccD, AccS);
97 extract_heredoc([Head | Tail], Marker, true, AccD, AccS) ->
98 extract_heredoc(Tail, Marker, true, [Head | AccD], AccS);
99 extract_heredoc([Head | Tail], Marker, false, AccD, AccS) ->
100 extract_heredoc(Tail, Marker, false, AccD, [Head | AccS]).
101
102 %%% END of pibfi_parser.erl %%%
0 %%% BEGIN pibfi_statistics.erl %%%
1 %%%
2 %%% pibfi - Platonic Ideal Brainf*ck Interpreter
3 %%% Copyright (c)2003 Cat's Eye Technologies. All rights reserved.
4 %%%
5 %%% Redistribution and use in source and binary forms, with or without
6 %%% modification, are permitted provided that the following conditions
7 %%% are met:
8 %%%
9 %%% Redistributions of source code must retain the above copyright
10 %%% notice, this list of conditions and the following disclaimer.
11 %%%
12 %%% Redistributions in binary form must reproduce the above copyright
13 %%% notice, this list of conditions and the following disclaimer in
14 %%% the documentation and/or other materials provided with the
15 %%% distribution.
16 %%%
17 %%% Neither the name of Cat's Eye Technologies nor the names of its
18 %%% contributors may be used to endorse or promote products derived
19 %%% from this software without specific prior written permission.
20 %%%
21 %%% THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
22 %%% CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
23 %%% INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
24 %%% MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
25 %%% DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE
26 %%% LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
27 %%% OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
28 %%% PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
29 %%% OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
30 %%% ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
31 %%% OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
32 %%% OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
33 %%% POSSIBILITY OF SUCH DAMAGE.
34
35 %% @doc Statistics collector for <code>pibfi</code>.
36 %%
37 %% @end
38
39 -module(pibfi_statistics).
40 -vsn('2003.0505').
41 -copyright('Copyright (c)2003 Cat`s Eye Technologies. All rights reserved.').
42
43 -export([start/3, server/2, dump/0, dump/1]).
44 -export([update_program/3]).
45
46 start(Supervisor, TapePid, Options) ->
47 pibfi_supervisor:spawn_link(Supervisor, "statistics collector",
48 noncritical, ?MODULE, server, [TapePid, Options]).
49
50 server(TapePid, Options) ->
51 register(?MODULE, self()),
52 case pibfi_options:get_option(Options, statusevery, undefined) of
53 I when is_integer(I) ->
54 timer:apply_interval(I, ?MODULE, dump, []);
55 _ ->
56 ok
57 end,
58 Start = calendar:local_time(),
59 loop({TapePid, 1, 1, $?, Start, {0,0,0,0,0,0,0,0,0}}).
60
61 loop({TapePid, ProgramRow, ProgramColumn, Instruction, Start,
62 {PlusT, MinusT, LeftT, RightT,
63 InT, OutT, WhileT, WendT, WhileLevel}}) ->
64 receive
65 {program, Row, Col, {Ins, N}} ->
66 PlusT1 = case Ins of $+ -> PlusT + N; _ -> PlusT end,
67 MinusT1 = case Ins of $- -> MinusT + N; _ -> MinusT end,
68 LeftT1 = case Ins of $< -> LeftT + N; _ -> LeftT end,
69 RightT1 = case Ins of $> -> RightT + N; _ -> RightT end,
70 InT1 = case Ins of $, -> InT + N; _ -> InT end,
71 OutT1 = case Ins of $. -> OutT + N; _ -> OutT end,
72 WhileT1 = case Ins of $[ -> WhileT + N; _ -> WhileT end,
73 WendT1 = case Ins of $] -> WendT + N; _ -> WendT end,
74 WhileLevel1 = case Ins of
75 $[ ->
76 WhileLevel + 1;
77 $] ->
78 WhileLevel - 1;
79 _ ->
80 WhileLevel
81 end,
82 % ce_log:write("~c -> ~c ~p", [Instruction, Ins, N]),
83 loop({TapePid, Row, Col, Ins, Start,
84 {PlusT1, MinusT1, LeftT1, RightT1,
85 InT1, OutT1, WhileT1, WendT1, WhileLevel1}});
86 {program, Row, Col, Ins} ->
87 PlusT1 = case Ins of $+ -> PlusT + 1; _ -> PlusT end,
88 MinusT1 = case Ins of $- -> MinusT + 1; _ -> MinusT end,
89 LeftT1 = case Ins of $< -> LeftT + 1; _ -> LeftT end,
90 RightT1 = case Ins of $> -> RightT + 1; _ -> RightT end,
91 InT1 = case Ins of $, -> InT + 1; _ -> InT end,
92 OutT1 = case Ins of $. -> OutT + 1; _ -> OutT end,
93 WhileT1 = case Ins of $[ -> WhileT + 1; _ -> WhileT end,
94 WendT1 = case Ins of $] -> WendT + 1; _ -> WendT end,
95 WhileLevel1 = case Ins of
96 $[ ->
97 WhileLevel + 1;
98 $] ->
99 WhileLevel - 1;
100 _ ->
101 WhileLevel
102 end,
103 % ce_log:write("~c -> ~c", [Instruction, Ins]),
104 loop({TapePid, Row, Col, Ins, Start,
105 {PlusT1, MinusT1, LeftT1, RightT1,
106 InT1, OutT1, WhileT1, WendT1, WhileLevel1}});
107 {Pid, dump, Type} ->
108 % flush mailbox here (?)
109 Stop = calendar:local_time(),
110 StartGD = calendar:datetime_to_gregorian_seconds(Start),
111 StopGD = calendar:datetime_to_gregorian_seconds(Stop),
112 Dur = StopGD - StartGD,
113 DurString = case Dur of
114 D when D < 60 ->
115 io_lib:format("~p sec", [D]);
116 D when D < 3600 ->
117 io_lib:format("~p min ~p sec", [D div 60, D rem 60]);
118 D ->
119 M = D rem 3600,
120 io_lib:format("~p hr ~p min ~p sec",
121 [D div 3600, M div 60, M rem 60])
122 end,
123 TotalT = PlusT + MinusT + LeftT + RightT + InT + OutT + WhileT + WendT,
124 KIPS = round((TotalT / Dur) / 1000),
125 io:fwrite("===== STATUS REPORT ===== ~s =====~n", [format_datetime(Stop)]),
126 io:fwrite("= Run began ~s duration ~s at mean kips ~p~n",
127 [format_datetime(Start), DurString, KIPS]),
128 State = case Type of
129 autopsy -> "Stopped";
130 normal -> "Currently"
131 end,
132 io:fwrite("= ~s at line ~p, col ~p, instruction '~c', whilelevel ~p~n",
133 [State, ProgramRow, ProgramColumn, Instruction, WhileLevel]),
134 io:fwrite("= Exec tally:~12wx(+)~12wx(-)~12wx(<)~12wx(>)~n",
135 [PlusT, MinusT, LeftT, RightT]),
136 io:fwrite("= Exec tally:~12wx(,)~12wx(.)~12wx([)~12wx(])~n",
137 [InT, OutT, WhileT, WendT]),
138 pibfi_tape:examine(TapePid),
139 Pid ! {?MODULE, dump, ok},
140 loop({TapePid, ProgramRow, ProgramColumn, Instruction, Start,
141 {PlusT, MinusT, LeftT, RightT,
142 InT, OutT, WhileT, WendT,
143 WhileLevel}})
144 end.
145
146 format_datetime({{Y, M, D}, {H, I, S}}) ->
147 DoW = element(calendar:day_of_the_week({Y,M,D}),
148 {"Mon","Tue","Wed","Thu","Fri","Sat","Sun"}),
149 MoY = element(M,
150 {"Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec"}),
151 T = io_lib:format("~s ~s ~w ~w, ~2.2.0w:~2.2.0w:~2.2.0w",
152 [DoW, MoY, D, Y, H, I, S]),
153 lists:flatten(T).
154
155 dump() ->
156 dump(normal).
157
158 dump(Type) ->
159 case catch ?MODULE ! {self(), dump, Type} of
160 {'EXIT', Reason} ->
161 {error, Reason};
162 _ ->
163 receive
164 {?MODULE, dump, ok} ->
165 ok
166 after 1000 ->
167 {error, timeout}
168 end
169 end.
170
171 update_program(Row, Col, Ins) ->
172 catch ?MODULE ! {program, Row, Col, Ins}.
173
174 %%% END of pibfi_statistics.erl %%%
0 %%% BEGIN pibfi_stripper.erl %%%
1 %%%
2 %%% pibfi - Platonic Ideal Brainf*ck Interpreter
3 %%% Copyright (c)2003 Cat's Eye Technologies. All rights reserved.
4 %%%
5 %%% Redistribution and use in source and binary forms, with or without
6 %%% modification, are permitted provided that the following conditions
7 %%% are met:
8 %%%
9 %%% Redistributions of source code must retain the above copyright
10 %%% notice, this list of conditions and the following disclaimer.
11 %%%
12 %%% Redistributions in binary form must reproduce the above copyright
13 %%% notice, this list of conditions and the following disclaimer in
14 %%% the documentation and/or other materials provided with the
15 %%% distribution.
16 %%%
17 %%% Neither the name of Cat's Eye Technologies nor the names of its
18 %%% contributors may be used to endorse or promote products derived
19 %%% from this software without specific prior written permission.
20 %%%
21 %%% THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
22 %%% CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
23 %%% INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
24 %%% MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
25 %%% DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE
26 %%% LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
27 %%% OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
28 %%% PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
29 %%% OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
30 %%% ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
31 %%% OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
32 %%% OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
33 %%% POSSIBILITY OF SUCH DAMAGE.
34
35 %% @doc Stripper for <code>pibfi</code>.
36 %%
37 %% <p>Takes the internal format as generated by the parser and
38 %% takes out everything non-essential.</p>
39 %%
40 %% @end
41
42 -module(pibfi_stripper).
43 -vsn('2003.0425').
44 -copyright('Copyright (c)2003 Cat`s Eye Technologies. All rights reserved.').
45
46 -export([strip/2]).
47
48 %% @spec strip(program(), Exclude::string()) -> program()
49 %% @doc Strips a Brainf*ck program.
50
51 strip(Program, Exclude) ->
52 list_to_tuple(lists:reverse(strip(Program, Exclude, 1, []))).
53
54 strip(Program, Exclude, Pos, Acc) when Pos > size(Program) ->
55 Acc;
56 strip(Program, Exclude, Pos, Acc) ->
57 Element = element(Pos, Program),
58 NewElement = case Element of
59 {instruction, R0, C0, Core}=I
60 when Core == $<; Core == $>; Core == $+; Core == $-;
61 Core == $[; Core == $]; Core == $.; Core == $, ->
62 strip(Program, Exclude, Pos + 1, [I | Acc]);
63 {instruction, R0, C0, Other}=I ->
64 case lists:member(Other, Exclude) of
65 true ->
66 strip(Program, Exclude, Pos + 1, [I | Acc]);
67 false ->
68 strip(Program, Exclude, Pos + 1, Acc)
69 end;
70 {while, R0, C0, Block} ->
71 strip(Program, Exclude, Pos + 1,
72 [{while, R0, C0, strip(Block, Exclude)} | Acc])
73 end.
74
75 %%% END of pibfi_stripper.erl %%%
0 %%% BEGIN pibfi_supervisor.erl %%%
1 %%%
2 %%% pibfi - Platonic Ideal Brainf*ck Interpreter
3 %%% Copyright (c)2003 Cat's Eye Technologies. All rights reserved.
4 %%%
5 %%% Redistribution and use in source and binary forms, with or without
6 %%% modification, are permitted provided that the following conditions
7 %%% are met:
8 %%%
9 %%% Redistributions of source code must retain the above copyright
10 %%% notice, this list of conditions and the following disclaimer.
11 %%%
12 %%% Redistributions in binary form must reproduce the above copyright
13 %%% notice, this list of conditions and the following disclaimer in
14 %%% the documentation and/or other materials provided with the
15 %%% distribution.
16 %%%
17 %%% Neither the name of Cat's Eye Technologies nor the names of its
18 %%% contributors may be used to endorse or promote products derived
19 %%% from this software without specific prior written permission.
20 %%%
21 %%% THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
22 %%% CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
23 %%% INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
24 %%% MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
25 %%% DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE
26 %%% LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
27 %%% OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
28 %%% PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
29 %%% OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
30 %%% ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
31 %%% OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
32 %%% OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
33 %%% POSSIBILITY OF SUCH DAMAGE.
34
35 %% @doc Supervisor process for <code>pibfi</code>.
36 %%
37 %% <p>All error handling is done here. This allows the other processes
38 %% to be coded in a more direct, laissez-crash style. The centralization
39 %% of error-handling code in this process allows for minimal
40 %% error-handling code in the other processes, which makes their code
41 %% clearer and easier to follow.</p>
42 %%
43 %% @end
44
45 -module(pibfi_supervisor).
46 -vsn('2003.0505').
47 -copyright('Copyright (c)2003 Cat`s Eye Technologies. All rights reserved.').
48
49 -export([start/0, server/0, spawn_link/6, link/3]).
50
51 start() ->
52 spawn(?MODULE, server, []).
53
54 server() ->
55 process_flag(trap_exit, true),
56 loop(dict:new(), dict:new(), 0).
57
58 loop(CriticalPids, NonCriticalPids, Count) ->
59 receive
60 {Pid, spawn, Name, critical, Module, Function, Args} ->
61 NewPid = spawn_link(Module, Function, Args),
62 CriticalPids0 = dict:store(NewPid, Name, CriticalPids),
63 whisper("~p->~p critical ~s started ~p", [Count, Count + 1, Name, NewPid]),
64 Pid ! {self(), spawned, Module, Function, Args, NewPid},
65 loop(CriticalPids0, NonCriticalPids, Count + 1);
66 {Pid, spawn, Name, noncritical, Module, Function, Args} ->
67 NewPid = spawn_link(Module, Function, Args),
68 NonCriticalPids0 = dict:store(NewPid, Name, NonCriticalPids),
69 whisper("~p->~p noncritical ~s started ~p", [Count, Count + 1, Name, NewPid]),
70 Pid ! {self(), spawned, Module, Function, Args, NewPid},
71 loop(CriticalPids, NonCriticalPids0, Count + 1);
72 {Pid, link, Name, LPid} ->
73 link(LPid),
74 NonCriticalPids0 = dict:store(LPid, Name, NonCriticalPids),
75 whisper("~p->~p noncritical ~s linked to ~p", [Count, Count + 1, Name, LPid]),
76 Pid ! {self(), linked, LPid},
77 loop(CriticalPids, NonCriticalPids0, Count + 1);
78 {'EXIT', From, OK} when OK == normal; OK == shutdown; OK == terminated ->
79 case dict:find(From, CriticalPids) of
80 {ok, Name} ->
81 whisper("~p->~p critical ~s exited normally", [Count, Count - 1, Name]),
82 CriticalPids0 = dict:erase(From, CriticalPids),
83 case dict:to_list(CriticalPids0) of
84 [] ->
85 whisper("all critical processes exited normally, exiting", []),
86 pibfi:whisper("---------------END PROGRAM OUTPUT---------------"),
87 case pibfi_options:get_flag(autopsy) of
88 true ->
89 pibfi_statistics:dump(autopsy);
90 false ->
91 ok
92 end,
93 exeunt(NonCriticalPids),
94 erlang:halt();
95 _ ->
96 loop(CriticalPids0, NonCriticalPids, Count - 1)
97 end;
98 _ ->
99 case dict:find(From, NonCriticalPids) of
100 {ok, Name} ->
101 whisper("~p->~p noncritical ~s exited normally",
102 [Count, Count - 1, Name]),
103 NonCriticalPids0 = dict:erase(From, NonCriticalPids),
104 loop(CriticalPids, NonCriticalPids0, Count - 1);
105 error ->
106 whisper("??? unknown pid ~p quitting", [From]),
107 loop(CriticalPids, NonCriticalPids, Count)
108 end
109 end;
110 {'EXIT', From, Reason} ->
111 Name = case dict:find(From, CriticalPids) of
112 {ok, N} ->
113 N;
114 _ ->
115 case dict:find(From, NonCriticalPids) of
116 {ok, N} ->
117 N;
118 _ ->
119 "unknown"
120 end
121 end,
122 pibfi:whisper("---------------END PROGRAM OUTPUT---------------"),
123 io:fwrite("~n***** HALTED~nAn error occurred in the ~s process:~n~p~n",
124 [Name, Reason]),
125 pibfi_statistics:dump(),
126 exeunt(CriticalPids),
127 exeunt(NonCriticalPids),
128 erlang:halt(1)
129 end.
130
131 exeunt(Dict) ->
132 exeunt0(dict:to_list(Dict)).
133
134 exeunt0(List) when is_list(List) ->
135 lists:foreach(fun({P,N}) ->
136 whisper("shutting down ~s ~p", [N, P]),
137 exit(P, shutdown)
138 end, List).
139
140 whisper(FmtString, Args) ->
141 case pibfi_options:get_flag(bearflowers) of
142 true ->
143 io:fwrite(">>> " ++ FmtString ++ "~n", Args);
144 false ->
145 ok
146 end.
147
148 %%% interface
149
150 spawn_link(Supervisor, Name, Class, Module, Function, Args) ->
151 Supervisor ! {self(), spawn, Name, Class, Module, Function, Args},
152 receive
153 {Supervisor, spawned, Module, Function, Args, Pid} ->
154 Pid
155 end.
156
157 link(Supervisor, Name, Pid) ->
158 Supervisor ! {self(), link, Name, Pid},
159 receive
160 {Supervisor, linked, Pid} ->
161 Pid
162 end.
163
164 %%% END of pibfi_supervisor.erl %%%
0 %%% BEGIN pibfi_tape.erl %%%
1 %%%
2 %%% pibfi - Platonic Ideal Brainf*ck Interpreter
3 %%% Copyright (c)2003 Cat's Eye Technologies. All rights reserved.
4 %%%
5 %%% Redistribution and use in source and binary forms, with or without
6 %%% modification, are permitted provided that the following conditions
7 %%% are met:
8 %%%
9 %%% Redistributions of source code must retain the above copyright
10 %%% notice, this list of conditions and the following disclaimer.
11 %%%
12 %%% Redistributions in binary form must reproduce the above copyright
13 %%% notice, this list of conditions and the following disclaimer in
14 %%% the documentation and/or other materials provided with the
15 %%% distribution.
16 %%%
17 %%% Neither the name of Cat's Eye Technologies nor the names of its
18 %%% contributors may be used to endorse or promote products derived
19 %%% from this software without specific prior written permission.
20 %%%
21 %%% THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
22 %%% CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
23 %%% INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
24 %%% MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
25 %%% DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE
26 %%% LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
27 %%% OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
28 %%% PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
29 %%% OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
30 %%% ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
31 %%% OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
32 %%% OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
33 %%% POSSIBILITY OF SUCH DAMAGE.
34
35 %% @doc Tape ADT for the Platonic Ideal Brainf*ck Interpreter.
36 %%
37 %% <p>Now a behaviour.</p>
38 %%
39 %% @end
40
41 -module(pibfi_tape).
42 -vsn('2003.0505').
43 -copyright('Copyright (c)2003 Cat`s Eye Technologies. All rights reserved.').
44
45 -export([behaviour_info/1]).
46 -export([start/3, server/2]).
47 -export([left/1, right/1, increment/1, decrement/1]).
48 -export([left/2, right/2, increment/2, decrement/2]).
49 -export([read/1, write/2]).
50 -export([examine/1]).
51
52 behaviour_info(callbacks) ->
53 [
54 {new, 1},
55 % Brainf*ck semantics
56 {left, 2}, % (tape(), delta()) -> {tape(), cell()}
57 {right, 2}, % (tape(), delta()) -> {tape(), cell()}
58 % Efficiency extensions
59 {read, 1}, % (tape()) -> cell()
60 {write, 2}, % (tape(), cell()) -> {tape(), cell()}
61 {peek, 2}, % (tape(), position()) -> cell()
62 {poke, 3}, % (tape(), position, cell()) -> tape()
63 {head, 1} % (tape()) -> position()
64 ].
65
66 %% @spec start(module(), Supervisor::pid(), [option()]) -> pid()
67 %% option() = {atom(), term()}
68 %% @doc Starts and returns the pid of a new tape server.
69 %% For a description of the allowed options, see the documentation for
70 %% the <code><a href="pibfi.html">pibfi</a></code> module.
71
72 start(Module, Supervisor, Options) ->
73 pibfi_supervisor:spawn_link(Supervisor, "tape server", noncritical,
74 ?MODULE, server, [Module, Options]).
75
76 server(Module, Options) ->
77 NewTape = Module:new(Options),
78 Position = Module:head(NewTape),
79 Value = Module:read(NewTape),
80 WrapTape = pibfi_options:get_option(Options, wraptape, false),
81 MaxTape = pibfi_options:get_option(Options, maxtape, infinity),
82 MinTape = pibfi_options:get_option(Options, mintape, 0),
83 WrapCell = pibfi_options:get_option(Options, wrapcell, false),
84 MaxCell = pibfi_options:get_option(Options, maxcell, infinity),
85 MinCell = pibfi_options:get_option(Options, mincell, 0),
86 case {WrapTape, MaxTape, MinTape, WrapCell, MaxCell, MinCell} of
87 {true, infinity, _, _, _, _} ->
88 exit(maxtape_must_be_finite_when_wraptape_is_true);
89 {true, _, infinity, _, _, _} ->
90 exit(mintape_must_be_finite_when_wraptape_is_true);
91 {_, _, _, true, infinity, _} ->
92 exit(maxcell_must_be_finite_when_wrapcell_is_true);
93 {_, _, _, true, _, infinity} ->
94 exit(mincell_must_be_finite_when_wrapcell_is_true);
95
96 {_, A, B, _, _, _} when B =/= infinity, A =/= infinity, B > A ->
97 exit(mintape_cannot_exceed_maxtape);
98 {_, A, infinity, _, _, _} when A =/= infinity, A < 0 ->
99 exit(mintape_maxtape_range_must_include_start_cell_0);
100 {_, infinity, B, _, _, _} when B =/= infinity, B > 0 ->
101 exit(mintape_maxtape_range_must_include_start_cell_0);
102 {_, A, B, _, _, _} when B =/= infinity, A =/= infinity, B > 0, A > 0 ->
103 exit(mintape_maxtape_range_must_include_start_cell_0);
104 {_, A, B, _, _, _} when B =/= infinity, A =/= infinity, B < 0, A < 0 ->
105 exit(mintape_maxtape_range_must_include_start_cell_0);
106
107 {_, _, _, _, A, B} when B =/= infinity, A =/= infinity, B > A ->
108 exit(mincell_cannot_exceed_maxcell);
109
110 _ ->
111 Value = 0,
112 loop(Module, NewTape, Position, Value,
113 0, 0, 0, 0,
114 MinTape, MaxTape, WrapTape,
115 MinCell, MaxCell, WrapCell)
116 end.
117
118 % only read and examine are synchronous
119
120 loop(Module, Tape, Position, Value,
121 LowPos, HighPos, LowValue, HighValue,
122 MinTape, MaxTape, WrapTape, MinCell, MaxCell, WrapCell) ->
123 {LowPos0, HighPos0} = case Position of
124 L when L < LowPos -> {L, HighPos};
125 H when H > HighPos -> {LowPos, H};
126 _ -> {LowPos, HighPos}
127 end,
128 {LowValue0, HighValue0} = case Value of
129 L0 when L0 < LowValue -> {L0, HighValue};
130 H0 when H0 > HighValue -> {LowValue, H0};
131 _ -> {LowValue, HighValue}
132 end,
133 receive
134 {Pid, increment, N} ->
135 % Pid ! {self(), {increment, N}, ok},
136 Value0 = case WrapCell of
137 true ->
138 pibfi:wrap(Value + N, MinCell, MaxCell);
139 false ->
140 pibfi:assert_in_bounds(tape_cell, MinCell, Value, MaxCell),
141 Value + N
142 end,
143 {Tape0, Value1} = Module:write(Tape, Value0),
144 loop(Module, Tape0, Position, Value1,
145 LowPos0, HighPos0, LowValue0, HighValue0,
146 MinTape, MaxTape, WrapTape, MinCell, MaxCell, WrapCell);
147 {Pid, decrement, N} ->
148 % Pid ! {self(), {decrement, N}, ok},
149 Value0 = case WrapCell of
150 true ->
151 pibfi:wrap(Value - N, MinCell, MaxCell);
152 false ->
153 pibfi:assert_in_bounds(tape_cell, MinCell, Value, MaxCell),
154 Value - N
155 end,
156 {Tape0, Value1} = Module:write(Tape, Value0),
157 loop(Module, Tape0, Position, Value1,
158 LowPos0, HighPos0, LowValue0, HighValue0,
159 MinTape, MaxTape, WrapTape, MinCell, MaxCell, WrapCell);
160 {Pid, left, N} ->
161 % Pid ! {self(), {left, N}, ok},
162 NewPosition = case Position - N of
163 P when MinTape == infinity ->
164 P;
165 P when P < MinTape ->
166 pibfi:assert(WrapTape, {tape_out_of_bounds, P}),
167 pibfi:wrap(P, MinTape, MaxTape);
168 P ->
169 P
170 end,
171 {Tape0, Value0} = Module:left(Tape, N),
172 % ce_log:write("left, newval ~p", [Value0]),
173 loop(Module, Tape0, NewPosition, Value0,
174 LowPos0, HighPos0, LowValue0, HighValue0,
175 MinTape, MaxTape, WrapTape, MinCell, MaxCell, WrapCell);
176 {Pid, right, N} ->
177 % Pid ! {self(), {right, N}, ok},
178 NewPosition = case Position + N of
179 P when MaxTape == infinity ->
180 P;
181 P when P > MaxTape ->
182 pibfi:assert(WrapTape, {tape_out_of_bounds, P}),
183 pibfi:wrap(P, MinTape, MaxTape);
184 P ->
185 P
186 end,
187 {Tape0, Value0} = Module:right(Tape, N),
188 % ce_log:write("right, newval ~p", [Value0]),
189 loop(Module, Tape0, NewPosition, Value0,
190 LowPos0, HighPos0, LowValue0, HighValue0,
191 MinTape, MaxTape, WrapTape, MinCell, MaxCell, WrapCell);
192 {Pid, read} ->
193 Pid ! {self(), read, Module:read(Tape)},
194 loop(Module, Tape, Position, Value,
195 LowPos0, HighPos0, LowValue0, HighValue0,
196 MinTape, MaxTape, WrapTape, MinCell, MaxCell, WrapCell);
197 {Pid, write, Value0} ->
198 % ce_log:write("write: ~p", [Value0]),
199 Value1 = case WrapCell of
200 true ->
201 pibfi:wrap(Value0, MinCell, MaxCell);
202 false ->
203 pibfi:assert_in_bounds(tape_cell, MinCell, Value0, MaxCell),
204 Value0
205 end,
206 {Tape0, Value2} = Module:write(Tape, Value1),
207 % ce_log:write("writing ~p", [Value2]),
208 % Pid ! {self(), {write, Value}, Value2},
209 loop(Module, Tape0, Position, Value2,
210 LowPos0, HighPos0, LowValue0, HighValue0,
211 MinTape, MaxTape, WrapTape, MinCell, MaxCell, WrapCell);
212 {Pid, examine} ->
213 server_examine(Module, Tape, Position, Value,
214 LowPos0, HighPos0, LowValue0, HighValue0,
215 MinTape, MaxTape, WrapTape, MinCell, MaxCell, WrapCell),
216 Pid ! {self(), examine, ok},
217 loop(Module, Tape, Position, Value,
218 LowPos0, HighPos0, LowValue0, HighValue0,
219 MinTape, MaxTape, WrapTape, MinCell, MaxCell, WrapCell)
220 end.
221
222 %% @spec left(pid()) -> ok
223 %% @doc Moves the read/write head one position left on the tape.
224
225 left(TapePid) -> left(TapePid, 1).
226
227 %% @spec left(pid(), N::integer()) -> ok
228 %% @doc Moves the read/write head N positions left on the tape.
229
230 left(TapePid, N) ->
231 TapePid ! {self(), left, N}. % , waitfor({TapePid, {left, N}, ok}).
232
233 %% @spec right(pid()) -> ok
234 %% @doc Moves the read/write head one position right on the tape.
235
236 right(TapePid) -> right(TapePid, 1).
237
238 %% @spec right(pid(), N::integer()) -> ok
239 %% @doc Moves the read/write head N positions right on the tape.
240
241 right(TapePid, N) ->
242 TapePid ! {self(), right, N}. % , waitfor({TapePid, {right, N}, ok}).
243
244 %% @spec read(pid()) -> integer()
245 %% @doc Returns the value at the current position on the tape.
246
247 read(TapePid) ->
248 TapePid ! {self(), read},
249 receive
250 {TapePid, read, X} ->
251 X
252 end.
253
254 waitfor(Thing) ->
255 receive
256 Thing ->
257 ok
258 after 1000 ->
259 {error, timeout}
260 end.
261
262 %% @spec write(tape(), integer()) -> {ok, integer()} | {error, Reason}
263 %% @doc Places the given value at the current position on the tape.
264
265 write(TapePid, Value) ->
266 TapePid ! {self(), write, Value}.
267
268 %% @spec increment(tape()) -> ok | {error, Reason}
269 %% @doc Increments the value at the current position on the tape.
270
271 increment(TapePid) -> increment(TapePid, 1).
272
273 %% @spec increment(tape(), N::integer()) -> ok | {error, Reason}
274 %% @doc Increments the value at the current position on the tape N times.
275
276 increment(TapePid, N) ->
277 TapePid ! {self(), increment, N}.
278
279 %% @spec decrement(tape()) -> ok | {error, Reason}
280 %% @doc Decrements the value at the current position on the tape.
281
282 decrement(TapePid) -> decrement(TapePid, 1).
283
284 %% @spec decrement(tape(), N::integer()) -> ok | {error, Reason}
285 %% @doc Decrements the value at the current position on the tape N times.
286
287 decrement(TapePid, N) ->
288 TapePid ! {self(), decrement, N}.
289
290 %% @spec examine(TapePid::pid()) -> ok | {error, Reason}
291 %% @doc Examines the state of the tape.
292
293 examine(TapePid) ->
294 TapePid ! {self(), examine}, waitfor({TapePid, examine, ok}).
295
296
297 server_examine(Module, Tape, Position, Value,
298 LowPos, HighPos, LowValue, HighValue,
299 MinTape, MaxTape, WrapTape,
300 MinCell, MaxCell, WrapCell) ->
301 case Position of
302 0 ->
303 io:fwrite("+ Tape head position: at start");
304 1 ->
305 io:fwrite("+ Tape head position: 1 cell right of start");
306 -1 ->
307 io:fwrite("+ Tape head position: 1 cell left of start");
308 P when P > 1 ->
309 io:fwrite("+ Tape head position: ~p cells right of start",
310 [Position]);
311 P when P < -1 ->
312 io:fwrite("+ Tape head position: ~p cells left of start",
313 [-1 * Position])
314 end,
315 io:fwrite(", cell contents: ~p~n", [Value]),
316 io:fwrite("+ Tape observed head position: min ~p, max ~p, range ~p~n",
317 [LowPos, HighPos, (HighPos - LowPos) + 1]),
318 io:fwrite("+ Tape observed cell contents: min ~p, max ~p, range ~p~n",
319 [LowValue, HighValue, (HighValue - LowValue) + 1]),
320 Low = case Position - 5 of
321 L when MinTape =/= infinity, L < MinTape ->
322 MinTape;
323 L ->
324 L
325 end,
326 High = case Position + 4 of
327 H when MaxTape =/= infinity, H > MaxTape ->
328 MaxTape;
329 H ->
330 H
331 end,
332 io:fwrite("+ Tape contents (~p - ~p cells right of start):~n", [Low, High]),
333 Range = lists:seq(Low, High),
334 lists:foreach(fun(X) ->
335 A = case X of
336 Position ->
337 "->#" ++ integer_to_list(X);
338 _ ->
339 "#" ++ integer_to_list(X)
340 end,
341 io:fwrite("~8s", [A])
342 end, Range),
343 io:nl(),
344 TapeContext = lists:reverse(lists:foldl(fun(X, A) ->
345 [Module:peek(Tape, X) | A]
346 end, [], Range)),
347 lists:foreach(fun(X) ->
348 io:fwrite("~8w", [X])
349 end, TapeContext),
350 io:nl().
351
352 %%% END of pibfi_tape.erl %%%
0 %%% BEGIN pibfi_tape_dict.erl %%%
1 %%%
2 %%% pibfi - Platonic Ideal Brainf*ck Interpreter
3 %%% Copyright (c)2003 Cat's Eye Technologies. All rights reserved.
4 %%%
5 %%% Redistribution and use in source and binary forms, with or without
6 %%% modification, are permitted provided that the following conditions
7 %%% are met:
8 %%%
9 %%% Redistributions of source code must retain the above copyright
10 %%% notice, this list of conditions and the following disclaimer.
11 %%%
12 %%% Redistributions in binary form must reproduce the above copyright
13 %%% notice, this list of conditions and the following disclaimer in
14 %%% the documentation and/or other materials provided with the
15 %%% distribution.
16 %%%
17 %%% Neither the name of Cat's Eye Technologies nor the names of its
18 %%% contributors may be used to endorse or promote products derived
19 %%% from this software without specific prior written permission.
20 %%%
21 %%% THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
22 %%% CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
23 %%% INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
24 %%% MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
25 %%% DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE
26 %%% LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
27 %%% OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
28 %%% PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
29 %%% OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
30 %%% ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
31 %%% OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
32 %%% OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
33 %%% POSSIBILITY OF SUCH DAMAGE.
34
35 %% @doc Dict backend for tape ADT for the Platonic Ideal Brainf*ck Interpreter.
36 %%
37 %% @end
38
39 -module(pibfi_tape_dict).
40 -vsn('2003.0427').
41 -copyright('Copyright (c)2003 Cat`s Eye Technologies. All rights reserved.').
42
43 -behaviour(pibfi_tape).
44
45 -export([new/1]).
46 -export([left/2, right/2]).
47 -export([read/1, write/2]).
48 -export([peek/2, poke/3, head/1]).
49
50 %% @spec new([option()]) -> tape()
51 %% option() = {atom(), term()}
52 %% tape() = tape()
53 %% @doc Creates and returns a new tape.
54 %% For a description of the allowed options, see the documentation for
55 %% the <code><a href="pibfi.html">pibfi</a></code> module.
56
57 new(Options) ->
58 {0, dict:new()}.
59
60 %% @spec left(tape(), N::integer()) -> {tape(), integer()}
61 %% @doc Moves the read/write head N positions left on the tape.
62
63 left({Position, Dict}, N) ->
64 {{Position - N, Dict}, read({Position - N, Dict})}.
65
66 %% @spec right(tape(), N::integer()) -> {tape(), integer()}
67 %% @doc Moves the read/write head N positions right on the tape.
68
69 right({Position, Dict}, N) ->
70 {{Position + N, Dict}, read({Position + N, Dict})}.
71
72 %% @spec read(tape()) -> integer()
73 %% @doc Returns the value at the current position on the tape.
74
75 read({Position, Dict}) ->
76 case dict:find(Position, Dict) of
77 error ->
78 0;
79 {ok, Value} ->
80 Value
81 end.
82
83 %% @spec write(tape(), integer()) -> {tape(), integer()}
84 %% @doc Places the given value at the current position on the tape.
85
86 write({Position, Dict}, Value) ->
87 {{Position, dict:store(Position, Value, Dict)}, Value}.
88
89 peek({Position, Dict}, Addr) ->
90 read({Addr, Dict}).
91
92 poke({Position, Dict}, Addr, Value) ->
93 {Position, dict:store(Addr, Value, Dict)}.
94
95 head({Position, Dict}) ->
96 Position.
97
98 %%% END of pibfi_tape_dict.erl %%%
0 %%% BEGIN pibfi_tape_dynarray.erl %%%
1 %%%
2 %%% pibfi - Platonic Ideal Brainf*ck Interpreter
3 %%% Copyright (c)2003 Cat's Eye Technologies. All rights reserved.
4 %%%
5 %%% Redistribution and use in source and binary forms, with or without
6 %%% modification, are permitted provided that the following conditions
7 %%% are met:
8 %%%
9 %%% Redistributions of source code must retain the above copyright
10 %%% notice, this list of conditions and the following disclaimer.
11 %%%
12 %%% Redistributions in binary form must reproduce the above copyright
13 %%% notice, this list of conditions and the following disclaimer in
14 %%% the documentation and/or other materials provided with the
15 %%% distribution.
16 %%%
17 %%% Neither the name of Cat's Eye Technologies nor the names of its
18 %%% contributors may be used to endorse or promote products derived
19 %%% from this software without specific prior written permission.
20 %%%
21 %%% THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
22 %%% CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
23 %%% INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
24 %%% MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
25 %%% DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE
26 %%% LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
27 %%% OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
28 %%% PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
29 %%% OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
30 %%% ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
31 %%% OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
32 %%% OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
33 %%% POSSIBILITY OF SUCH DAMAGE.
34
35 %% @doc dynarray backend for tape ADT for <code>pibfi</code>.
36 %%
37 %% @end
38
39 -module(pibfi_tape_dynarray).
40 -vsn('2003.0427').
41 -copyright('Copyright (c)2003 Cat`s Eye Technologies. All rights reserved.').
42
43 -behaviour(pibfi_tape).
44
45 -export([new/1]).
46 -export([left/2, right/2, increment/2, decrement/2]).
47 -export([read/1, write/2, peek/2, poke/3, head/1]).
48
49 %% @spec new([option()]) -> tape()
50 %% option() = {atom(), term()}
51 %% tape() = tape()
52 %% @doc Creates and returns a new dynarray-backed tape.
53
54 new(Options) ->
55 0 = pibfi_options:get_option(Options, mintape, 0),
56 {1, dynarray:new()}.
57
58 %% @spec left(tape(), N::integer()) -> {tape(), integer()}
59 %% @doc Moves the read/write head N positions left on the tape.
60
61 left({Position, DynArray}, N) ->
62 {{Position - N, DynArray}, lookup(Position - N, DynArray)}.
63
64 %% @spec right(tape(), N::integer()) -> {tape(), integer()}
65 %% @doc Moves the read/write head N positions right on the tape.
66
67 right({Position, DynArray}, N) ->
68 {{Position + N, DynArray}, lookup(Position + N, DynArray)}.
69
70 %% @spec read(tape()) -> integer()
71 %% @doc Returns the value at the current position on the tape.
72
73 read({Position, DynArray}) -> lookup(Position, DynArray).
74
75 %% @spec write(tape(), integer()) -> {tape(), integer()}
76 %% @doc Places the given value at the current position on the tape.
77
78 write({Position, DynArray}, Value) ->
79 {{Position, dynarray:insert(Position, DynArray, Value)}, Value}.
80
81 %% @spec increment(tape(), N::integer()) -> tape()
82 %% @doc Increments the value at the current position on the tape N times.
83
84 increment(Tape, N) ->
85 write(Tape, read(Tape) + N).
86
87 %% @spec decrement(tape(), N::integer()) -> tape()
88 %% @doc Decrements the value at the current position on the tape N times.
89
90 decrement(Tape, N) ->
91 write(Tape, read(Tape) - N).
92
93 peek({Position, DynArray}, Addr) ->
94 lookup(Addr + 1, DynArray).
95
96 poke({Position, DynArray}, Addr, Value) ->
97 {Position, dynarray:insert(Addr + 1, DynArray, Value)}.
98
99 head({Position, DynArray}) ->
100 Position - 1.
101
102 lookup(Position, DynArray) ->
103 % ce_log:write("looking up ~p ~p", [Position, DynArray]),
104 case dynarray:lookup(Position, DynArray) of
105 [] ->
106 0;
107 Else when is_integer(Else) ->
108 Else
109 end.
110
111 %%% END of pibfi_tape_dynarray.erl %%%
0 %%% BEGIN pibfi_tape_ets.erl %%%
1 %%%
2 %%% pibfi - Platonic Ideal Brainf*ck Interpreter
3 %%% Copyright (c)2003 Cat's Eye Technologies. All rights reserved.
4 %%%
5 %%% Redistribution and use in source and binary forms, with or without
6 %%% modification, are permitted provided that the following conditions
7 %%% are met:
8 %%%
9 %%% Redistributions of source code must retain the above copyright
10 %%% notice, this list of conditions and the following disclaimer.
11 %%%
12 %%% Redistributions in binary form must reproduce the above copyright
13 %%% notice, this list of conditions and the following disclaimer in
14 %%% the documentation and/or other materials provided with the
15 %%% distribution.
16 %%%
17 %%% Neither the name of Cat's Eye Technologies nor the names of its
18 %%% contributors may be used to endorse or promote products derived
19 %%% from this software without specific prior written permission.
20 %%%
21 %%% THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
22 %%% CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
23 %%% INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
24 %%% MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
25 %%% DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE
26 %%% LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
27 %%% OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
28 %%% PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
29 %%% OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
30 %%% ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
31 %%% OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
32 %%% OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
33 %%% POSSIBILITY OF SUCH DAMAGE.
34
35 %% @doc ETS backend for tape ADT for the Platonic Ideal Brainf*ck Interpreter.
36 %%
37 %% @end
38
39 -module(pibfi_tape_ets).
40 -vsn('2003.0427').
41 -copyright('Copyright (c)2003 Cat`s Eye Technologies. All rights reserved.').
42
43 -behaviour(pibfi_tape).
44
45 -export([new/1]).
46 -export([left/2, right/2]).
47 -export([read/1, write/2]).
48 -export([peek/2, poke/3, head/1]).
49
50 %% @spec new([option()]) -> tape()
51 %% option() = {atom(), term()}
52 %% tape() = tape()
53 %% @doc Creates and returns a new ETS-backed tape.
54
55 new(Options) ->
56 ets:new(?MODULE, [public, named_table]),
57 {0, ?MODULE}.
58
59 %% @spec left(tape(), N::integer()) -> {tape(), integer()}
60 %% @doc Moves the read/write head N positions left on the tape.
61
62 left({Position, ?MODULE}, N) ->
63 {{Position - N, ?MODULE}, read({Position - N, ?MODULE})}.
64
65 %% @spec right(tape(), N::integer()) -> {tape(), integer()}
66 %% @doc Moves the read/write head N positions right on the tape.
67
68 right({Position, ?MODULE}, N) ->
69 {{Position + N, ?MODULE}, read({Position + N, ?MODULE})}.
70
71 %% @spec read(tape()) -> integer()
72 %% @doc Returns the value at the current position on the tape.
73
74 read({Position, ?MODULE}) ->
75 case ets:lookup(?MODULE, Position) of
76 [] ->
77 0;
78 [{Position, Value}] ->
79 Value
80 end.
81
82 %% @spec write(tape(), integer()) -> {tape(), integer()}
83 %% @doc Places the given value at the current position on the tape.
84
85 write({Position, ?MODULE}, Value) ->
86 ets:insert(?MODULE, {Position, Value}),
87 {{Position, ?MODULE}, Value}.
88
89 peek({Position, ?MODULE}, Addr) ->
90 read({Addr, ?MODULE}).
91
92 poke({Position, ?MODULE}, Addr, Value) ->
93 ets:store(?MODULE, Addr, Value),
94 {Position, ?MODULE}.
95
96 head({Position, ?MODULE}) ->
97 Position.
98
99 %%% END of pibfi_tape_ets.erl %%%
0 %%% BEGIN pibfi_tape_tuple.erl %%%
1 %%%
2 %%% pibfi - Platonic Ideal Brainf*ck Interpreter
3 %%% Copyright (c)2003 Cat's Eye Technologies. All rights reserved.
4 %%%
5 %%% Redistribution and use in source and binary forms, with or without
6 %%% modification, are permitted provided that the following conditions
7 %%% are met:
8 %%%
9 %%% Redistributions of source code must retain the above copyright
10 %%% notice, this list of conditions and the following disclaimer.
11 %%%
12 %%% Redistributions in binary form must reproduce the above copyright
13 %%% notice, this list of conditions and the following disclaimer in
14 %%% the documentation and/or other materials provided with the
15 %%% distribution.
16 %%%
17 %%% Neither the name of Cat's Eye Technologies nor the names of its
18 %%% contributors may be used to endorse or promote products derived
19 %%% from this software without specific prior written permission.
20 %%%
21 %%% THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
22 %%% CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
23 %%% INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
24 %%% MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
25 %%% DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE
26 %%% LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
27 %%% OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
28 %%% PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
29 %%% OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
30 %%% ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
31 %%% OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
32 %%% OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
33 %%% POSSIBILITY OF SUCH DAMAGE.
34
35 %% @doc Tuple backend for tape ADT for <code>pibfi</code>.
36 %%
37 %% @end
38
39 -module(pibfi_tape_tuple).
40 -vsn('2003.0427').
41 -copyright('Copyright (c)2003 Cat`s Eye Technologies. All rights reserved.').
42
43 -behaviour(pibfi_tape).
44
45 -export([new/1]).
46 -export([left/2, right/2, increment/2, decrement/2]).
47 -export([read/1, write/2, peek/2, poke/3, head/1]).
48
49 %% @spec new([option()]) -> tape()
50 %% option() = {atom(), term()}
51 %% tape() = tape()
52 %% @doc Creates and returns a new tuple-backed tape.
53
54 new(Options) ->
55 0 = pibfi_options:get_option(Options, mintape, 0),
56 Max = pibfi_options:get_option(Options, maxtape, 30000),
57 {1, erlang:make_tuple(Max, 0)}.
58
59 %% @spec left(tape(), N::integer()) -> {tape(), integer()}
60 %% @doc Moves the read/write head N positions left on the tape.
61
62 left({Position, Tuple}, N)
63 when (Position - N) >= 1 ->
64 {{Position - N, Tuple}, element(Position - N, Tuple)}.
65
66 %% @spec right(tape(), N::integer()) -> {tape(), integer()}
67 %% @doc Moves the read/write head N positions right on the tape.
68
69 right({Position, Tuple}, N)
70 when (Position + N) =< size(Tuple) ->
71 {{Position + N, Tuple}, element(Position + N, Tuple)}.
72
73 %% @spec read(tape()) -> integer()
74 %% @doc Returns the value at the current position on the tape.
75
76 read({Position, Tuple}) -> element(Position, Tuple).
77
78 %% @spec write(tape(), integer()) -> {tape(), integer()}
79 %% @doc Places the given value at the current position on the tape.
80
81 write({Position, Tuple}, Value) ->
82 {{Position, setelement(Position, Tuple, Value)}, Value}.
83
84 %% @spec increment(tape(), N::integer()) -> tape()
85 %% @doc Increments the value at the current position on the tape N times.
86
87 increment(Tape, N) ->
88 write(Tape, read(Tape) + N).
89
90 %% @spec decrement(tape(), N::integer()) -> tape()
91 %% @doc Decrements the value at the current position on the tape N times.
92
93 decrement(Tape, N) ->
94 write(Tape, read(Tape) - N).
95
96 peek({Position, Tuple}, Addr) ->
97 element(Addr + 1, Tuple).
98
99 poke({Position, Tuple}, Addr, Value) ->
100 {Position, setelement(Addr + 1, Value, Tuple)}.
101
102 head({Position, Tuple}) ->
103 Position - 1.
104
105 %%% END of pibfi_tape_tuple.erl %%%
0 %%% BEGIN pibfi_xlat.erl %%%
1 %%%
2 %%% pibfi - Platonic Ideal Brainf*ck Interpreter
3 %%% Copyright (c)2003 Cat's Eye Technologies. All rights reserved.
4 %%%
5 %%% Redistribution and use in source and binary forms, with or without
6 %%% modification, are permitted provided that the following conditions
7 %%% are met:
8 %%%
9 %%% Redistributions of source code must retain the above copyright
10 %%% notice, this list of conditions and the following disclaimer.
11 %%%
12 %%% Redistributions in binary form must reproduce the above copyright
13 %%% notice, this list of conditions and the following disclaimer in
14 %%% the documentation and/or other materials provided with the
15 %%% distribution.
16 %%%
17 %%% Neither the name of Cat's Eye Technologies nor the names of its
18 %%% contributors may be used to endorse or promote products derived
19 %%% from this software without specific prior written permission.
20 %%%
21 %%% THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
22 %%% CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
23 %%% INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
24 %%% MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
25 %%% DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE
26 %%% LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
27 %%% OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
28 %%% PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
29 %%% OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
30 %%% ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
31 %%% OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
32 %%% OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
33 %%% POSSIBILITY OF SUCH DAMAGE.
34
35 %% @doc Character translation server for <code>pibfi</code>.
36 %%
37 %% <p>This is not efficient. An efficient implementation would compile
38 %% the candidates into a finite-state machine first. This doesn't do that.</p>
39 %%
40 %% @end
41
42 -module(pibfi_xlat).
43 -vsn('2003.0427').
44 -author('catseye@catseye.mb.ca').
45 -copyright('Copyright (c)2003 Cat`s Eye Technologies. All rights reserved.').
46
47 -export([start/2, server/2]).
48 -export([send/2, notify/2, flush/1]).
49 -export([test/0]).
50
51 %% @spec start(candidates(), Dest::pid()) -> xlat()
52 %% candidates() = [{string(), string()}]
53 %% xlat() = pid()
54 %% string() = [char()]
55 %% char() = integer()
56 %% @doc Starts an xlat server. Candidates is a list of pairs of strings.
57 %% Characters are sent to the xlat server with the <code>send/2</code>
58 %% function. When they match the left
59 %% string of a candidate, the right string is sent to Dest instead.
60 %% If they do not match any candidates, they are sent through unaltered.
61 %% Characters are sent to Dest in the form
62 %% <code>{xlat(), xlat_char, char()}</code>.
63 %% Note that if two candidates have the same left string, the result of
64 %% the translation is undefined. Also note that if one candidate has
65 %% a left string that is a prefix of another candidate's left string,
66 %% that second candidate will never match (the shorter one will always
67 %% be matched first.)
68
69 start(Candidates, Dest) ->
70 spawn_link(?MODULE, server, [Candidates, Dest]).
71
72 %% @spec server(candidates(), Dest::pid()) -> never_returns()
73 %% @doc Spawned by <code>start/2</code>, should not be called
74 %% directly by user code.
75
76 server(Candidates, Dest) ->
77 loop(Candidates, Candidates, Dest, []).
78
79 loop(Candidates, Working, Dest, Chars) ->
80 receive
81 {Pid, flush} ->
82 gen_string(lists:reverse(Chars), Dest),
83 Pid ! {self(), flush, ok},
84 loop(Candidates, Candidates, Dest, []);
85 {Pid, notify, Term} ->
86 Dest ! {self(), Pid, message, Term},
87 loop(Candidates, Working, Dest, Chars);
88 {Pid, xlat_char, Char} ->
89 % find all the things in our candidates that start with char
90 sub_loop(Candidates, Working, Dest, Chars, Char)
91 end.
92
93 sub_loop(Candidates, Working, Dest, Chars, Char) ->
94 case get_candidates(Working, Char) of
95 [] ->
96 % ce_log:write("got nothin ~p", [{Char, Chars}]),
97 % we got nothin. just send the chars they sent so far
98 case Chars of
99 [] ->
100 Dest ! {self(), xlat_char, Char},
101 loop(Candidates, Candidates, Dest, []);
102 _ ->
103 % we now have to invalidate our assumptions about these
104 gen_string(lists:reverse(Chars), Dest),
105 % and immediately re-check this char from the beginning
106 sub_loop(Candidates, Candidates, Dest, [], Char)
107 end;
108 [{"", To} | Tail] ->
109 % we got a match.
110 gen_string(To, Dest),
111 loop(Candidates, Candidates, Dest, []);
112 NewCandidates ->
113 % we got more than one partially matching candidate.
114 loop(Candidates, NewCandidates, Dest, [Char | Chars])
115 end.
116
117 get_candidates(L, Char) ->
118 lists:sort(lists:foldl(fun
119 ({[Ch | Tail], To}, Acc) when Ch == Char->
120 [{Tail, To} | Acc];
121 (_, Acc) ->
122 Acc
123 end, [], L)).
124
125 gen_string(String, Dest) ->
126 lists:foreach(fun(Z) ->
127 Dest ! {self(), xlat_char, Z}
128 end, String).
129
130 %%% interface
131
132 %% @spec send(xlat(), char() | string()) -> ok
133 %% @doc Sends a character or characters to an xlat server for translation.
134
135 send(Pid, Chars) when is_list(Chars) ->
136 lists:foreach(fun(Char) ->
137 % timer:sleep(100),
138 Pid ! {self(), xlat_char, Char}
139 end, Chars),
140 ok;
141
142 send(Pid, Char) ->
143 Pid ! {self(), xlat_char, Char},
144 ok.
145
146 %% @spec notify(xlat(), term()) -> ok
147 %% @doc Notifies the other end of the connection.
148 %% They will receive a <code>{Xlat::pid(), Notifier::pid(), message, term()}</code> message.
149
150 notify(Pid, Term) ->
151 Pid ! {self(), notify, Term},
152 ok.
153
154 %% @spec flush(xlat()) -> ok
155 %% @doc Causes the xlat server to flush all its characters to the output,
156 %% even ones in the process of matching candidate strings. Typically
157 %% this is called before the output is closed.
158
159 flush(Pid) ->
160 Pid ! {self(), flush},
161 receive
162 {Pid, flush, Result} ->
163 Result
164 end.
165
166 test() ->
167 lists:foreach(fun({S, P}) ->
168 test(S, P),
169 io:fwrite("\n\n")
170 end,
171 [
172 {"Oh look, a here-doc.",
173 [{"er", "e"}]},
174 {"Oh look, a here-doc.",
175 [{"re", "e"}]},
176 {"Oh look, a here-doc.",
177 [{"er", "!"}]},
178 {"Oh look, a here-doc.",
179 [{"re", "!"}]},
180 {"Brak and Zorak were both eaten by a bear.",
181 [{"Brak", "Zorak"}, {"Zorak", "Brak"}]},
182 {"Hello, world!",
183 [{"lo", "LO"}, {"ld", "KPLACE"}, {" ", ""}, {"!", "?"}]}
184 ]).
185
186 test(String, XlatList) ->
187 Xlat = start(XlatList, self()),
188 send(Xlat, lists:flatten(String)),
189 flush(Xlat),
190 flush().
191 flush() ->
192 receive
193 {Xlat, xlat_char, Char} ->
194 io:fwrite("~c", [Char]),
195 flush();
196 X ->
197 io:fwrite("~p~n", [X]),
198 flush()
199 after 2000 ->
200 ok
201 end.
202
203 %%% END of ce_xlat.erl %%%