Merge pull request #2 from catseye/develop-2021
Develop 1.1-2021.0622
Chris Pressey authored 1 year, 5 days ago
GitHub committed 1 year, 5 days ago
0 | ZOWIE version history | |
1 | ===================== | |
2 | ||
3 | Version 1.0 (Dec 29 2009) | |
4 | ------------------------- | |
5 | ||
6 | * Initial release. | |
7 | ||
8 | Version 1.0 revision 2011.1214 | |
9 | ------------------------------ | |
10 | ||
11 | * Trivial tweaks to the documentation's HTML. | |
12 | ||
13 | Version 1.0 revision 2012.0325 | |
14 | ------------------------------ | |
15 | ||
16 | * Converted documentation to Markdown format. | |
17 | * PEP-8 cleanups to `zowie.py`; no functional changes. | |
18 | ||
19 | Version 1.0 revision 2014.0819 | |
20 | ------------------------------ | |
21 | ||
22 | * Added ability to run `zowie.py` under Skulpt, and demo HTML page of this. | |
23 | * Added some rudimentary Falderal tests. | |
24 | * Added UNLICENSE to emphasize the public domain status of these materials. | |
25 | * Made `zowie.py` file executable, using `/usr/bin/env` to find `python`. | |
26 | * More Markdown, whitespace, and PEP-8 cleanups. | |
27 | ||
28 | Version 1.1 | |
29 | ----------- | |
30 | ||
31 | * Made syntax more strict: | |
32 | * Names of commands and registers must be in uppercase. | |
33 | * Previous lax parsing of indirect register references was dropped. | |
34 | * Because this above changed the definition of the language, but not in any | |
35 | jaw-dropping way, the minor version number was bumped. | |
36 | * Uses of regular expressions and old-style classes `zowie.py` were dropped. | |
37 | * Added ability to compile `zowie.py` with RPython from PyPy version 2.3.1. | |
38 | ||
39 | Version 1.1 revision 2019.0122 | |
40 | ------------------------------ | |
41 | ||
42 | * Added example Javascript files demonstrating how zowie.py can be run | |
43 | under Skulpt in a web browser. |
0 | ZOWIE version history | |
1 | ===================== | |
2 | ||
3 | Version 1.0 (Dec 29 2009) | |
4 | ------------------------- | |
5 | ||
6 | * Initial release. | |
7 | ||
8 | Version 1.0 revision 2011.1214 | |
9 | ------------------------------ | |
10 | ||
11 | * Trivial tweaks to the documentation's HTML. | |
12 | ||
13 | Version 1.0 revision 2012.0325 | |
14 | ------------------------------ | |
15 | ||
16 | * Converted documentation to Markdown format. | |
17 | * PEP-8 cleanups to `zowie.py`; no functional changes. | |
18 | ||
19 | Version 1.0 revision 2014.0819 | |
20 | ------------------------------ | |
21 | ||
22 | * Added ability to run `zowie.py` under Skulpt, and demo HTML page of this. | |
23 | * Added some rudimentary Falderal tests. | |
24 | * Added UNLICENSE to emphasize the public domain status of these materials. | |
25 | * Made `zowie.py` file executable, using `/usr/bin/env` to find `python`. | |
26 | * More Markdown, whitespace, and PEP-8 cleanups. | |
27 | ||
28 | Version 1.1 | |
29 | ----------- | |
30 | ||
31 | * Made syntax more strict: | |
32 | * Names of commands and registers must be in uppercase. | |
33 | * Previous lax parsing of indirect register references was dropped. | |
34 | * Because this above changed the definition of the language, but not in any | |
35 | jaw-dropping way, the minor version number was bumped. | |
36 | * Uses of regular expressions and old-style classes `zowie.py` were dropped. | |
37 | * Added ability to compile `zowie.py` with RPython from PyPy version 2.3.1. | |
38 | ||
39 | Version 1.1 revision 2019.0122 | |
40 | ------------------------------ | |
41 | ||
42 | * Added example Javascript files demonstrating how zowie.py can be run | |
43 | under Skulpt in a web browser. | |
44 | ||
45 | Version 1.1 revision 2021.0622 | |
46 | ------------------------------ | |
47 | ||
48 | * Updated reference implementation to be able to run under either Python 2 | |
49 | or Python 3. | |
50 | * Allowed reference implementation to be compiled by the RPython compiler | |
51 | from PyPy version 7.3.5. Note that the RPython-compiled version cannot | |
52 | currently output Unicode, and always falls back to the `&#...;` syntax | |
53 | when outputting non-ASCII characters. | |
54 | * More idiomatic structuring of the Falderal test files. |
0 | ZOWIE | |
1 | ===== | |
2 | ||
3 | Introduction | |
4 | ------------ | |
5 | ||
6 | ZOWIE is a programming language where all control flow is both | |
7 | *memory-mapped* and *structured*. It is memory-mapped in the sense that | |
8 | changes in flow are triggered by changes made to memory locations, and | |
9 | it is structured in the sense of structured programming – the programmer | |
10 | never deals with `goto`s, offsets, or labels of any kind. | |
11 | ||
12 | History | |
13 | ------- | |
14 | ||
15 | The primary design goal of ZOWIE was to have memory-mapped structured | |
16 | control flow. This goal was inspired by Jeffry Johnston's unsuccessful | |
17 | attempt to reduce the number of instructions in | |
18 | [BitChanger](http://esolangs.org/wiki/BitChanger) (while retaining | |
19 | Turing-completeness) by memory-mapping the loop operation. | |
20 | ||
21 | I initially thought that the difficulty lay in BitChanger's minimalism. | |
22 | To do memory-mapped flow control in general sounded easy – just start a | |
23 | loop when one memory location is written, and end it when some other | |
24 | location is written, right? But no. It's not that simple, as I attempt | |
25 | to explain below. ZOWIE is the last of several, sometimes painful, | |
26 | attempts over the summer of 2009 to realize this design goal (and it is | |
27 | not clear that the techniques used in ZOWIE could be usefully imported | |
28 | back into BitChanger.) The final, workable idea crystallized at about | |
29 | the time September turned into October. | |
30 | ||
31 | The thing with loop structures is that there is usually some way to jump | |
32 | to a known point in the loop (say, the start, or the end) – really, | |
33 | that's what makes them structured. And to jump to a point in a loop, you | |
34 | have to know where that point is. And if you can analyze the loop | |
35 | structure statically, for example if your semantics are directed by | |
36 | syntax as in almost all high-level languages, then it's not difficult to | |
37 | know where that point is. | |
38 | ||
39 | But if that point is defined by when some *memory* location is changed, | |
40 | it is not in general possible to detect it statically (by Rice's | |
41 | Theorem, which is just a generalization of the Halting Problem.) So it | |
42 | is not, in general, possible to know ahead of time where the loop begins | |
43 | or ends. | |
44 | ||
45 | There are a few things to note about this. | |
46 | ||
47 | One is that by "statically" I do not necessarily mean "at compile-time". | |
48 | Many Brainfuck and Mouse interpreters seek out the end of the loop only | |
49 | when they know they must exit it. However, because they are looking | |
50 | through the program text, it is still a kind of static analysis. | |
51 | ||
52 | Another thing is that it would of course be possible to detect some kind | |
53 | of (fixed) command to change the memory location associated with ending | |
54 | a loop – but that would be cheating! (Also, if memory locations can be | |
55 | computed, it is still not fully general, because we cannot look for all | |
56 | possible computations that would result in that memory location.) | |
57 | ||
58 | Lastly, note that we really don't have a problem detecting the start of | |
59 | a loop. As soon as we execute the start of a loop, we know it's a loop, | |
60 | and we know where it is, so we can record that location. The problem is | |
61 | any other point in the loop, like the end. A little reflection will | |
62 | reveal that this means it will be more difficult to do a "WHILE" loop or | |
63 | a structured conditional ("IF-THEN-ENDIF") than a "REPEAT" loop (where | |
64 | the condition is at the end of the loop.) However, it is widely known | |
65 | that "REPEAT" loops alone are not sufficient for a Turing-complete | |
66 | language. We'll see below that ZOWIE manages to create generalized loops | |
67 | through the use of transactions. | |
68 | ||
69 | The secondary design goal of ZOWIE was to strike the perfect balance | |
70 | between _It's a Mad Mad Mad Mad World_ and _The Party_. It is generally | |
71 | considered a morbid failure in that regard, what with not being a madcap | |
72 | 60's movie and all. | |
73 | ||
74 | Syntax and Semantics | |
75 | -------------------- | |
76 | ||
77 | To mitigate retooling costs, ZOWIE borrows much of its archiecture and | |
78 | instruction repertoire from [SMITH](http://catseye.tc/projects/smith/). | |
79 | There are an unlimited number of registers, numbered from 0 upward; each | |
80 | register contains a non-negative integer value of unbounded extent. The | |
81 | contents of a register before it has ever been written is guaranteed to | |
82 | be 0. | |
83 | ||
84 | There are five instruction forms. The first register is the destination | |
85 | register, and is written to; the second register (or immediate value) is | |
86 | read from. As in SMITH, square brackets indicate indirect register | |
87 | access. All instruction forms are case-sensitive; they must be given | |
88 | using capital letters. | |
89 | ||
90 | MOV register, immediate e.g. MOV R8, 141 | |
91 | MOV register, register MOV R8, R9 | |
92 | MOV [register], register MOV R[R8], R9 | |
93 | MOV register, [register] MOV R8, R[R9] | |
94 | MOV [register], [register] MOV R[R8], R[R9] | |
95 | ||
96 | Not only flow control, but in fact all operations in ZOWIE are | |
97 | memory-mapped. The lowest-numbered nine registers have special behaviour | |
98 | when written to or read from: | |
99 | ||
100 | `R0` | |
101 | ||
102 | When a value is written into R0, the Unicode symbol represented by the | |
103 | value is sent to the standard output channel. | |
104 | ||
105 | Reading from R0 waits until a Unicode symbol is available on the | |
106 | standard input, then offers its value as the value of this register. | |
107 | ||
108 | This is similar to the `TTY` pseudo-register of SMITH. | |
109 | ||
110 | *Note: although implementations should make a best effort, the external | |
111 | encoding and representation of Unicode characters is ultimately | |
112 | implementation-defined, especially on systems which are only capable of | |
113 | accurately displaying a subset of the Unicode character set. For | |
114 | example, on a strict ASCII teletype or other device incapable of | |
115 | displaying the DOWNWARDS ARROW (↓) symbol, it would be reasonable to | |
116 | output `↓` or some similar "escape sequence" when executing | |
117 | `MOV R0, 8595`.* | |
118 | ||
119 | `R1` | |
120 | ||
121 | When a value is written into R1, a **BEGIN TRANSACTION** occurs; | |
122 | conceptually, a copy of the program state, including all registers and | |
123 | the location of the currently executing instruction, is made, and pushed | |
124 | onto a stack. | |
125 | ||
126 | Reading from R1 always offers the value 1. | |
127 | ||
128 | `R2` | |
129 | ||
130 | When a value is written into R2, what happens depends on the value. | |
131 | ||
132 | If the value is greater than zero, the current transaction is | |
133 | **COMMIT**ted; conceptually, the topmost program state is popped from | |
134 | the stack and discarded. | |
135 | ||
136 | If the value is equal to zero, the current transaction is | |
137 | **ROLLBACK**ed. Conceptually, the topmost program state is popped; the | |
138 | contents of all registers are reset to what they were in the popped | |
139 | program state; but the location of the currently executing instruction | |
140 | is unchanged. | |
141 | ||
142 | Reading from R2 always offers the value 2. | |
143 | ||
144 | `R3` | |
145 | ||
146 | When a value is written into R3, what happens depends on the value. | |
147 | ||
148 | If the value is greater than zero, the current transaction is **COMMIT | |
149 | AND REPEAT**ed; conceptually, the topmost program state is popped from | |
150 | the stack; the location of the currently executing instruction is reset | |
151 | to what it was in the program state; and a copy of this new program | |
152 | state is pushed once more onto the stack. | |
153 | ||
154 | If the value is equal to zero, the current transaction is **COMMIT**ed | |
155 | (described previously in R2). | |
156 | ||
157 | Reading from R3 always offers the value 3. | |
158 | ||
159 | `R4` | |
160 | ||
161 | When a value is written into R4, that value is added to the value in R8, | |
162 | and the result is written into R8. Reading from R4 always offers the | |
163 | value 4. | |
164 | ||
165 | `R5` | |
166 | ||
167 | When a value is written into R5, that value is subtracted from the value | |
168 | in R8, and the result is written into R8. If the result would be | |
169 | negative, the result will be zero. Reading from R5 always offers the | |
170 | value 5. | |
171 | ||
172 | `R6` | |
173 | ||
174 | When a value is written into R6, the product of that value and the value | |
175 | in R8 is written into R8. Reading from R6 always offers the value 6. | |
176 | ||
177 | `R7` | |
178 | ||
179 | When a value is written into R7, the boolean negation of that value is | |
180 | written into R7: 1 if the value was 0, and 0 otherwise. Reading from R7 | |
181 | always offers the value 7. | |
182 | ||
183 | `R8` | |
184 | ||
185 | Not really memory-mapped, but used as an "accumulator" by the registers | |
186 | R4 through R7. | |
187 | ||
188 | Because the reading and writing of registers can have side-effects, the | |
189 | order of reads and writes during the execution of a single instruction | |
190 | is strictly defined as follows: | |
191 | ||
192 | - The indirect source register, if any, is read (to discover the | |
193 | direct source register.) | |
194 | - The direct source register is read. | |
195 | - The indirect destination register, if any, is read (to discover the | |
196 | direct destination register.) | |
197 | - The direct destination register is written. | |
198 | ||
199 | Computational Class | |
200 | ------------------- | |
201 | ||
202 | I believe ZOWIE is Turing-complete because the transactions can simulate | |
203 | both "IF" and "REPEAT" control structures, which, taken together, can | |
204 | simulate a "WHILE", which is widely known to be sufficient, along with | |
205 | the usual arithmetical operations on an unbounded number of unbounded | |
206 | integer registers, to have a system that is Turing-complete. | |
207 | ||
208 | For example, a crude translation of Brainfuck into ZOWIE might go like: | |
209 | ||
210 | preamble MOV R10, 100 ; the Brainfuck tape index | |
211 | MOV R11, 101 ; the saved-test-value stack pointer | |
212 | ||
213 | > MOV R8, R10 ; inc tape index by two | |
214 | MOV R4, R2 | |
215 | MOV R10, R8 | |
216 | ||
217 | < MOV R8, R10 ; dec tape index by two | |
218 | MOV R5, R2 | |
219 | MOV R10, R8 | |
220 | ||
221 | + MOV R8, R[R10] ; inc value on tape | |
222 | MOV R4, R1 | |
223 | MOV R[R10], R8 | |
224 | ||
225 | - MOV R8, R[R10] ; dec value on tape | |
226 | MOV R5, R1 | |
227 | MOV R[R10], R8 | |
228 | ||
229 | . MOV R0, R[R10] ; output | |
230 | ||
231 | , MOV R[R10], R0 ; input | |
232 | ||
233 | [ MOV R1, R1 ; BEGIN TRANSACTION for "REPEAT" | |
234 | MOV R8, R11 ; bump up the saved-value stack pointer | |
235 | MOV R4, R2 | |
236 | MOV R11, R8 | |
237 | MOV R[R11], R[R10] ; save the value we are testing | |
238 | MOV R1, R1 ; BEGIN TRANSACTION for "IF" | |
239 | ||
240 | ] MOV R2, R[R11] ; COMMIT if non-zero or ROLLBACK otherwise | |
241 | MOV R12, R11 ; retain a copy of the saved-stack pointer | |
242 | MOV R8, R11 ; bump down the saved-stack pointer | |
243 | MOV R5, R2 | |
244 | MOV R11, R8 | |
245 | MOV R3, R[R12] ; COMMIT AND REPEAT if non-zero | |
246 | ||
247 | Three things to note: | |
248 | ||
249 | - In this translation, the simulated Brainfuck tape and the | |
250 | saved-value stack are interleaved. | |
251 | - It is important to save the value being tested *before* the "IF" | |
252 | transaction is begun – otherwise, the value will be rolled back | |
253 | before it can be tested for the **COMMIT AND REPEAT**. | |
254 | - The input-output behaviour of ZOWIE programs produced by this | |
255 | translation does differ from Brainfuck. If the value on the tape is | |
256 | initially zero, a Brainfuck "while" loop will never be executed at | |
257 | all, whereas a ZOWIE transaction *will* be executed, but afterwards | |
258 | undone – everything, that is, except input and output, because being | |
259 | interactions with the outside world, those can't be undone. This | |
260 | limitation does not affect whether ZOWIE is Turing-complete or not | |
261 | (you could just refrain from outputting anything until the very end | |
262 | of the computation), but it does imply that ZOWIE has limitations on | |
263 | how it can communicate. | |
264 | ||
265 | That's all. | |
266 | ||
267 | Happy *«deleted by black helicopters»*! | |
268 | Chris Pressey | |
269 | December 29th, 2009 CE | |
270 | Evanston, IL |
0 | ZOWIE | |
1 | ===== | |
2 | ||
3 | _Try it online_ [@ catseye.tc](https://catseye.tc/installation/ZOWIE) | |
4 | | _Wiki entry_ [@ esolangs.org](https://esolangs.org/wiki/ZOWIE) | |
5 | | _See also:_ [SMITH](https://github.com/catseye/SMITH#readme) | |
6 | ||
7 | - - - - | |
8 | ||
9 | Introduction | |
10 | ------------ | |
11 | ||
12 | ZOWIE is a programming language where all control flow is both | |
13 | *memory-mapped* and *structured*. It is memory-mapped in the sense that | |
14 | changes in flow are triggered by changes made to memory locations, and | |
15 | it is structured in the sense of structured programming – the programmer | |
16 | never deals with `goto`s, offsets, or labels of any kind. | |
17 | ||
18 | History | |
19 | ------- | |
20 | ||
21 | The primary design goal of ZOWIE was to have memory-mapped structured | |
22 | control flow. This goal was inspired by Jeffry Johnston's unsuccessful | |
23 | attempt to reduce the number of instructions in | |
24 | [BitChanger](http://esolangs.org/wiki/BitChanger) (while retaining | |
25 | Turing-completeness) by memory-mapping the loop operation. | |
26 | ||
27 | I initially thought that the difficulty lay in BitChanger's minimalism. | |
28 | To do memory-mapped flow control in general sounded easy – just start a | |
29 | loop when one memory location is written, and end it when some other | |
30 | location is written, right? But no. It's not that simple, as I attempt | |
31 | to explain below. ZOWIE is the last of several, sometimes painful, | |
32 | attempts over the summer of 2009 to realize this design goal (and it is | |
33 | not clear that the techniques used in ZOWIE could be usefully imported | |
34 | back into BitChanger.) The final, workable idea crystallized at about | |
35 | the time September turned into October. | |
36 | ||
37 | The thing with loop structures is that there is usually some way to jump | |
38 | to a known point in the loop (say, the start, or the end) – really, | |
39 | that's what makes them structured. And to jump to a point in a loop, you | |
40 | have to know where that point is. And if you can analyze the loop | |
41 | structure statically, for example if your semantics are directed by | |
42 | syntax as in almost all high-level languages, then it's not difficult to | |
43 | know where that point is. | |
44 | ||
45 | But if that point is defined by when some *memory* location is changed, | |
46 | it is not in general possible to detect it statically (by Rice's | |
47 | Theorem, which is just a generalization of the Halting Problem.) So it | |
48 | is not, in general, possible to know ahead of time where the loop begins | |
49 | or ends. | |
50 | ||
51 | There are a few things to note about this. | |
52 | ||
53 | One is that by "statically" I do not necessarily mean "at compile-time". | |
54 | Many Brainfuck and Mouse interpreters seek out the end of the loop only | |
55 | when they know they must exit it. However, because they are looking | |
56 | through the program text, it is still a kind of static analysis. | |
57 | ||
58 | Another thing is that it would of course be possible to detect some kind | |
59 | of (fixed) command to change the memory location associated with ending | |
60 | a loop – but that would be cheating! (Also, if memory locations can be | |
61 | computed, it is still not fully general, because we cannot look for all | |
62 | possible computations that would result in that memory location.) | |
63 | ||
64 | Lastly, note that we really don't have a problem detecting the start of | |
65 | a loop. As soon as we execute the start of a loop, we know it's a loop, | |
66 | and we know where it is, so we can record that location. The problem is | |
67 | any other point in the loop, like the end. A little reflection will | |
68 | reveal that this means it will be more difficult to do a "WHILE" loop or | |
69 | a structured conditional ("IF-THEN-ENDIF") than a "REPEAT" loop (where | |
70 | the condition is at the end of the loop.) However, it is widely known | |
71 | that "REPEAT" loops alone are not sufficient for a Turing-complete | |
72 | language. We'll see below that ZOWIE manages to create generalized loops | |
73 | through the use of transactions. | |
74 | ||
75 | The secondary design goal of ZOWIE was to strike the perfect balance | |
76 | between _It's a Mad Mad Mad Mad World_ and _The Party_. It is generally | |
77 | considered a morbid failure in that regard, what with not being a madcap | |
78 | 60's movie and all. | |
79 | ||
80 | Syntax and Semantics | |
81 | -------------------- | |
82 | ||
83 | To mitigate retooling costs, ZOWIE borrows much of its archiecture and | |
84 | instruction repertoire from [SMITH](http://catseye.tc/projects/smith/). | |
85 | There are an unlimited number of registers, numbered from 0 upward; each | |
86 | register contains a non-negative integer value of unbounded extent. The | |
87 | contents of a register before it has ever been written is guaranteed to | |
88 | be 0. | |
89 | ||
90 | There are five instruction forms. The first register is the destination | |
91 | register, and is written to; the second register (or immediate value) is | |
92 | read from. As in SMITH, square brackets indicate indirect register | |
93 | access. All instruction forms are case-sensitive; they must be given | |
94 | using capital letters. | |
95 | ||
96 | MOV register, immediate e.g. MOV R8, 141 | |
97 | MOV register, register MOV R8, R9 | |
98 | MOV [register], register MOV R[R8], R9 | |
99 | MOV register, [register] MOV R8, R[R9] | |
100 | MOV [register], [register] MOV R[R8], R[R9] | |
101 | ||
102 | Not only flow control, but in fact all operations in ZOWIE are | |
103 | memory-mapped. The lowest-numbered nine registers have special behaviour | |
104 | when written to or read from: | |
105 | ||
106 | `R0` | |
107 | ||
108 | When a value is written into R0, the Unicode symbol represented by the | |
109 | value is sent to the standard output channel. | |
110 | ||
111 | Reading from R0 waits until a Unicode symbol is available on the | |
112 | standard input, then offers its value as the value of this register. | |
113 | ||
114 | This is similar to the `TTY` pseudo-register of SMITH. | |
115 | ||
116 | *Note: although implementations should make a best effort, the external | |
117 | encoding and representation of Unicode characters is ultimately | |
118 | implementation-defined, especially on systems which are only capable of | |
119 | accurately displaying a subset of the Unicode character set. For | |
120 | example, on a strict ASCII teletype or other device incapable of | |
121 | displaying the DOWNWARDS ARROW (↓) symbol, it would be reasonable to | |
122 | output `↓` or some similar "escape sequence" when executing | |
123 | `MOV R0, 8595`.* | |
124 | ||
125 | `R1` | |
126 | ||
127 | When a value is written into R1, a **BEGIN TRANSACTION** occurs; | |
128 | conceptually, a copy of the program state, including all registers and | |
129 | the location of the currently executing instruction, is made, and pushed | |
130 | onto a stack. | |
131 | ||
132 | Reading from R1 always offers the value 1. | |
133 | ||
134 | `R2` | |
135 | ||
136 | When a value is written into R2, what happens depends on the value. | |
137 | ||
138 | If the value is greater than zero, the current transaction is | |
139 | **COMMIT**ted; conceptually, the topmost program state is popped from | |
140 | the stack and discarded. | |
141 | ||
142 | If the value is equal to zero, the current transaction is | |
143 | **ROLLBACK**ed. Conceptually, the topmost program state is popped; the | |
144 | contents of all registers are reset to what they were in the popped | |
145 | program state; but the location of the currently executing instruction | |
146 | is unchanged. | |
147 | ||
148 | Reading from R2 always offers the value 2. | |
149 | ||
150 | `R3` | |
151 | ||
152 | When a value is written into R3, what happens depends on the value. | |
153 | ||
154 | If the value is greater than zero, the current transaction is **COMMIT | |
155 | AND REPEAT**ed; conceptually, the topmost program state is popped from | |
156 | the stack; the location of the currently executing instruction is reset | |
157 | to what it was in the program state; and a copy of this new program | |
158 | state is pushed once more onto the stack. | |
159 | ||
160 | If the value is equal to zero, the current transaction is **COMMIT**ed | |
161 | (described previously in R2). | |
162 | ||
163 | Reading from R3 always offers the value 3. | |
164 | ||
165 | `R4` | |
166 | ||
167 | When a value is written into R4, that value is added to the value in R8, | |
168 | and the result is written into R8. Reading from R4 always offers the | |
169 | value 4. | |
170 | ||
171 | `R5` | |
172 | ||
173 | When a value is written into R5, that value is subtracted from the value | |
174 | in R8, and the result is written into R8. If the result would be | |
175 | negative, the result will be zero. Reading from R5 always offers the | |
176 | value 5. | |
177 | ||
178 | `R6` | |
179 | ||
180 | When a value is written into R6, the product of that value and the value | |
181 | in R8 is written into R8. Reading from R6 always offers the value 6. | |
182 | ||
183 | `R7` | |
184 | ||
185 | When a value is written into R7, the boolean negation of that value is | |
186 | written into R7: 1 if the value was 0, and 0 otherwise. Reading from R7 | |
187 | always offers the value 7. | |
188 | ||
189 | `R8` | |
190 | ||
191 | Not really memory-mapped, but used as an "accumulator" by the registers | |
192 | R4 through R7. | |
193 | ||
194 | Because the reading and writing of registers can have side-effects, the | |
195 | order of reads and writes during the execution of a single instruction | |
196 | is strictly defined as follows: | |
197 | ||
198 | - The indirect source register, if any, is read (to discover the | |
199 | direct source register.) | |
200 | - The direct source register is read. | |
201 | - The indirect destination register, if any, is read (to discover the | |
202 | direct destination register.) | |
203 | - The direct destination register is written. | |
204 | ||
205 | Computational Class | |
206 | ------------------- | |
207 | ||
208 | I believe ZOWIE is Turing-complete because the transactions can simulate | |
209 | both "IF" and "REPEAT" control structures, which, taken together, can | |
210 | simulate a "WHILE", which is widely known to be sufficient, along with | |
211 | the usual arithmetical operations on an unbounded number of unbounded | |
212 | integer registers, to have a system that is Turing-complete. | |
213 | ||
214 | For example, a crude translation of Brainfuck into ZOWIE might go like: | |
215 | ||
216 | preamble MOV R10, 100 ; the Brainfuck tape index | |
217 | MOV R11, 101 ; the saved-test-value stack pointer | |
218 | ||
219 | > MOV R8, R10 ; inc tape index by two | |
220 | MOV R4, R2 | |
221 | MOV R10, R8 | |
222 | ||
223 | < MOV R8, R10 ; dec tape index by two | |
224 | MOV R5, R2 | |
225 | MOV R10, R8 | |
226 | ||
227 | + MOV R8, R[R10] ; inc value on tape | |
228 | MOV R4, R1 | |
229 | MOV R[R10], R8 | |
230 | ||
231 | - MOV R8, R[R10] ; dec value on tape | |
232 | MOV R5, R1 | |
233 | MOV R[R10], R8 | |
234 | ||
235 | . MOV R0, R[R10] ; output | |
236 | ||
237 | , MOV R[R10], R0 ; input | |
238 | ||
239 | [ MOV R1, R1 ; BEGIN TRANSACTION for "REPEAT" | |
240 | MOV R8, R11 ; bump up the saved-value stack pointer | |
241 | MOV R4, R2 | |
242 | MOV R11, R8 | |
243 | MOV R[R11], R[R10] ; save the value we are testing | |
244 | MOV R1, R1 ; BEGIN TRANSACTION for "IF" | |
245 | ||
246 | ] MOV R2, R[R11] ; COMMIT if non-zero or ROLLBACK otherwise | |
247 | MOV R12, R11 ; retain a copy of the saved-stack pointer | |
248 | MOV R8, R11 ; bump down the saved-stack pointer | |
249 | MOV R5, R2 | |
250 | MOV R11, R8 | |
251 | MOV R3, R[R12] ; COMMIT AND REPEAT if non-zero | |
252 | ||
253 | Three things to note: | |
254 | ||
255 | - In this translation, the simulated Brainfuck tape and the | |
256 | saved-value stack are interleaved. | |
257 | - It is important to save the value being tested *before* the "IF" | |
258 | transaction is begun – otherwise, the value will be rolled back | |
259 | before it can be tested for the **COMMIT AND REPEAT**. | |
260 | - The input-output behaviour of ZOWIE programs produced by this | |
261 | translation does differ from Brainfuck. If the value on the tape is | |
262 | initially zero, a Brainfuck "while" loop will never be executed at | |
263 | all, whereas a ZOWIE transaction *will* be executed, but afterwards | |
264 | undone – everything, that is, except input and output, because being | |
265 | interactions with the outside world, those can't be undone. This | |
266 | limitation does not affect whether ZOWIE is Turing-complete or not | |
267 | (you could just refrain from outputting anything until the very end | |
268 | of the computation), but it does imply that ZOWIE has limitations on | |
269 | how it can communicate. | |
270 | ||
271 | That's all. | |
272 | ||
273 | Happy *«deleted by black helicopters»*! | |
274 | Chris Pressey | |
275 | December 29th, 2009 CE | |
276 | Evanston, IL |
3 | 3 | echo 'RPython not found. Not building. Use CPython or Skulpt instead.' |
4 | 4 | else |
5 | 5 | python `which rpython` src/zowie.py |
6 | mkdir -p bin | |
7 | mv zowie-c bin/ | |
6 | 8 | fi |
3 | 3 | # Chris Pressey, Cat's Eye Technologies, Oct 6 2009 |
4 | 4 | # Adapted to run under Skulpt Oct 10 2013 |
5 | 5 | # Adapted to compile under RPython Sep 2014 |
6 | # Adapted to run under both Python 2 and 3 Jun 22 2021 | |
6 | 7 | # This source code is in the public domain. |
7 | 8 | # |
8 | 9 | |
21 | 22 | return x |
22 | 23 | |
23 | 24 | |
25 | def unichr_compat(code): | |
26 | try: | |
27 | return unichr(code) | |
28 | except NameError: | |
29 | return chr(code) | |
30 | ||
31 | ||
24 | 32 | def output(code): |
25 | 33 | try: |
26 | sys.stdout.write(unichr(code)) | |
34 | sys.stdout.write(unichr_compat(code)) | |
27 | 35 | except UnicodeEncodeError: |
28 | 36 | sys.stdout.write("&#%d;" % code) |
29 | 37 | |
42 | 50 | pass |
43 | 51 | |
44 | 52 | def skulpt_output(code): |
45 | print "&#%d;" % code | |
53 | print("&#%d;" % code) | |
46 | 54 | |
47 | 55 | output = skulpt_output |
48 | 56 | |
390 | 398 | if not s: |
391 | 399 | return 0 |
392 | 400 | return ord(s[0]) |
393 | ||
394 | ||
401 | ||
402 | ||
395 | 403 | def rpython_output(code): |
396 | os.write(0, unichr(code).encode('utf-8')) | |
397 | ||
398 | ||
404 | if code <= 127: | |
405 | os.write(0, chr(code)) | |
406 | else: | |
407 | os.write(0, "&#%d;" % code) | |
408 | ||
409 | ||
399 | 410 | def rpython_load(filename): |
400 | fd = os.open(filename, os.O_RDONLY, 0644) | |
411 | fd = os.open(filename, os.O_RDONLY, 0o644) | |
401 | 412 | text = '' |
402 | 413 | chunk = os.read(fd, 1024) |
403 | 414 | text += chunk |
406 | 417 | text += chunk |
407 | 418 | os.close(fd) |
408 | 419 | return text |
409 | ||
410 | ||
420 | ||
421 | ||
411 | 422 | def rpython_main(argv): |
412 | 423 | p = Processor() |
413 | 424 | program = rpython_load(argv[1]) |
0 | 0 | #!/bin/sh |
1 | 1 | |
2 | FIXTURES='' | |
3 | if [ ! `which rpython`X = X ]; then | |
4 | FIXTURES="$FIXTURES tests/rpython-fixture.markdown" | |
5 | if [ ! -e ./zowie-c ]; then | |
6 | ./build.sh || exit $? | |
7 | fi | |
2 | APPLIANCES="tests/appliances/zowie.py2.md tests/appliances/zowie.py3.md" | |
3 | if [ -x bin/zowie-c ]; then | |
4 | APPLIANCES="$APPLIANCES tests/appliances/zowie-c.md" | |
8 | 5 | fi |
9 | 6 | |
10 | falderal --substring-error $FIXTURES tests/ZOWIE.markdown | |
7 | falderal $APPLIANCES tests/ZOWIE.md |
0 | Tests for ZOWIE | |
1 | =============== | |
2 | ||
3 | This non-exhaustive test suite is written in format of Falderal 0.9. | |
4 | ||
5 | -> Tests for functionality "Interpret ZOWIE Program" | |
6 | ||
7 | -> Functionality "Interpret ZOWIE Program" is implemented by | |
8 | -> shell command | |
9 | -> "python src/zowie.py %(test-body-file)" | |
10 | ||
11 | Display the Roman alphabet in reverse. | |
12 | ||
13 | | MOV R10, 90 ; initially it's "Z" | |
14 | | MOV R1, R1 ; BEGIN TRANSACTION for "REPEAT" | |
15 | | MOV R0, R10 ; output character | |
16 | | MOV R8, R10 ; decrement character | |
17 | | MOV R5, 1 | |
18 | | MOV R10, R8 | |
19 | | MOV R8, R10 ; test if character is above "@" | |
20 | | MOV R5, 64 | |
21 | | MOV R3, R8 ; COMMIT AND REPEAT if non-zero | |
22 | = ZYXWVUTSRQPONMLKJIHGFEDCBA | |
23 | ||
24 | Compute a factorial. | |
25 | ||
26 | | MOV R11, 5 ; let's find 5! | |
27 | | MOV R10, 1 ; accumulator | |
28 | | | |
29 | | MOV R8, R11 ; increase multiplicand | |
30 | | MOV R4, 1 | |
31 | | MOV R11, R8 | |
32 | | | |
33 | | MOV R1, R1 ; BEGIN TRANSACTION for "REPEAT" | |
34 | | | |
35 | | MOV R8, R11 ; decrease multiplicand | |
36 | | MOV R5, 1 | |
37 | | MOV R11, R8 | |
38 | | | |
39 | | MOV R1, R1 ; BEGIN TRANSACTION for "IF" | |
40 | | | |
41 | | MOV R8, R10 ; accumulator | |
42 | | MOV R6, R11 ; multiplied | |
43 | | MOV R10, R8 | |
44 | | | |
45 | | MOV R2, R11 ; COMMIT if multiplicand above zero, or ROLLBACK otherwise | |
46 | | MOV R3, R11 ; COMMIT AND REPEAT if multiplicand above zero | |
47 | | | |
48 | | MOV R0, R10 ; output accumulator (as single Unicode character) | |
49 | = x | |
50 | ||
51 | The only command in the language is `MOV` and it must be in uppercase. | |
52 | ||
53 | | cmp R11, 5 | |
54 | ? | |
55 | ||
56 | | mov R11, 5 | |
57 | ? | |
58 | ||
59 | Register names must be uppercase, too. | |
60 | ||
61 | | MOV r11, 5 | |
62 | ? | |
63 | ||
64 | The destination cannot be an immediate. | |
65 | ||
66 | | MOV 5, R11 | |
67 | ? | |
68 | ||
69 | Retrieve indirect reference. | |
70 | ||
71 | | MOV R11, 65 | |
72 | | MOV R12, 11 | |
73 | | MOV R0, R[R12] | |
74 | = A | |
75 | ||
76 | Store indirect reference. | |
77 | ||
78 | | MOV R12, 11 | |
79 | | MOV R[R12], 65 | |
80 | | MOV R0, R11 | |
81 | = A |
0 | Tests for ZOWIE | |
1 | =============== | |
2 | ||
3 | This non-exhaustive test suite is written in format of Falderal 0.9. | |
4 | ||
5 | -> Tests for functionality "Interpret ZOWIE Program" | |
6 | ||
7 | Display the Roman alphabet in reverse. | |
8 | ||
9 | | MOV R10, 90 ; initially it's "Z" | |
10 | | MOV R1, R1 ; BEGIN TRANSACTION for "REPEAT" | |
11 | | MOV R0, R10 ; output character | |
12 | | MOV R8, R10 ; decrement character | |
13 | | MOV R5, 1 | |
14 | | MOV R10, R8 | |
15 | | MOV R8, R10 ; test if character is above "@" | |
16 | | MOV R5, 64 | |
17 | | MOV R3, R8 ; COMMIT AND REPEAT if non-zero | |
18 | = ZYXWVUTSRQPONMLKJIHGFEDCBA | |
19 | ||
20 | Compute a factorial. | |
21 | ||
22 | | MOV R11, 5 ; let's find 5! | |
23 | | MOV R10, 1 ; accumulator | |
24 | | | |
25 | | MOV R8, R11 ; increase multiplicand | |
26 | | MOV R4, 1 | |
27 | | MOV R11, R8 | |
28 | | | |
29 | | MOV R1, R1 ; BEGIN TRANSACTION for "REPEAT" | |
30 | | | |
31 | | MOV R8, R11 ; decrease multiplicand | |
32 | | MOV R5, 1 | |
33 | | MOV R11, R8 | |
34 | | | |
35 | | MOV R1, R1 ; BEGIN TRANSACTION for "IF" | |
36 | | | |
37 | | MOV R8, R10 ; accumulator | |
38 | | MOV R6, R11 ; multiplied | |
39 | | MOV R10, R8 | |
40 | | | |
41 | | MOV R2, R11 ; COMMIT if multiplicand above zero, or ROLLBACK otherwise | |
42 | | MOV R3, R11 ; COMMIT AND REPEAT if multiplicand above zero | |
43 | | | |
44 | | MOV R0, R10 ; output accumulator (as single Unicode character) | |
45 | = x | |
46 | ||
47 | The only command in the language is `MOV` and it must be in uppercase. | |
48 | ||
49 | | cmp R11, 5 | |
50 | ? | |
51 | ||
52 | | mov R11, 5 | |
53 | ? | |
54 | ||
55 | Register names must be uppercase, too. | |
56 | ||
57 | | MOV r11, 5 | |
58 | ? | |
59 | ||
60 | The destination cannot be an immediate. | |
61 | ||
62 | | MOV 5, R11 | |
63 | ? | |
64 | ||
65 | Retrieve indirect reference. | |
66 | ||
67 | | MOV R11, 65 | |
68 | | MOV R12, 11 | |
69 | | MOV R0, R[R12] | |
70 | = A | |
71 | ||
72 | Store indirect reference. | |
73 | ||
74 | | MOV R12, 11 | |
75 | | MOV R[R12], 65 | |
76 | | MOV R0, R11 | |
77 | = A |
0 | This Falderal appliance tests the compiled-with-RPython version of the ZOWIE | |
1 | reference interpreter. | |
2 | ||
3 | This requires `fa-under-pty`, which is a part of Falderal since version 0.10. | |
4 | ||
5 | It requires `fa-under-pty` because, for whatever reason, executables produced | |
6 | by RPython from PyPy version 7.3.5 do not handle having their stdout redirected | |
7 | very well. Specifically, they dump core. It is for this very reason that | |
8 | `fa-under-pty` was written, in fact. | |
9 | ||
10 | -> Functionality "Interpret ZOWIE Program" is implemented by | |
11 | -> shell command | |
12 | -> "fa-under-pty ./bin/zowie-c %(test-body-file)" | |
13 |
0 | -> Functionality "Interpret ZOWIE Program" is implemented by | |
1 | -> shell command | |
2 | -> "python2 src/zowie.py %(test-body-file)" |
0 | -> Functionality "Interpret ZOWIE Program" is implemented by | |
1 | -> shell command | |
2 | -> "python3 src/zowie.py %(test-body-file)" |
0 | This Falderal fixture tests the compiled-with-RPython version of the ZOWIE | |
1 | reference interpreter. | |
2 | ||
3 | This requires `fa-under-pty`, which is a part of Falderal version 0.10. | |
4 | ||
5 | It requires `fa-under-pty` because, for whatever reason, executables produced | |
6 | by RPython from PyPy version 2.3.1 do not handle having their stdout redirected | |
7 | very well. Specifically, they dump core. It is for this very reason that | |
8 | `fa-under-pty` was written, in fact. | |
9 | ||
10 | -> Functionality "Interpret ZOWIE Program" is implemented by | |
11 | -> shell command | |
12 | -> "fa-under-pty ./zowie-c %(test-body-file)" | |
13 |