Initial import of pibfi version 1.0 revision 2003.0505 sources.
catseye
12 years ago
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
Binary diff not shown
Binary diff not shown
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 %%% |