git @ Cat's Eye Technologies ZOWIE / 4e37608
Convert CRLF EOLs to LFs. catseye 9 years ago
1 changed file(s) with 270 addition(s) and 270 deletion(s). Raw diff Collapse all Expand all
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.
88
89 MOV register, immediate e.g. MOV R8, 141
90 MOV register, register MOV R8, R9
91 MOV [register], register MOV R[R8], R9
92 MOV register, [register] MOV R8, R[R9]
93 MOV [register], [register] MOV R[R8], R[R9]
94
95 Not only flow control, but in fact all operations in ZOWIE are
96 memory-mapped. The lowest-numbered nine registers have special behaviour
97 when written to or read from:
98
99 `R0`
100
101 When a value is written into R0, the Unicode symbol represented by the
102 value is sent to the standard output channel.
103
104 Reading from R0 waits until a Unicode symbol is available on the
105 standard input, then offers its value as the value of this register.
106
107 This is similar to the `TTY` pseudo-register of SMITH.
108
109 *Note: although implementations should make a best effort, the external
110 encoding and representation of Unicode characters is ultimately
111 implementation-defined, especially on systems which are only capable of
112 accurately displaying a subset of the Unicode character set. For
113 example, on a strict ASCII teletype or other device incapable of
114 displaying the DOWNWARDS ARROW (↓) symbol, it would be reasonable to
115 output `↓` or some similar "escape sequence" when executing
116 `MOV R0, 8595`.*
117
118 `R1`
119
120 When a value is written into R1, a **BEGIN TRANSACTION** occurs;
121 conceptually, a copy of the program state, including all registers and
122 the location of the currently executing instruction, is made, and pushed
123 onto a stack.
124
125 Reading from R1 always offers the value 1.
126
127 `R2`
128
129 When a value is written into R2, what happens depends on the value.
130
131 If the value is greater than zero, the current transaction is
132 **COMMIT**ted; conceptually, the topmost program state is popped from
133 the stack and discarded.
134
135 If the value is equal to zero, the current transaction is
136 **ROLLBACK**ed. Conceptually, the topmost program state is popped; the
137 contents of all registers are reset to what they were in the popped
138 program state; but the location of the currently executing instruction
139 is unchanged.
140
141 Reading from R2 always offers the value 2.
142
143 `R3`
144
145 When a value is written into R3, what happens depends on the value.
146
147 If the value is greater than zero, the current transaction is **COMMIT
148 AND REPEAT**ed; conceptually, the topmost program state is popped from
149 the stack; the location of the currently executing instruction is reset
150 to what it was in the program state; and a copy of this new program
151 state is pushed once more onto the stack.
152
153 If the value is equal to zero, the current transaction is **COMMIT**ed
154 (described previously in R2).
155
156 Reading from R3 always offers the value 3.
157
158 `R4`
159
160 When a value is written into R4, that value is added to the value in R8,
161 and the result is written into R8. Reading from R4 always offers the
162 value 4.
163
164 `R5`
165
166 When a value is written into R5, that value is subtracted from the value
167 in R8, and the result is written into R8. If the result would be
168 negative, the result will be zero. Reading from R5 always offers the
169 value 5.
170
171 `R6`
172
173 When a value is written into R6, the product of that value and the value
174 in R8 is written into R8. Reading from R6 always offers the value 6.
175
176 `R7`
177
178 When a value is written into R7, the boolean negation of that value is
179 written into R7: 1 if the value was 0, and 0 otherwise. Reading from R7
180 always offers the value 7.
181
182 `R8`
183
184 Not really memory-mapped, but used as an "accumulator" by the registers
185 R4 through R7.
186
187 Because the reading and writing of registers can have side-effects, the
188 order of reads and writes during the execution of a single instruction
189 is strictly defined as follows:
190
191 - The indirect source register, if any, is read (to discover the
192 direct source register.)
193 - The direct source register is read.
194 - The indirect destination register, if any, is read (to discover the
195 direct destination register.)
196 - The direct destination register is written.
197
198 Computational Class
199 -------------------
200
201 I believe ZOWIE is Turing-complete because the transactions can simulate
202 both "IF" and "REPEAT" control structures, which, taken together, can
203 simulate a "WHILE", which is widely known to be sufficient, along with
204 the usual arithmetical operations on an unbounded number of unbounded
205 integer registers, to have a system that is Turing-complete.
206
207 For example, a crude translation of Brainfuck into ZOWIE might go like:
208
209 preamble MOV R10, 100 ; the Brainfuck tape index
210 MOV R11, 101 ; the saved-test-value stack pointer
211
212 > MOV R8, R10 ; inc tape index by two
213 MOV R4, R2
214 MOV R10, R8
215
216 < MOV R8, R10 ; dec tape index by two
217 MOV R5, R2
218 MOV R10, R8
219
220 + MOV R8, R[R10] ; inc value on tape
221 MOV R4, R1
222 MOV R[R10], R8
223
224 - MOV R8, R[R10] ; dec value on tape
225 MOV R5, R1
226 MOV R[R10], R8
227
228 . MOV R0, R[R10] ; output
229
230 , MOV R[R10], R0 ; input
231
232 [ MOV R1, R1 ; BEGIN TRANSACTION for "REPEAT"
233 MOV R8, R11 ; bump up the saved-value stack pointer
234 MOV R4, R2
235 MOV R11, R8
236 MOV R[R11], R[R10] ; save the value we are testing
237 MOV R1, R1 ; BEGIN TRANSACTION for "IF"
238
239 ] MOV R2, R[R11] ; COMMIT if non-zero or ROLLBACK otherwise
240 MOV R12, R11 ; retain a copy of the saved-stack pointer
241 MOV R8, R11 ; bump down the saved-stack pointer
242 MOV R5, R2
243 MOV R11, R8
244 MOV R3, R[R12] ; COMMIT AND REPEAT if non-zero
245
246 Three things to note:
247
248 - In this translation, the simulated Brainfuck tape and the
249 saved-value stack are interleaved.
250 - It is important to save the value being tested *before* the "IF"
251 transaction is begun – otherwise, the value will be rolled back
252 before it can be tested for the **COMMIT AND REPEAT**.
253 - The input-output behaviour of ZOWIE programs produced by this
254 translation does differ from Brainfuck. If the value on the tape is
255 initially zero, a Brainfuck "while" loop will never be executed at
256 all, whereas a ZOWIE transaction *will* be executed, but afterwards
257 undone – everything, that is, except input and output, because being
258 interactions with the outside world, those can't be undone. This
259 limitation does not affect whether ZOWIE is Turing-complete or not
260 (you could just refrain from outputting anything until the very end
261 of the computation), but it does imply that ZOWIE has limitations on
262 how it can communicate.
263
264 That's all.
265
266 Happy *«deleted by black helicopters»*!
267 Chris Pressey
268 December 29^th^, 2009 CE
269 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.
88
89 MOV register, immediate e.g. MOV R8, 141
90 MOV register, register MOV R8, R9
91 MOV [register], register MOV R[R8], R9
92 MOV register, [register] MOV R8, R[R9]
93 MOV [register], [register] MOV R[R8], R[R9]
94
95 Not only flow control, but in fact all operations in ZOWIE are
96 memory-mapped. The lowest-numbered nine registers have special behaviour
97 when written to or read from:
98
99 `R0`
100
101 When a value is written into R0, the Unicode symbol represented by the
102 value is sent to the standard output channel.
103
104 Reading from R0 waits until a Unicode symbol is available on the
105 standard input, then offers its value as the value of this register.
106
107 This is similar to the `TTY` pseudo-register of SMITH.
108
109 *Note: although implementations should make a best effort, the external
110 encoding and representation of Unicode characters is ultimately
111 implementation-defined, especially on systems which are only capable of
112 accurately displaying a subset of the Unicode character set. For
113 example, on a strict ASCII teletype or other device incapable of
114 displaying the DOWNWARDS ARROW (↓) symbol, it would be reasonable to
115 output `&#8595;` or some similar "escape sequence" when executing
116 `MOV R0, 8595`.*
117
118 `R1`
119
120 When a value is written into R1, a **BEGIN TRANSACTION** occurs;
121 conceptually, a copy of the program state, including all registers and
122 the location of the currently executing instruction, is made, and pushed
123 onto a stack.
124
125 Reading from R1 always offers the value 1.
126
127 `R2`
128
129 When a value is written into R2, what happens depends on the value.
130
131 If the value is greater than zero, the current transaction is
132 **COMMIT**ted; conceptually, the topmost program state is popped from
133 the stack and discarded.
134
135 If the value is equal to zero, the current transaction is
136 **ROLLBACK**ed. Conceptually, the topmost program state is popped; the
137 contents of all registers are reset to what they were in the popped
138 program state; but the location of the currently executing instruction
139 is unchanged.
140
141 Reading from R2 always offers the value 2.
142
143 `R3`
144
145 When a value is written into R3, what happens depends on the value.
146
147 If the value is greater than zero, the current transaction is **COMMIT
148 AND REPEAT**ed; conceptually, the topmost program state is popped from
149 the stack; the location of the currently executing instruction is reset
150 to what it was in the program state; and a copy of this new program
151 state is pushed once more onto the stack.
152
153 If the value is equal to zero, the current transaction is **COMMIT**ed
154 (described previously in R2).
155
156 Reading from R3 always offers the value 3.
157
158 `R4`
159
160 When a value is written into R4, that value is added to the value in R8,
161 and the result is written into R8. Reading from R4 always offers the
162 value 4.
163
164 `R5`
165
166 When a value is written into R5, that value is subtracted from the value
167 in R8, and the result is written into R8. If the result would be
168 negative, the result will be zero. Reading from R5 always offers the
169 value 5.
170
171 `R6`
172
173 When a value is written into R6, the product of that value and the value
174 in R8 is written into R8. Reading from R6 always offers the value 6.
175
176 `R7`
177
178 When a value is written into R7, the boolean negation of that value is
179 written into R7: 1 if the value was 0, and 0 otherwise. Reading from R7
180 always offers the value 7.
181
182 `R8`
183
184 Not really memory-mapped, but used as an "accumulator" by the registers
185 R4 through R7.
186
187 Because the reading and writing of registers can have side-effects, the
188 order of reads and writes during the execution of a single instruction
189 is strictly defined as follows:
190
191 - The indirect source register, if any, is read (to discover the
192 direct source register.)
193 - The direct source register is read.
194 - The indirect destination register, if any, is read (to discover the
195 direct destination register.)
196 - The direct destination register is written.
197
198 Computational Class
199 -------------------
200
201 I believe ZOWIE is Turing-complete because the transactions can simulate
202 both "IF" and "REPEAT" control structures, which, taken together, can
203 simulate a "WHILE", which is widely known to be sufficient, along with
204 the usual arithmetical operations on an unbounded number of unbounded
205 integer registers, to have a system that is Turing-complete.
206
207 For example, a crude translation of Brainfuck into ZOWIE might go like:
208
209 preamble MOV R10, 100 ; the Brainfuck tape index
210 MOV R11, 101 ; the saved-test-value stack pointer
211
212 > MOV R8, R10 ; inc tape index by two
213 MOV R4, R2
214 MOV R10, R8
215
216 < MOV R8, R10 ; dec tape index by two
217 MOV R5, R2
218 MOV R10, R8
219
220 + MOV R8, R[R10] ; inc value on tape
221 MOV R4, R1
222 MOV R[R10], R8
223
224 - MOV R8, R[R10] ; dec value on tape
225 MOV R5, R1
226 MOV R[R10], R8
227
228 . MOV R0, R[R10] ; output
229
230 , MOV R[R10], R0 ; input
231
232 [ MOV R1, R1 ; BEGIN TRANSACTION for "REPEAT"
233 MOV R8, R11 ; bump up the saved-value stack pointer
234 MOV R4, R2
235 MOV R11, R8
236 MOV R[R11], R[R10] ; save the value we are testing
237 MOV R1, R1 ; BEGIN TRANSACTION for "IF"
238
239 ] MOV R2, R[R11] ; COMMIT if non-zero or ROLLBACK otherwise
240 MOV R12, R11 ; retain a copy of the saved-stack pointer
241 MOV R8, R11 ; bump down the saved-stack pointer
242 MOV R5, R2
243 MOV R11, R8
244 MOV R3, R[R12] ; COMMIT AND REPEAT if non-zero
245
246 Three things to note:
247
248 - In this translation, the simulated Brainfuck tape and the
249 saved-value stack are interleaved.
250 - It is important to save the value being tested *before* the "IF"
251 transaction is begun – otherwise, the value will be rolled back
252 before it can be tested for the **COMMIT AND REPEAT**.
253 - The input-output behaviour of ZOWIE programs produced by this
254 translation does differ from Brainfuck. If the value on the tape is
255 initially zero, a Brainfuck "while" loop will never be executed at
256 all, whereas a ZOWIE transaction *will* be executed, but afterwards
257 undone – everything, that is, except input and output, because being
258 interactions with the outside world, those can't be undone. This
259 limitation does not affect whether ZOWIE is Turing-complete or not
260 (you could just refrain from outputting anything until the very end
261 of the computation), but it does imply that ZOWIE has limitations on
262 how it can communicate.
263
264 That's all.
265
266 Happy *«deleted by black helicopters»*!
267 Chris Pressey
268 December 29^th^, 2009 CE
269 Evanston, IL