Parse indirect calls, but break evaluator.
Chris Pressey
6 years ago
109 | 109 | } |
110 | 110 | |
111 | 111 | Routines may call only routines previously defined in the program source. |
112 | Thus, recursive routines are not allowed. | |
112 | Thus, directly recursive routines are not allowed. (However, routines may | |
113 | also call routines via vectors, which are dynamically assigned. In this | |
114 | case, there is, for the time being, no check for recursive calls.) | |
113 | 115 | |
114 | 116 | For a SixtyPical program to be run, there must be one routine called `main`. |
115 | 117 | This routine is executed when the program is run. |
284 | 286 | |
285 | 287 | ### call ### |
286 | 288 | |
287 | call <routine-name> | |
289 | call <executable-name> | |
290 | ||
291 | Transfers execution to the given executable, whether that is a previously- | |
292 | defined routine, or a vector location which contains the address of a routine | |
293 | which will be called indirectly. | |
288 | 294 | |
289 | 295 | Just before the call, |
290 | 296 |
2 | 2 | from sixtypical.ast import Program, Routine, Block, Instr |
3 | 3 | from sixtypical.model import ( |
4 | 4 | TYPE_BYTE, TYPE_BYTE_TABLE, |
5 | RoutineType, VectorType, ExecutableType, | |
5 | VectorType, ExecutableType, | |
6 | 6 | ConstantRef, LocationRef, |
7 | 7 | REG_A, FLAG_Z, FLAG_N, FLAG_V, FLAG_C |
8 | 8 | ) |
1 | 1 | |
2 | 2 | from sixtypical.ast import Program, Routine, Block, Instr |
3 | 3 | from sixtypical.model import ( |
4 | ConstantRef, LocationRef, | |
4 | ConstantRef, | |
5 | 5 | TYPE_BIT, |
6 | 6 | RoutineType, VectorType, |
7 | REG_A, REG_X, REG_Y, FLAG_Z, FLAG_N, FLAG_V, FLAG_C | |
7 | REG_A, REG_X, REG_Y, FLAG_C | |
8 | 8 | ) |
9 | 9 | from sixtypical.emitter import Byte, Label, Offset |
10 | 10 | from sixtypical.gen6502 import ( |
8 | 8 | class Byte(Emittable): |
9 | 9 | def __init__(self, value): |
10 | 10 | if value < -127 or value > 255: |
11 | raise IndexError(thing) | |
11 | raise IndexError(value) | |
12 | 12 | if value < 0: |
13 | 13 | value += 256 |
14 | 14 | self.value = value |
22 | 22 | raise ValueError(ref) |
23 | 23 | |
24 | 24 | def set(self, ref, value): |
25 | assert isinstance(ref, LocationRef) | |
26 | self._store[ref.name] = value | |
25 | # bleah | |
26 | if isinstance(ref, LocationRef): | |
27 | self._store[ref.name] = value | |
28 | else: | |
29 | self._store[ref] = value | |
27 | 30 | |
28 | 31 | |
29 | 32 | def eval_program(program): |
30 | 33 | assert isinstance(program, Program) |
31 | routines = {r.name: r for r in program.routines} | |
32 | 34 | context = Context() |
33 | 35 | for ref in (REG_A, REG_X, REG_Y, FLAG_Z, FLAG_N, FLAG_V, FLAG_C): |
34 | 36 | context.set(ref, 0) |
35 | eval_routine(routines['main'], context, routines) | |
37 | for routine in program.routines: | |
38 | context.set(routine.name, routine) | |
39 | eval_routine(context['main'], context) | |
36 | 40 | return context |
37 | 41 | |
38 | 42 | |
39 | def eval_routine(routine, context, routines): | |
43 | def eval_routine(routine, context): | |
40 | 44 | assert isinstance(routine, Routine) |
41 | eval_block(routine.block, context, routines) | |
45 | eval_block(routine.block, context) | |
42 | 46 | |
43 | 47 | |
44 | def eval_block(block, context, routines): | |
48 | def eval_block(block, context): | |
45 | 49 | assert isinstance(block, Block) |
46 | 50 | for i in block.instrs: |
47 | eval_instr(i, context, routines) | |
51 | eval_instr(i, context) | |
48 | 52 | |
49 | 53 | |
50 | def eval_instr(instr, context, routines): | |
54 | def eval_instr(instr, context): | |
51 | 55 | assert isinstance(instr, Instr) |
52 | 56 | opcode = instr.opcode |
53 | 57 | dest = instr.dest |
141 | 145 | context.set(FLAG_N, 1 if result & 128 else 0) |
142 | 146 | context.set(dest, result) |
143 | 147 | elif opcode == 'call': |
144 | eval_routine(routines[instr.name], context, routines) | |
148 | eval_routine(context[instr.name], context) | |
145 | 149 | elif opcode == 'if': |
146 | 150 | val = context.get(src) |
147 | 151 | test = (val != 0) if not instr.inverted else (val == 0) |
148 | 152 | if test: |
149 | eval_block(instr.block1, context, routines) | |
153 | eval_block(instr.block1, context) | |
150 | 154 | elif instr.block2: |
151 | eval_block(instr.block2, context, routines) | |
155 | eval_block(instr.block2, context) | |
152 | 156 | elif opcode == 'repeat': |
153 | eval_block(instr.block, context, routines) | |
157 | eval_block(instr.block, context) | |
154 | 158 | while context.get(src) == 0: |
155 | eval_block(instr.block, context, routines) | |
159 | eval_block(instr.block, context) | |
156 | 160 | elif opcode == 'copy': |
157 | 161 | context.set(dest, context.get(src)) |
158 | 162 | # these are trashed; so could be anything really |
0 | 0 | """Emittables for 6502 machine code.""" |
1 | 1 | |
2 | from sixtypical.emitter import Emittable, Byte, Word, Label, Offset | |
2 | from sixtypical.emitter import Emittable, Byte, Label, Offset | |
3 | 3 | |
4 | 4 | |
5 | 5 | class AddressingMode(Emittable): |
57 | 57 | pass |
58 | 58 | |
59 | 59 | |
60 | class Indirect(AddressingMode): | |
61 | def __init__(self, value): | |
62 | assert isinstance(value, Label) | |
63 | self.value = value | |
64 | ||
65 | def size(self): | |
66 | return 2 | |
67 | ||
68 | def serialize(self, addr=None): | |
69 | return self.value.serialize() | |
70 | ||
71 | ||
60 | 72 | class Relative(AddressingMode): |
61 | 73 | def __init__(self, value): |
62 | 74 | assert isinstance(value, Label) |
69 | 81 | return self.value.serialize_relative_to(addr) |
70 | 82 | |
71 | 83 | |
72 | class Opcode(Emittable): | |
84 | class Instruction(Emittable): | |
73 | 85 | def __init__(self, operand=None): |
74 | 86 | self.operand = operand or Implied() |
75 | 87 | |
86 | 98 | return "%s(%r)" % (self.__class__.__name__, self.operand) |
87 | 99 | |
88 | 100 | |
89 | class ADC(Opcode): | |
101 | class ADC(Instruction): | |
90 | 102 | opcodes = { |
91 | 103 | Immediate: 0x69, |
92 | 104 | Absolute: 0x6d, |
95 | 107 | } |
96 | 108 | |
97 | 109 | |
98 | class AND(Opcode): | |
110 | class AND(Instruction): | |
99 | 111 | opcodes = { |
100 | 112 | Immediate: 0x29, |
101 | 113 | Absolute: 0x2d, |
104 | 116 | } |
105 | 117 | |
106 | 118 | |
107 | class BCC(Opcode): | |
119 | class BCC(Instruction): | |
108 | 120 | opcodes = { |
109 | 121 | Relative: 0x90, |
110 | 122 | } |
111 | 123 | |
112 | 124 | |
113 | class BCS(Opcode): | |
125 | class BCS(Instruction): | |
114 | 126 | opcodes = { |
115 | 127 | Relative: 0xb0, |
116 | 128 | } |
117 | 129 | |
118 | 130 | |
119 | class BEQ(Opcode): | |
131 | class BEQ(Instruction): | |
120 | 132 | opcodes = { |
121 | 133 | Relative: 0xf0, |
122 | 134 | } |
123 | 135 | |
124 | 136 | |
125 | class BNE(Opcode): | |
137 | class BNE(Instruction): | |
126 | 138 | opcodes = { |
127 | 139 | Relative: 0xd0, |
128 | 140 | } |
129 | 141 | |
130 | 142 | |
131 | class CLC(Opcode): | |
143 | class CLC(Instruction): | |
132 | 144 | opcodes = { |
133 | 145 | Implied: 0x18 |
134 | 146 | } |
135 | 147 | |
136 | 148 | |
137 | class CLI(Opcode): | |
149 | class CLI(Instruction): | |
138 | 150 | opcodes = { |
139 | 151 | Implied: 0x58, |
140 | 152 | } |
141 | 153 | |
142 | 154 | |
143 | class CMP(Opcode): | |
155 | class CMP(Instruction): | |
144 | 156 | opcodes = { |
145 | 157 | Immediate: 0xc9, |
146 | 158 | Absolute: 0xcd, |
149 | 161 | } |
150 | 162 | |
151 | 163 | |
152 | class CPX(Opcode): | |
164 | class CPX(Instruction): | |
153 | 165 | opcodes = { |
154 | 166 | Immediate: 0xe0, |
155 | 167 | Absolute: 0xec, |
156 | 168 | } |
157 | 169 | |
158 | 170 | |
159 | class CPY(Opcode): | |
171 | class CPY(Instruction): | |
160 | 172 | opcodes = { |
161 | 173 | Immediate: 0xc0, |
162 | 174 | Absolute: 0xcc, |
163 | 175 | } |
164 | 176 | |
165 | 177 | |
166 | class DEC(Opcode): | |
178 | class DEC(Instruction): | |
167 | 179 | opcodes = { |
168 | 180 | Absolute: 0xce, |
169 | 181 | } |
170 | 182 | |
171 | 183 | |
172 | class DEX(Opcode): | |
184 | class DEX(Instruction): | |
173 | 185 | opcodes = { |
174 | 186 | Implied: 0xca, |
175 | 187 | } |
176 | 188 | |
177 | 189 | |
178 | class DEY(Opcode): | |
190 | class DEY(Instruction): | |
179 | 191 | opcodes = { |
180 | 192 | Implied: 0x88, |
181 | 193 | } |
182 | 194 | |
183 | 195 | |
184 | class EOR(Opcode): | |
196 | class EOR(Instruction): | |
185 | 197 | opcodes = { |
186 | 198 | Immediate: 0x49, |
187 | 199 | Absolute: 0x4d, |
190 | 202 | } |
191 | 203 | |
192 | 204 | |
193 | class INC(Opcode): | |
205 | class INC(Instruction): | |
194 | 206 | opcodes = { |
195 | 207 | Absolute: 0xee, |
196 | 208 | AbsoluteX: 0xfe, |
197 | 209 | } |
198 | 210 | |
199 | 211 | |
200 | class INX(Opcode): | |
212 | class INX(Instruction): | |
201 | 213 | opcodes = { |
202 | 214 | Implied: 0xe8, |
203 | 215 | } |
204 | 216 | |
205 | 217 | |
206 | class INY(Opcode): | |
218 | class INY(Instruction): | |
207 | 219 | opcodes = { |
208 | 220 | Implied: 0xc8, |
209 | 221 | } |
210 | 222 | |
211 | 223 | |
212 | class JMP(Opcode): | |
224 | class JMP(Instruction): | |
213 | 225 | opcodes = { |
214 | 226 | Absolute: 0x4c, |
215 | } | |
216 | ||
217 | ||
218 | class JSR(Opcode): | |
227 | Indirect: 0x6c, | |
228 | } | |
229 | ||
230 | ||
231 | class JSR(Instruction): | |
219 | 232 | opcodes = { |
220 | 233 | Absolute: 0x20, |
221 | 234 | } |
222 | 235 | |
223 | 236 | |
224 | class LDA(Opcode): | |
237 | class LDA(Instruction): | |
225 | 238 | opcodes = { |
226 | 239 | Immediate: 0xa9, |
227 | 240 | Absolute: 0xad, |
230 | 243 | } |
231 | 244 | |
232 | 245 | |
233 | class LDX(Opcode): | |
246 | class LDX(Instruction): | |
234 | 247 | opcodes = { |
235 | 248 | Immediate: 0xa2, |
236 | 249 | Absolute: 0xae, |
238 | 251 | } |
239 | 252 | |
240 | 253 | |
241 | class LDY(Opcode): | |
254 | class LDY(Instruction): | |
242 | 255 | opcodes = { |
243 | 256 | Immediate: 0xa0, |
244 | 257 | Absolute: 0xac, |
246 | 259 | } |
247 | 260 | |
248 | 261 | |
249 | class ORA(Opcode): | |
262 | class ORA(Instruction): | |
250 | 263 | opcodes = { |
251 | 264 | Immediate: 0x09, |
252 | 265 | Absolute: 0x0d, |
255 | 268 | } |
256 | 269 | |
257 | 270 | |
258 | class ROL(Opcode): | |
271 | class ROL(Instruction): | |
259 | 272 | opcodes = { |
260 | 273 | Implied: 0x2a, # Accumulator |
261 | 274 | Absolute: 0x2e, |
263 | 276 | } |
264 | 277 | |
265 | 278 | |
266 | class ROR(Opcode): | |
279 | class ROR(Instruction): | |
267 | 280 | opcodes = { |
268 | 281 | Implied: 0x6a, # Accumulator |
269 | 282 | Absolute: 0x6e, |
271 | 284 | } |
272 | 285 | |
273 | 286 | |
274 | class RTS(Opcode): | |
287 | class RTS(Instruction): | |
275 | 288 | opcodes = { |
276 | 289 | Implied: 0x60, |
277 | 290 | } |
278 | 291 | |
279 | 292 | |
280 | class SBC(Opcode): | |
293 | class SBC(Instruction): | |
281 | 294 | opcodes = { |
282 | 295 | Immediate: 0xe9, |
283 | 296 | Absolute: 0xed, |
286 | 299 | } |
287 | 300 | |
288 | 301 | |
289 | class SEC(Opcode): | |
302 | class SEC(Instruction): | |
290 | 303 | opcodes = { |
291 | 304 | Implied: 0x38, |
292 | 305 | } |
293 | 306 | |
294 | 307 | |
295 | class SEI(Opcode): | |
308 | class SEI(Instruction): | |
296 | 309 | opcodes = { |
297 | 310 | Implied: 0x78, |
298 | 311 | } |
299 | 312 | |
300 | 313 | |
301 | class STA(Opcode): | |
314 | class STA(Instruction): | |
302 | 315 | opcodes = { |
303 | 316 | Absolute: 0x8d, |
304 | 317 | AbsoluteX: 0x9d, |
306 | 319 | } |
307 | 320 | |
308 | 321 | |
309 | class STX(Opcode): | |
322 | class STX(Instruction): | |
310 | 323 | opcodes = { |
311 | 324 | Absolute: 0x8e, |
312 | 325 | } |
313 | 326 | |
314 | 327 | |
315 | class STY(Opcode): | |
328 | class STY(Instruction): | |
316 | 329 | opcodes = { |
317 | 330 | Absolute: 0x8c, |
318 | 331 | } |
319 | 332 | |
320 | 333 | |
321 | class TAX(Opcode): | |
334 | class TAX(Instruction): | |
322 | 335 | opcodes = { |
323 | 336 | Implied: 0xaa, |
324 | 337 | } |
325 | 338 | |
326 | 339 | |
327 | class TAY(Opcode): | |
340 | class TAY(Instruction): | |
328 | 341 | opcodes = { |
329 | 342 | Implied: 0xa8, |
330 | 343 | } |
331 | 344 | |
332 | 345 | |
333 | class TXA(Opcode): | |
346 | class TXA(Instruction): | |
334 | 347 | opcodes = { |
335 | 348 | Implied: 0x8a, |
336 | 349 | } |
337 | 350 | |
338 | 351 | |
339 | class TYA(Opcode): | |
352 | class TYA(Instruction): | |
340 | 353 | opcodes = { |
341 | 354 | Implied: 0x98, |
342 | 355 | } |
85 | 85 | self.type = type |
86 | 86 | self.value = value |
87 | 87 | |
88 | def __repr__(self): | |
89 | return 'ConstantRef(%r)' % self.value | |
90 | ||
91 | 88 | def __eq__(self, other): |
92 | 89 | return isinstance(other, ConstantRef) and ( |
93 | 90 | other.type == self.type and other.value == self.value |
4 | 4 | from sixtypical.ast import Program, Defn, Routine, Block, Instr |
5 | 5 | from sixtypical.model import ( |
6 | 6 | TYPE_BIT, TYPE_BYTE, TYPE_BYTE_TABLE, |
7 | RoutineType, VectorType, | |
7 | RoutineType, VectorType, ExecutableType, | |
8 | 8 | LocationRef, ConstantRef |
9 | 9 | ) |
10 | 10 | |
266 | 266 | self.scanner.scan() |
267 | 267 | if name not in self.symbols: |
268 | 268 | raise SyntaxError('Undefined routine "%s"' % name) |
269 | if not isinstance(self.symbols[name].model.type, RoutineType): | |
270 | raise SyntaxError('Illegal call of non-routine "%s"' % name) | |
269 | if not isinstance(self.symbols[name].model.type, ExecutableType): | |
270 | raise SyntaxError('Illegal call of non-executable "%s"' % name) | |
271 | 271 | return Instr(opcode=opcode, name=name, dest=None, src=None) |
272 | 272 | elif self.scanner.token in ("copy",): |
273 | 273 | opcode = self.scanner.token |
399 | 399 | = x: 5 |
400 | 400 | = y: 5 |
401 | 401 | = z: 0 |
402 | ||
403 | Indirect call. | |
404 | ||
405 | | vector foo outputs x trashes z, n | |
406 | | | |
407 | | routine bar outputs x trashes z, n { | |
408 | | ld x, 200 | |
409 | | } | |
410 | | | |
411 | | routine main { | |
412 | | copy bar, foo | |
413 | | call foo | |
414 | | } | |
415 | = a: 0 | |
416 | = c: 0 | |
417 | = n: 1 | |
418 | = v: 0 | |
419 | = x: 200 | |
420 | = y: 0 | |
421 | = z: 0 |
2 | 2 | |
3 | 3 | This is a test suite, written in [Falderal][] format, for the syntax of |
4 | 4 | the Sixtypical language, disgregarding execution, static analysis, etc. |
5 | ||
6 | Note that these example programs are intended to be syntactically correct, | |
7 | but not necessarily sensible programs. | |
5 | 8 | |
6 | 9 | [Falderal]: http://catseye.tc/node/Falderal |
7 | 10 | |
214 | 217 | | } |
215 | 218 | = ok |
216 | 219 | |
217 | Declaring a vector. | |
220 | Declaring and calling a vector. | |
218 | 221 | |
219 | 222 | | vector cinv |
220 | 223 | | inputs a |
229 | 232 | | with interrupts off { |
230 | 233 | | copy foo, cinv |
231 | 234 | | } |
235 | | call cinv | |
232 | 236 | | } |
233 | 237 | = ok |
234 | 238 |