git @ Cat's Eye Technologies ZOWIE / 86c1100
Rename Markdown file extension to '.md'. Chris Pressey 1 year, 6 days ago
4 changed file(s) with 315 addition(s) and 315 deletion(s). Raw diff Collapse all Expand all
+0
-44
HISTORY.markdown less more
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.
+0
-271
README.markdown less more
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 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 `&#8595;` 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