mirror of
https://github.com/catseye/SixtyPical.git
synced 2025-01-08 19:30:29 +00:00
Almost compile for
loops correctly.
This commit is contained in:
parent
b79059faa4
commit
adb53f7a04
@ -654,20 +654,21 @@ class Analyzer(object):
|
||||
context.assert_meaningful(instr.dest)
|
||||
|
||||
bottom, top = context.get_range(instr.dest)
|
||||
final = instr.final.value
|
||||
|
||||
if instr.direction > 0:
|
||||
if top >= instr.final:
|
||||
raise RangeExceededError(self.routine, "Top of range of {} is {} but must be lower than {}".format(
|
||||
instr.dest, top, instr.final
|
||||
if top >= final:
|
||||
raise RangeExceededError(instr, "Top of range of {} is {} but must be lower than {}".format(
|
||||
instr.dest, top, final
|
||||
))
|
||||
top = instr.final
|
||||
top = final
|
||||
|
||||
if instr.direction < 0:
|
||||
if bottom <= instr.final:
|
||||
raise RangeExceededError(self.routine, "Bottom of range of {} is {} but must be higher than {}".format(
|
||||
instr.dest, bottom, instr.final
|
||||
if bottom <= final:
|
||||
raise RangeExceededError(instr, "Bottom of range of {} is {} but must be higher than {}".format(
|
||||
instr.dest, bottom, final
|
||||
))
|
||||
bottom = instr.final
|
||||
bottom = final
|
||||
|
||||
subcontext = context.clone()
|
||||
subcontext.set_range(instr.dest, bottom, top)
|
||||
|
@ -74,17 +74,17 @@ class SingleOp(Instr):
|
||||
|
||||
|
||||
class If(Instr):
|
||||
value_attrs = ('src', 'inverted')
|
||||
value_attrs = ('src', 'inverted',)
|
||||
child_attrs = ('block1', 'block2',)
|
||||
|
||||
|
||||
class Repeat(Instr):
|
||||
value_attrs = ('src', 'inverted')
|
||||
value_attrs = ('src', 'inverted',)
|
||||
child_attrs = ('block',)
|
||||
|
||||
|
||||
class For(Instr):
|
||||
value_attrs = ('dest', 'direction', 'final')
|
||||
value_attrs = ('dest', 'direction', 'final',)
|
||||
child_attrs = ('block',)
|
||||
|
||||
|
||||
|
@ -1,6 +1,6 @@
|
||||
# encoding: UTF-8
|
||||
|
||||
from sixtypical.ast import Program, Routine, Block, Instr, SingleOp, If, Repeat, WithInterruptsOff
|
||||
from sixtypical.ast import Program, Routine, Block, Instr, SingleOp, If, Repeat, For, WithInterruptsOff
|
||||
from sixtypical.model import (
|
||||
ConstantRef, LocationRef, IndexedRef, IndirectRef, AddressRef,
|
||||
TYPE_BIT, TYPE_BYTE, TYPE_WORD,
|
||||
@ -148,6 +148,8 @@ class Compiler(object):
|
||||
return self.compile_if(instr)
|
||||
elif isinstance(instr, Repeat):
|
||||
return self.compile_repeat(instr)
|
||||
elif isinstance(instr, For):
|
||||
return self.compile_for(instr)
|
||||
elif isinstance(instr, WithInterruptsOff):
|
||||
return self.compile_with_interrupts_off(instr)
|
||||
else:
|
||||
@ -300,31 +302,11 @@ class Compiler(object):
|
||||
else:
|
||||
raise UnsupportedOpcodeError(instr)
|
||||
elif opcode == 'inc':
|
||||
if dest == REG_X:
|
||||
self.emitter.emit(INX())
|
||||
elif dest == REG_Y:
|
||||
self.emitter.emit(INY())
|
||||
else:
|
||||
self.emitter.emit(INC(Absolute(self.get_label(dest.name))))
|
||||
self.compile_inc(instr, instr.dest)
|
||||
elif opcode == 'dec':
|
||||
if dest == REG_X:
|
||||
self.emitter.emit(DEX())
|
||||
elif dest == REG_Y:
|
||||
self.emitter.emit(DEY())
|
||||
else:
|
||||
self.emitter.emit(DEC(Absolute(self.get_label(dest.name))))
|
||||
self.compile_dec(instr, instr.dest)
|
||||
elif opcode == 'cmp':
|
||||
cls = {
|
||||
'a': CMP,
|
||||
'x': CPX,
|
||||
'y': CPY,
|
||||
}.get(dest.name)
|
||||
if cls is None:
|
||||
raise UnsupportedOpcodeError(instr)
|
||||
if isinstance(src, ConstantRef):
|
||||
self.emitter.emit(cls(Immediate(Byte(src.value))))
|
||||
else:
|
||||
self.emitter.emit(cls(Absolute(self.get_label(src.name))))
|
||||
self.compile_cmp(instr, instr.src, instr.dest)
|
||||
elif opcode in ('and', 'or', 'xor',):
|
||||
cls = {
|
||||
'and': AND,
|
||||
@ -369,18 +351,45 @@ class Compiler(object):
|
||||
else:
|
||||
raise NotImplementedError
|
||||
elif opcode == 'copy':
|
||||
self.compile_copy_op(instr)
|
||||
self.compile_copy(instr, instr.src, instr.dest)
|
||||
elif opcode == 'trash':
|
||||
pass
|
||||
else:
|
||||
raise NotImplementedError(opcode)
|
||||
|
||||
def compile_copy_op(self, instr):
|
||||
def compile_cmp(self, instr, src, dest):
|
||||
"""`instr` is only for reporting purposes"""
|
||||
cls = {
|
||||
'a': CMP,
|
||||
'x': CPX,
|
||||
'y': CPY,
|
||||
}.get(dest.name)
|
||||
if cls is None:
|
||||
raise UnsupportedOpcodeError(instr)
|
||||
if isinstance(src, ConstantRef):
|
||||
self.emitter.emit(cls(Immediate(Byte(src.value))))
|
||||
else:
|
||||
self.emitter.emit(cls(Absolute(self.get_label(src.name))))
|
||||
|
||||
opcode = instr.opcode
|
||||
dest = instr.dest
|
||||
src = instr.src
|
||||
def compile_inc(self, instr, dest):
|
||||
"""`instr` is only for reporting purposes"""
|
||||
if dest == REG_X:
|
||||
self.emitter.emit(INX())
|
||||
elif dest == REG_Y:
|
||||
self.emitter.emit(INY())
|
||||
else:
|
||||
self.emitter.emit(INC(Absolute(self.get_label(dest.name))))
|
||||
|
||||
def compile_dec(self, instr, dest):
|
||||
"""`instr` is only for reporting purposes"""
|
||||
if dest == REG_X:
|
||||
self.emitter.emit(DEX())
|
||||
elif dest == REG_Y:
|
||||
self.emitter.emit(DEY())
|
||||
else:
|
||||
self.emitter.emit(DEC(Absolute(self.get_label(dest.name))))
|
||||
|
||||
def compile_copy(self, instr, src, dest):
|
||||
if isinstance(src, ConstantRef) and isinstance(dest, IndirectRef) and src.type == TYPE_BYTE and isinstance(dest.ref.type, PointerType):
|
||||
### copy 123, [ptr] + y
|
||||
dest_label = self.get_label(dest.ref.name)
|
||||
@ -540,6 +549,18 @@ class Compiler(object):
|
||||
raise UnsupportedOpcodeError(instr)
|
||||
self.emitter.emit(cls(Relative(top_label)))
|
||||
|
||||
def compile_for(self, instr):
|
||||
top_label = self.emitter.make_label()
|
||||
|
||||
self.compile_block(instr.block)
|
||||
|
||||
if instr.direction > 0:
|
||||
self.compile_inc(instr, instr.dest)
|
||||
elif instr.direction < 0:
|
||||
self.compile_dec(instr, instr.dest)
|
||||
self.compile_cmp(instr, instr.final, instr.dest)
|
||||
self.emitter.emit(BNE(Relative(top_label)))
|
||||
|
||||
def compile_with_interrupts_off(self, instr):
|
||||
self.emitter.emit(SEI())
|
||||
self.compile_block(instr.block)
|
||||
|
@ -137,10 +137,16 @@ class Parser(object):
|
||||
return Defn(self.scanner.line_number, name=name, addr=addr, initial=initial, location=location)
|
||||
|
||||
def literal_int(self):
|
||||
self.scanner.check_type('integer literal')
|
||||
c = int(self.scanner.token)
|
||||
self.scanner.scan()
|
||||
return c
|
||||
self.scanner.check_type('integer literal')
|
||||
c = int(self.scanner.token)
|
||||
self.scanner.scan()
|
||||
return c
|
||||
|
||||
def literal_int_const(self):
|
||||
value = self.literal_int()
|
||||
type_ = TYPE_WORD if value > 255 else TYPE_BYTE
|
||||
loc = ConstantRef(type_, value)
|
||||
return loc
|
||||
|
||||
def defn_size(self):
|
||||
self.scanner.expect('[')
|
||||
@ -293,11 +299,7 @@ class Parser(object):
|
||||
self.scanner.scan()
|
||||
return loc
|
||||
elif self.scanner.on_type('integer literal'):
|
||||
value = int(self.scanner.token)
|
||||
type_ = TYPE_WORD if value > 255 else TYPE_BYTE
|
||||
loc = ConstantRef(type_, value)
|
||||
self.scanner.scan()
|
||||
return loc
|
||||
return self.literal_int_const()
|
||||
elif self.scanner.consume('word'):
|
||||
loc = ConstantRef(TYPE_WORD, int(self.scanner.token))
|
||||
self.scanner.scan()
|
||||
@ -385,7 +387,7 @@ class Parser(object):
|
||||
else:
|
||||
self.syntax_error('expected "up" or "down", found "%s"' % self.scanner.token)
|
||||
self.scanner.expect('to')
|
||||
final = self.literal_int()
|
||||
final = self.literal_int_const()
|
||||
block = self.block()
|
||||
return For(self.scanner.line_number, dest=dest, direction=direction, final=final, block=block)
|
||||
elif self.scanner.token in ("ld",):
|
||||
|
@ -351,6 +351,46 @@ The body of `repeat forever` can be empty.
|
||||
= $080D JMP $080D
|
||||
= $0810 RTS
|
||||
|
||||
Compiling `for ... up to`.
|
||||
|
||||
| byte table[256] tab
|
||||
|
|
||||
| define main routine
|
||||
| inputs tab
|
||||
| trashes a, x, c, z, v, n
|
||||
| {
|
||||
| ld x, 0
|
||||
| for x up to 15 {
|
||||
| ld a, tab + x
|
||||
| }
|
||||
| }
|
||||
= $080D LDX #$00
|
||||
= $080F LDA $0818,X
|
||||
= $0812 INX
|
||||
= $0813 CPX #$10
|
||||
= $0815 BNE $080F
|
||||
= $0817 RTS
|
||||
|
||||
Compiling `for ... down to`.
|
||||
|
||||
| byte table[256] tab
|
||||
|
|
||||
| define main routine
|
||||
| inputs tab
|
||||
| trashes a, x, c, z, v, n
|
||||
| {
|
||||
| ld x, 15
|
||||
| for x down to 0 {
|
||||
| ld a, tab + x
|
||||
| }
|
||||
| }
|
||||
= $080D LDX #$0F
|
||||
= $080F LDA $0818,X
|
||||
= $0812 DEX
|
||||
= $0813 CPX #$FF
|
||||
= $0815 BNE $080F
|
||||
= $0817 RTS
|
||||
|
||||
Indexed access.
|
||||
|
||||
| byte one
|
||||
|
Loading…
Reference in New Issue
Block a user