git @ Cat's Eye Technologies SixtyPical / 49e42af
Implement `if not` and `repeat forever`. Chris Pressey 6 years ago
11 changed file(s) with 169 addition(s) and 16 deletion(s). Raw diff Collapse all Expand all
1616 0.3
1717 ---
1818
19 Added ability to compile to 6502 machine code and output a `PRG` file.
19 * Added external routine declarations.
20 * Added ability to compile to 6502 machine code and output a `PRG` file.
2021
2122 0.4
2223 ---
2324
24 Added `repeat` loops to the language.
25 * Added `repeat` loops to the language, which can repeat until a flag
26 is set (or `not` set), or which can repeat `forever`.
27 * `if not` inverts the sense of the test.
3232
3333 For 0.4:
3434
35 * `if not`.
3635 * explicitly-addressed memory locations
3736
3837 For 0.5:
313313 if z {
314314 }
315315 } until z
316
317 "until" is optional, but if omitted, must be replaced with "forever".
316318
317319 Grammar
318320 -------
343345 | "dec" LocExpr
344346 | "call" RoutineIdent
345347 | "if" ["not"] LocExpr Block ["else" Block]
346 | "repeat" Block "until" ["not"] LocExpr
348 | "repeat" Block ("until" ["not"] LocExpr | "forever")
347349 .
0 routine main
1 trashes a, y, z, n, c
2 {
3 ld y, 65
4 repeat {
5 inc y
6 } forever
7 }
176176 self.emitter.emit(JSR(Absolute(label)))
177177 elif opcode == 'if':
178178 cls = {
179 'c': BCC,
180 'z': BNE,
181 }.get(src.name)
179 False: {
180 'c': BCC,
181 'z': BNE,
182 },
183 True: {
184 'c': BCS,
185 'z': BEQ,
186 },
187 }[instr.inverted].get(src.name)
182188 if cls is None:
183189 raise UnsupportedOpcodeError(instr)
184190 else_label = Label('else_label')
193199 else:
194200 self.emitter.resolve_label(else_label)
195201 elif opcode == 'repeat':
196 cls = {
197 'c': BCC,
198 'z': BNE,
199 }.get(src.name)
200 if cls is None:
201 raise UnsupportedOpcodeError(instr)
202202 top_label = self.emitter.make_label()
203203 self.compile_block(instr.block)
204 self.emitter.emit(cls(Relative(top_label)))
204 if src is None:
205 self.emitter.emit(JMP(Absolute(top_label)))
206 else:
207 cls = {
208 False: {
209 'c': BCC,
210 'z': BNE,
211 },
212 True: {
213 'c': BCS,
214 'z': BEQ,
215 },
216 }[instr.inverted].get(src.name)
217 if cls is None:
218 raise UnsupportedOpcodeError(instr)
219 self.emitter.emit(cls(Relative(top_label)))
205220 else:
206221 raise NotImplementedError
144144 eval_routine(routines[instr.name], context, routines)
145145 elif opcode == 'if':
146146 val = context.get(src)
147 if val != 0:
147 test = (val != 0) if not instr.inverted else (val == 0)
148 if test:
148149 eval_block(instr.block1, context, routines)
149150 elif instr.block2:
150151 eval_block(instr.block2, context, routines)
184184 if self.scanner.consume('not'):
185185 inverted = True
186186 src = self.locexpr()
187 else:
188 self.scanner.expect('forever')
187189 return Instr(opcode='repeat', dest=None, src=src,
188190 block=block, inverted=inverted)
189191 elif self.scanner.token in ("ld", "add", "sub", "cmp", "and", "or", "xor"):
752752 | }
753753 ? InconsistentInitializationError: x
754754
755 | routine foo
756 | inputs a
757 | outputs x
758 | trashes a, z, n, c
759 | {
760 | cmp a, 42
761 | if not z {
762 | ld a, 6
763 | } else {
764 | ld x, 7
765 | }
766 | }
767 ? InconsistentInitializationError: x
768
755769 An `if` with a single block is analyzed as if it had an empty `else` block.
756770
757771 | routine foo
774788 | ld x, 0
775789 | cmp a, 42
776790 | if z {
791 | ld x, 7
792 | }
793 | }
794 = ok
795
796 | routine foo
797 | inputs a
798 | outputs x
799 | trashes a, z, n, c
800 | {
801 | ld x, 0
802 | cmp a, 42
803 | if not z {
777804 | ld x, 7
778805 | }
779806 | }
132132 | }
133133 = 00c0a900d005a0014c0bc0a00260
134134
135 Compiling `if not`.
136
137 | routine main
138 | trashes a, x, y, z, n, c, v
139 | {
140 | ld a, 0
141 | if not z {
142 | ld y, 1
143 | } else {
144 | ld y, 2
145 | }
146 | }
147 = 00c0a900f005a0014c0bc0a00260
148
135149 Compiling `if` without `else`.
136150
137151 | routine main
157171 | } until z
158172 | }
159173 = 00c0a04198c8c05bd0fa60
174
175 Compiling `repeat until not`.
176
177 | routine main
178 | trashes a, y, z, n, c
179 | {
180 | ld y, 65
181 | repeat {
182 | ld a, y
183 | inc y
184 | cmp y, 91
185 | } until not z
186 | }
187 = 00c0a04198c8c05bf0fa60
188
189 Compiling `repeat forever`.
190
191 | routine main
192 | trashes a, y, z, n, c
193 | {
194 | ld y, 65
195 | repeat {
196 | inc y
197 | } forever
198 | }
199 = 00c0a041c84c02c060
353353 = y: 0
354354 = z: 0
355355
356 If without else.
357
356358 | routine main {
357359 | ld x, 39
358360 | cmp x, 40
362364 | ld x, 2
363365 | }
364366 = a: 0
367 = c: 1
368 = n: 0
369 = v: 0
370 = x: 2
371 = y: 0
372 = z: 0
373
374 `not` inverts the sense of the test.
375
376 | routine main {
377 | ld x, 40
378 | cmp x, 40
379 | if not z {
380 | ld a, 1
381 | } else {
382 | ld a, 8
383 | }
384 | ld x, 2
385 | }
386 = a: 8
387 = c: 0
388 = n: 0
389 = v: 0
390 = x: 2
391 = y: 0
392 = z: 0
393
394 | routine main {
395 | ld x, 39
396 | cmp x, 40
397 | if not z {
398 | ld a, 1
399 | }
400 | ld x, 2
401 | }
402 = a: 1
365403 = c: 1
366404 = n: 0
367405 = v: 0
7070 | if not z {
7171 | inc y
7272 | }
73 | }
73 | } until z
7474 | }
7575 = ok
76
77 Repeat forever
78
79 | routine foo inputs y {
80 | repeat {
81 | inc y
82 | } forever
83 | }
84 = ok
85
86 Repeat with not
87
88 | routine foo inputs y {
89 | repeat {
90 | inc y
91 | } until not z
92 | }
93 = ok