The evaluator doesn't add much and keeps falling behind; remove it.
Chris Pressey
4 years ago
7 | 7 | * Initialized `byte table` values need not have all 256 bytes initialized. |
8 | 8 | * Constraints for `vector` type come immediately after the type, not the variable. |
9 | 9 | * `vector table` storage, and ability to copy vectors in and out of same. |
10 | * Removed the evaluator. The reference implementation only analyzes and compiles. | |
10 | 11 | * Fixed bug where index register wasn't required to be initialized before table access. |
11 | 12 | |
12 | 13 | 0.10 |
20 | 20 | * explicit tail calls |
21 | 21 | * indirect subroutine calls |
22 | 22 | |
23 | The reference implementation can execute, analyze, and compile SixtyPical | |
24 | programs to 6502 machine code. | |
23 | The reference implementation can analyze and compile SixtyPical programs to | |
24 | 6502 machine code. | |
25 | 25 | |
26 | 26 | Documentation |
27 | 27 | ------------- |
43 | 43 | Finish the little demo "game" where you can move a block around the screen with |
44 | 44 | the joystick (i.e. bring it up to par with the original demo game that was written |
45 | 45 | for SixtyPical) |
46 | ||
47 | ### `vector table` type | |
48 | 46 | |
49 | 47 | ### `low` and `high` address operators |
50 | 48 |
1 | 1 | |
2 | 2 | """Usage: sixtypical [OPTIONS] FILES |
3 | 3 | |
4 | Analyzes and/or executes and/or compiles a Sixtypical program. | |
4 | Analyzes and compiles a Sixtypical program. | |
5 | 5 | """ |
6 | 6 | |
7 | 7 | from os.path import realpath, dirname, join |
18 | 18 | import traceback |
19 | 19 | |
20 | 20 | from sixtypical.parser import Parser |
21 | from sixtypical.evaluator import Evaluator | |
22 | 21 | from sixtypical.analyzer import Analyzer |
23 | 22 | from sixtypical.emitter import Emitter, Byte, Word |
24 | 23 | from sixtypical.compiler import Compiler |
40 | 39 | action="store_true", |
41 | 40 | help="") |
42 | 41 | optparser.add_option("--traceback", |
43 | action="store_true", | |
44 | help="") | |
45 | optparser.add_option("--execute", | |
46 | 42 | action="store_true", |
47 | 43 | help="") |
48 | 44 | |
87 | 83 | pprint(emitter.accum) |
88 | 84 | else: |
89 | 85 | emitter.serialize(fh) |
90 | ||
91 | if options.execute: | |
92 | context = Evaluator().eval_program(program) | |
93 | print str(context) |
1 | 1 | ========== |
2 | 2 | |
3 | 3 | This document describes the SixtyPical programming language version 0.11, |
4 | both its execution aspect and its static analysis aspect (even though | |
5 | these are, technically speaking, separate concepts.) | |
4 | both its static semantics (the capabilities and limits of the static | |
5 | analyses it defines) and its runtime semantics (with reference to the | |
6 | semantics of 6502 machine code.) | |
6 | 7 | |
7 | 8 | This document is nominally normative, but the tests in the `tests` directory |
8 | 9 | are even more normative. |
0 | # encoding: UTF-8 | |
1 | ||
2 | from sixtypical.ast import Program, Routine, Block, Instr | |
3 | from sixtypical.model import ( | |
4 | ConstantRef, LocationRef, PartRef, IndirectRef, | |
5 | REG_A, REG_X, REG_Y, FLAG_Z, FLAG_N, FLAG_V, FLAG_C | |
6 | ) | |
7 | ||
8 | ||
9 | class Context(object): | |
10 | def __init__(self): | |
11 | self._store = {} | |
12 | ||
13 | def __str__(self): | |
14 | return '\n'.join("%s: %s" % (name, value) | |
15 | for (name, value) in sorted(self._store.iteritems()) | |
16 | if not isinstance(value, Routine)) | |
17 | ||
18 | def get(self, ref): | |
19 | if isinstance(ref, ConstantRef): | |
20 | return ref.value | |
21 | elif isinstance(ref, LocationRef): | |
22 | return self._store[ref.name] | |
23 | elif isinstance(ref, PartRef): | |
24 | value = self.get(ref.ref) | |
25 | if ref.height == 0: | |
26 | return value & 255 | |
27 | elif ref.height == 1: | |
28 | return (value >> 8) & 255 | |
29 | else: | |
30 | raise NotImplementedError | |
31 | else: | |
32 | raise ValueError(ref) | |
33 | ||
34 | def set(self, ref, value): | |
35 | if isinstance(ref, PartRef): | |
36 | old = self.get(ref.ref) | |
37 | if ref.height == 0: | |
38 | value = (old & (255 << 8)) | value | |
39 | elif ref.height == 1: | |
40 | value = (value << 8) | (old & 255) | |
41 | else: | |
42 | raise NotImplementedError | |
43 | ref = ref.ref | |
44 | assert isinstance(ref, LocationRef) | |
45 | self._store[ref.name] = value | |
46 | ||
47 | ||
48 | class Evaluator(object): | |
49 | ||
50 | def eval_program(self, program): | |
51 | assert isinstance(program, Program) | |
52 | context = Context() | |
53 | for ref in (REG_A, REG_X, REG_Y, FLAG_Z, FLAG_N, FLAG_V, FLAG_C): | |
54 | context.set(ref, 0) | |
55 | main = None | |
56 | ||
57 | for defn in program.defns: | |
58 | if defn.initial is not None: | |
59 | context.set(defn.location, defn.initial) | |
60 | ||
61 | for routine in program.routines: | |
62 | context.set(routine.location, routine) | |
63 | if routine.name == 'main': | |
64 | main = routine | |
65 | ||
66 | self.eval_routine(main, context) | |
67 | return context | |
68 | ||
69 | def eval_routine(self, routine, context): | |
70 | assert isinstance(routine, Routine) | |
71 | self.next_routine = routine | |
72 | while self.next_routine: | |
73 | routine = self.next_routine | |
74 | self.next_routine = None | |
75 | self.eval_block(routine.block, context) | |
76 | ||
77 | def eval_block(self, block, context): | |
78 | assert isinstance(block, Block) | |
79 | for i in block.instrs: | |
80 | self.eval_instr(i, context) | |
81 | if self.next_routine: | |
82 | break | |
83 | ||
84 | def eval_instr(self, instr, context): | |
85 | assert isinstance(instr, Instr) | |
86 | opcode = instr.opcode | |
87 | dest = instr.dest | |
88 | src = instr.src | |
89 | ||
90 | if opcode == 'ld': | |
91 | result = context.get(src) | |
92 | context.set(FLAG_Z, 1 if result == 0 else 0) | |
93 | context.set(FLAG_N, 1 if result & 128 else 0) | |
94 | context.set(dest, result) | |
95 | elif opcode == 'st': | |
96 | context.set(dest, context.get(src)) | |
97 | elif opcode == 'add': | |
98 | carry = context.get(FLAG_C) | |
99 | val = context.get(src) | |
100 | now = context.get(dest) | |
101 | result = now + val + carry | |
102 | if result > 255: | |
103 | result &= 255 | |
104 | context.set(FLAG_C, 1) | |
105 | else: | |
106 | context.set(FLAG_C, 0) | |
107 | context.set(FLAG_Z, 1 if result == 0 else 0) | |
108 | context.set(FLAG_N, 1 if result & 128 else 0) | |
109 | context.set(dest, result) | |
110 | elif opcode == 'sub': | |
111 | carry = context.get(FLAG_C) | |
112 | val = context.get(src) | |
113 | now = context.get(dest) | |
114 | result = now - val - carry | |
115 | if result < 0: | |
116 | result &= 255 | |
117 | context.set(FLAG_C, 1) | |
118 | else: | |
119 | context.set(FLAG_C, 0) | |
120 | context.set(FLAG_Z, 1 if result == 0 else 0) | |
121 | context.set(FLAG_N, 1 if result & 128 else 0) | |
122 | context.set(dest, result) | |
123 | elif opcode == 'inc': | |
124 | val = context.get(dest) | |
125 | result = (val + 1) & 255 | |
126 | context.set(FLAG_Z, 1 if result == 0 else 0) | |
127 | context.set(FLAG_N, 1 if result & 128 else 0) | |
128 | context.set(dest, result) | |
129 | elif opcode == 'dec': | |
130 | val = context.get(dest) | |
131 | result = (val - 1) & 255 | |
132 | context.set(FLAG_Z, 1 if result == 0 else 0) | |
133 | context.set(FLAG_N, 1 if result & 128 else 0) | |
134 | context.set(dest, result) | |
135 | elif opcode == 'cmp': | |
136 | val = context.get(src) | |
137 | now = context.get(dest) | |
138 | result = now - val | |
139 | context.set(FLAG_Z, 1 if result == 0 else 0) | |
140 | context.set(FLAG_N, 1 if result & 128 else 0) | |
141 | if result < 0: | |
142 | result &= 255 | |
143 | context.set(FLAG_C, 1) | |
144 | else: | |
145 | context.set(FLAG_C, 0) | |
146 | elif opcode == 'and': | |
147 | result = context.get(dest) & context.get(src) | |
148 | context.set(FLAG_Z, 1 if result == 0 else 0) | |
149 | context.set(FLAG_N, 1 if result & 128 else 0) | |
150 | context.set(dest, result) | |
151 | elif opcode == 'or': | |
152 | result = context.get(dest) | context.get(src) | |
153 | context.set(FLAG_Z, 1 if result == 0 else 0) | |
154 | context.set(FLAG_N, 1 if result & 128 else 0) | |
155 | context.set(dest, result) | |
156 | elif opcode == 'xor': | |
157 | result = context.get(dest) ^ context.get(src) | |
158 | context.set(FLAG_Z, 1 if result == 0 else 0) | |
159 | context.set(FLAG_N, 1 if result & 128 else 0) | |
160 | context.set(dest, result) | |
161 | elif opcode == 'shl': | |
162 | val = context.get(dest) | |
163 | carry = context.get(FLAG_C) | |
164 | context.set(FLAG_C, 1 if val & 128 else 0) | |
165 | result = ((val << 1) + carry) & 255 | |
166 | context.set(FLAG_Z, 1 if result == 0 else 0) | |
167 | context.set(FLAG_N, 1 if result & 128 else 0) | |
168 | context.set(dest, result) | |
169 | elif opcode == 'shr': | |
170 | val = context.get(dest) | |
171 | carry = context.get(FLAG_C) | |
172 | context.set(FLAG_C, 1 if val & 1 else 0) | |
173 | result = (val >> 1) + (carry * 128) | |
174 | context.set(FLAG_Z, 1 if result == 0 else 0) | |
175 | context.set(FLAG_N, 1 if result & 128 else 0) | |
176 | context.set(dest, result) | |
177 | elif opcode == 'call': | |
178 | self.eval_routine(context.get(instr.location), context) | |
179 | elif opcode == 'goto': | |
180 | self.next_routine = context.get(instr.location) | |
181 | elif opcode == 'if': | |
182 | val = context.get(src) | |
183 | test = (val != 0) if not instr.inverted else (val == 0) | |
184 | if test: | |
185 | self.eval_block(instr.block1, context) | |
186 | elif instr.block2: | |
187 | self.eval_block(instr.block2, context) | |
188 | elif opcode == 'repeat': | |
189 | self.eval_block(instr.block, context) | |
190 | while context.get(src) == 0: | |
191 | self.eval_block(instr.block, context) | |
192 | elif opcode == 'copy': | |
193 | if isinstance(src, IndirectRef): | |
194 | raise NotImplementedError("this doesn't actually work") | |
195 | src = src.ref | |
196 | if isinstance(dest, IndirectRef): | |
197 | raise NotImplementedError("this doesn't actually work") | |
198 | dest = dest.ref | |
199 | context.set(dest, context.get(src)) | |
200 | # these are trashed; so could be anything really | |
201 | context.set(REG_A, 0) | |
202 | context.set(FLAG_Z, 0) | |
203 | context.set(FLAG_N, 0) | |
204 | elif opcode == 'with-sei': | |
205 | self.eval_block(instr.block) | |
206 | else: | |
207 | raise NotImplementedError |
1 | 1 | |
2 | 2 | falderal --substring-error \ |
3 | 3 | tests/SixtyPical\ Syntax.md \ |
4 | tests/SixtyPical\ Execution.md \ | |
5 | 4 | tests/SixtyPical\ Analysis.md \ |
6 | 5 | tests/SixtyPical\ Compilation.md |
0 | SixtyPical Execution | |
1 | ==================== | |
2 | ||
3 | This is a test suite, written in [Falderal][] format, for the dynamic | |
4 | execution behaviour of the Sixtypical language, disgregarding static analysis. | |
5 | ||
6 | [Falderal]: http://catseye.tc/node/Falderal | |
7 | ||
8 | -> Functionality "Execute SixtyPical program" is implemented by | |
9 | -> shell command "bin/sixtypical --execute %(test-body-file)" | |
10 | ||
11 | -> Tests for functionality "Execute SixtyPical program" | |
12 | ||
13 | Rudimentary program. | |
14 | ||
15 | | routine main { | |
16 | | ld a, 0 | |
17 | | add a, 1 | |
18 | | } | |
19 | = a: 1 | |
20 | = c: 0 | |
21 | = n: 0 | |
22 | = v: 0 | |
23 | = x: 0 | |
24 | = y: 0 | |
25 | = z: 0 | |
26 | ||
27 | Program accesses a memory location. | |
28 | ||
29 | | byte lives | |
30 | | | |
31 | | routine main { | |
32 | | ld a, 0 | |
33 | | st a, lives | |
34 | | ld x, lives | |
35 | | add x, 1 | |
36 | | st x, lives | |
37 | | } | |
38 | = a: 0 | |
39 | = c: 0 | |
40 | = lives: 1 | |
41 | = n: 0 | |
42 | = v: 0 | |
43 | = x: 1 | |
44 | = y: 0 | |
45 | = z: 0 | |
46 | ||
47 | Program accesses a memory location with initial value. | |
48 | ||
49 | | byte lives : 3 | |
50 | | | |
51 | | routine main { | |
52 | | ld a, lives | |
53 | | } | |
54 | = a: 3 | |
55 | = c: 0 | |
56 | = lives: 3 | |
57 | = n: 0 | |
58 | = v: 0 | |
59 | = x: 0 | |
60 | = y: 0 | |
61 | = z: 0 | |
62 | ||
63 | Add honours carry. | |
64 | ||
65 | | routine main { | |
66 | | ld a, 255 | |
67 | | st on, c | |
68 | | add a, 0 | |
69 | | } | |
70 | = a: 0 | |
71 | = c: 1 | |
72 | = n: 0 | |
73 | = v: 0 | |
74 | = x: 0 | |
75 | = y: 0 | |
76 | = z: 1 | |
77 | ||
78 | | routine main { | |
79 | | ld a, $ff | |
80 | | st off, c | |
81 | | add a, 1 | |
82 | | } | |
83 | = a: 0 | |
84 | = c: 1 | |
85 | = n: 0 | |
86 | = v: 0 | |
87 | = x: 0 | |
88 | = y: 0 | |
89 | = z: 1 | |
90 | ||
91 | Subtract honours carry. | |
92 | ||
93 | | routine main { | |
94 | | ld a, 0 | |
95 | | st on, c | |
96 | | sub a, 0 | |
97 | | } | |
98 | = a: 255 | |
99 | = c: 1 | |
100 | = n: 1 | |
101 | = v: 0 | |
102 | = x: 0 | |
103 | = y: 0 | |
104 | = z: 0 | |
105 | ||
106 | | routine main { | |
107 | | ld a, 0 | |
108 | | st off, c | |
109 | | sub a, 1 | |
110 | | } | |
111 | = a: 255 | |
112 | = c: 1 | |
113 | = n: 1 | |
114 | = v: 0 | |
115 | = x: 0 | |
116 | = y: 0 | |
117 | = z: 0 | |
118 | ||
119 | Inc and dec do not honour carry, but do set n and z. | |
120 | ||
121 | | routine main { | |
122 | | ld x, 254 | |
123 | | st on, c | |
124 | | inc x | |
125 | | } | |
126 | = a: 0 | |
127 | = c: 1 | |
128 | = n: 1 | |
129 | = v: 0 | |
130 | = x: 255 | |
131 | = y: 0 | |
132 | = z: 0 | |
133 | ||
134 | | routine main { | |
135 | | ld y, 1 | |
136 | | st on, c | |
137 | | dec y | |
138 | | } | |
139 | = a: 0 | |
140 | = c: 1 | |
141 | = n: 0 | |
142 | = v: 0 | |
143 | = x: 0 | |
144 | = y: 0 | |
145 | = z: 1 | |
146 | ||
147 | Compare affects, but does not use, carry. | |
148 | ||
149 | | routine main { | |
150 | | ld a, 1 | |
151 | | st on, c | |
152 | | cmp a, 1 | |
153 | | } | |
154 | = a: 1 | |
155 | = c: 0 | |
156 | = n: 0 | |
157 | = v: 0 | |
158 | = x: 0 | |
159 | = y: 0 | |
160 | = z: 1 | |
161 | ||
162 | | routine main { | |
163 | | ld a, 1 | |
164 | | st off, c | |
165 | | cmp a, 5 | |
166 | | } | |
167 | = a: 1 | |
168 | = c: 1 | |
169 | = n: 1 | |
170 | = v: 0 | |
171 | = x: 0 | |
172 | = y: 0 | |
173 | = z: 0 | |
174 | ||
175 | AND. | |
176 | ||
177 | | routine main { | |
178 | | ld a, 15 | |
179 | | and a, 18 | |
180 | | } | |
181 | = a: 2 | |
182 | = c: 0 | |
183 | = n: 0 | |
184 | = v: 0 | |
185 | = x: 0 | |
186 | = y: 0 | |
187 | = z: 0 | |
188 | ||
189 | OR. | |
190 | ||
191 | | routine main { | |
192 | | ld a, 34 | |
193 | | or a, 18 | |
194 | | } | |
195 | = a: 50 | |
196 | = c: 0 | |
197 | = n: 0 | |
198 | = v: 0 | |
199 | = x: 0 | |
200 | = y: 0 | |
201 | = z: 0 | |
202 | ||
203 | XOR. | |
204 | ||
205 | | routine main { | |
206 | | ld a, 34 | |
207 | | xor a, 18 | |
208 | | } | |
209 | = a: 48 | |
210 | = c: 0 | |
211 | = n: 0 | |
212 | = v: 0 | |
213 | = x: 0 | |
214 | = y: 0 | |
215 | = z: 0 | |
216 | ||
217 | Shift left. | |
218 | ||
219 | | routine main { | |
220 | | ld a, 129 | |
221 | | st off, c | |
222 | | shl a | |
223 | | } | |
224 | = a: 2 | |
225 | = c: 1 | |
226 | = n: 0 | |
227 | = v: 0 | |
228 | = x: 0 | |
229 | = y: 0 | |
230 | = z: 0 | |
231 | ||
232 | | routine main { | |
233 | | ld a, 0 | |
234 | | st on, c | |
235 | | shl a | |
236 | | } | |
237 | = a: 1 | |
238 | = c: 0 | |
239 | = n: 0 | |
240 | = v: 0 | |
241 | = x: 0 | |
242 | = y: 0 | |
243 | = z: 0 | |
244 | ||
245 | Shift right. | |
246 | ||
247 | | routine main { | |
248 | | ld a, 129 | |
249 | | st off, c | |
250 | | shr a | |
251 | | } | |
252 | = a: 64 | |
253 | = c: 1 | |
254 | = n: 0 | |
255 | = v: 0 | |
256 | = x: 0 | |
257 | = y: 0 | |
258 | = z: 0 | |
259 | ||
260 | | routine main { | |
261 | | ld a, 0 | |
262 | | st on, c | |
263 | | shr a | |
264 | | } | |
265 | = a: 128 | |
266 | = c: 0 | |
267 | = n: 1 | |
268 | = v: 0 | |
269 | = x: 0 | |
270 | = y: 0 | |
271 | = z: 0 | |
272 | ||
273 | Call routine. | |
274 | ||
275 | | routine up { | |
276 | | inc x | |
277 | | inc y | |
278 | | } | |
279 | | routine main { | |
280 | | ld x, 0 | |
281 | | ld y, 1 | |
282 | | call up | |
283 | | call up | |
284 | | } | |
285 | = a: 0 | |
286 | = c: 0 | |
287 | = n: 0 | |
288 | = v: 0 | |
289 | = x: 2 | |
290 | = y: 3 | |
291 | = z: 0 | |
292 | ||
293 | If. | |
294 | ||
295 | | routine main { | |
296 | | ld x, 40 | |
297 | | cmp x, 40 | |
298 | | if z { | |
299 | | ld a, 1 | |
300 | | } else { | |
301 | | ld a, 8 | |
302 | | } | |
303 | | ld x, 2 | |
304 | | } | |
305 | = a: 1 | |
306 | = c: 0 | |
307 | = n: 0 | |
308 | = v: 0 | |
309 | = x: 2 | |
310 | = y: 0 | |
311 | = z: 0 | |
312 | ||
313 | | routine main { | |
314 | | ld x, 39 | |
315 | | cmp x, 40 | |
316 | | if z { | |
317 | | ld a, 1 | |
318 | | } else { | |
319 | | ld a, 8 | |
320 | | } | |
321 | | ld x, 2 | |
322 | | } | |
323 | = a: 8 | |
324 | = c: 1 | |
325 | = n: 0 | |
326 | = v: 0 | |
327 | = x: 2 | |
328 | = y: 0 | |
329 | = z: 0 | |
330 | ||
331 | If without else. | |
332 | ||
333 | | routine main { | |
334 | | ld x, 39 | |
335 | | cmp x, 40 | |
336 | | if z { | |
337 | | ld a, 1 | |
338 | | } | |
339 | | ld x, 2 | |
340 | | } | |
341 | = a: 0 | |
342 | = c: 1 | |
343 | = n: 0 | |
344 | = v: 0 | |
345 | = x: 2 | |
346 | = y: 0 | |
347 | = z: 0 | |
348 | ||
349 | `not` inverts the sense of the test. | |
350 | ||
351 | | routine main { | |
352 | | ld x, 40 | |
353 | | cmp x, 40 | |
354 | | if not z { | |
355 | | ld a, 1 | |
356 | | } else { | |
357 | | ld a, 8 | |
358 | | } | |
359 | | ld x, 2 | |
360 | | } | |
361 | = a: 8 | |
362 | = c: 0 | |
363 | = n: 0 | |
364 | = v: 0 | |
365 | = x: 2 | |
366 | = y: 0 | |
367 | = z: 0 | |
368 | ||
369 | | routine main { | |
370 | | ld x, 39 | |
371 | | cmp x, 40 | |
372 | | if not z { | |
373 | | ld a, 1 | |
374 | | } | |
375 | | ld x, 2 | |
376 | | } | |
377 | = a: 1 | |
378 | = c: 1 | |
379 | = n: 0 | |
380 | = v: 0 | |
381 | = x: 2 | |
382 | = y: 0 | |
383 | = z: 0 | |
384 | ||
385 | Repeat loop. | |
386 | ||
387 | | routine main { | |
388 | | ld x, 0 | |
389 | | ld y, 15 | |
390 | | repeat { | |
391 | | inc x | |
392 | | inc y | |
393 | | cmp x, 10 | |
394 | | } until z | |
395 | | } | |
396 | = a: 0 | |
397 | = c: 0 | |
398 | = n: 0 | |
399 | = v: 0 | |
400 | = x: 10 | |
401 | = y: 25 | |
402 | = z: 1 | |
403 | ||
404 | Copy instruction. Note that the state of a, z, and n are not defined | |
405 | after copy executes. | |
406 | ||
407 | | routine main { | |
408 | | ld x, 5 | |
409 | | copy x, y | |
410 | | } | |
411 | = a: 0 | |
412 | = c: 0 | |
413 | = n: 0 | |
414 | = v: 0 | |
415 | = x: 5 | |
416 | = y: 5 | |
417 | = z: 0 | |
418 | ||
419 | Copy word to word. | |
420 | ||
421 | | word foo : 2000 | |
422 | | word bar | |
423 | | | |
424 | | routine main { | |
425 | | copy foo, bar | |
426 | | } | |
427 | = a: 0 | |
428 | = bar: 2000 | |
429 | = c: 0 | |
430 | = foo: 2000 | |
431 | = n: 0 | |
432 | = v: 0 | |
433 | = x: 0 | |
434 | = y: 0 | |
435 | = z: 0 | |
436 | ||
437 | Copy literal word to word. | |
438 | ||
439 | | word bar | |
440 | | | |
441 | | routine main { | |
442 | | copy word 2000, bar | |
443 | | } | |
444 | = a: 0 | |
445 | = bar: 2000 | |
446 | = c: 0 | |
447 | = n: 0 | |
448 | = v: 0 | |
449 | = x: 0 | |
450 | = y: 0 | |
451 | = z: 0 | |
452 | ||
453 | Indirect call. | |
454 | ||
455 | | vector foo outputs x trashes z, n | |
456 | | | |
457 | | routine bar outputs x trashes z, n { | |
458 | | ld x, 200 | |
459 | | } | |
460 | | | |
461 | | routine main inputs bar outputs x, foo trashes a, z, n { | |
462 | | copy bar, foo | |
463 | | call foo | |
464 | | } | |
465 | = a: 0 | |
466 | = c: 0 | |
467 | = n: 1 | |
468 | = v: 0 | |
469 | = x: 200 | |
470 | = y: 0 | |
471 | = z: 0 | |
472 | ||
473 | goto. | |
474 | ||
475 | | routine bar outputs x trashes z, n { | |
476 | | ld x, 200 | |
477 | | } | |
478 | | | |
479 | | routine main outputs x trashes a, z, n { | |
480 | | ld y, 200 | |
481 | | goto bar | |
482 | | } | |
483 | = a: 0 | |
484 | = c: 0 | |
485 | = n: 1 | |
486 | = v: 0 | |
487 | = x: 200 | |
488 | = y: 200 | |
489 | = z: 0 |