From a95cbb0f47131d2c1085637f0c49827026ec21ce Mon Sep 17 00:00:00 2001 From: Chris Pressey Date: Fri, 1 Dec 2017 11:44:40 +0000 Subject: [PATCH] Introduce IndirectRef and use it instead of adhoc 'copy[]+y' opcode. --- src/sixtypical/analyzer.py | 28 ++++++++++++++-------------- src/sixtypical/compiler.py | 24 ++++++++++++------------ src/sixtypical/evaluator.py | 17 +++++++---------- src/sixtypical/model.py | 23 ++++++++++++++++++++++- src/sixtypical/parser.py | 27 ++++++++++++++------------- 5 files changed, 69 insertions(+), 50 deletions(-) diff --git a/src/sixtypical/analyzer.py b/src/sixtypical/analyzer.py index 16c83dc..60e2718 100644 --- a/src/sixtypical/analyzer.py +++ b/src/sixtypical/analyzer.py @@ -3,7 +3,7 @@ from sixtypical.ast import Program, Routine, Block, Instr from sixtypical.model import ( TYPE_BYTE, TYPE_BYTE_TABLE, BufferType, PointerType, VectorType, ExecutableType, - ConstantRef, LocationRef, + ConstantRef, LocationRef, IndirectRef, REG_A, REG_Y, FLAG_Z, FLAG_N, FLAG_V, FLAG_C ) @@ -294,7 +294,13 @@ class Analyzer(object): elif opcode == 'copy': # check that their types are compatible - if src.type == dest.type: + + if isinstance(dest, IndirectRef): + if src.type == TYPE_BYTE and isinstance(dest.ref.type, PointerType): + pass + else: + raise TypeMismatchError((src, dest)) + elif src.type == dest.type: pass elif isinstance(src.type, ExecutableType) and \ isinstance(dest.type, VectorType): @@ -316,20 +322,14 @@ class Analyzer(object): if not (src.type.trashes <= dest.type.trashes): raise IncompatibleConstraintsError(src.type.trashes - dest.type.trashes) - context.assert_meaningful(src) - context.set_written(dest) - context.set_touched(REG_A, FLAG_Z, FLAG_N) - context.set_unmeaningful(REG_A, FLAG_Z, FLAG_N) - - elif opcode == 'copy[]+y': - # check that their types are compatible - if src.type == TYPE_BYTE and isinstance(dest.type, PointerType): - pass + if isinstance(dest, IndirectRef): + context.assert_meaningful(src, REG_Y) + # TODO this will need to be more sophisticated. it's the thing ref points to that is written, not ref itself. + context.set_written(dest.ref) else: - raise TypeMismatchError((src, dest)) + context.assert_meaningful(src) + context.set_written(dest) - context.assert_meaningful(src, REG_Y) - context.set_written(dest) context.set_touched(REG_A, FLAG_Z, FLAG_N) context.set_unmeaningful(REG_A, FLAG_Z, FLAG_N) diff --git a/src/sixtypical/compiler.py b/src/sixtypical/compiler.py index 192f81f..eb5aee5 100644 --- a/src/sixtypical/compiler.py +++ b/src/sixtypical/compiler.py @@ -2,7 +2,7 @@ from sixtypical.ast import Program, Routine, Block, Instr from sixtypical.model import ( - ConstantRef, + ConstantRef, IndirectRef, TYPE_BIT, TYPE_BYTE, TYPE_WORD, BufferType, PointerType, RoutineType, VectorType, REG_A, REG_X, REG_Y, FLAG_C ) @@ -274,7 +274,17 @@ class Compiler(object): self.compile_block(instr.block) self.emitter.emit(CLI()) elif opcode == 'copy': - if src.type == TYPE_BYTE and dest.type == TYPE_BYTE: + if isinstance(dest, IndirectRef): + if src.type == TYPE_BYTE and isinstance(dest.ref.type, PointerType): + if isinstance(src, ConstantRef): + dest_label = self.labels[dest.ref.name] + self.emitter.emit(LDA(Immediate(Byte(src.value)))) + self.emitter.emit(STA(IndirectY(dest_label))) + else: + raise NotImplementedError((src, dest)) + else: + raise NotImplementedError((src, dest)) + elif src.type == TYPE_BYTE and dest.type == TYPE_BYTE: if isinstance(src, ConstantRef): raise NotImplementedError else: @@ -322,15 +332,5 @@ class Compiler(object): self.emitter.emit(STA(Absolute(Offset(dest_label, 1)))) else: raise NotImplementedError(src.type) - elif opcode == 'copy[]+y': - if src.type == TYPE_BYTE and isinstance(dest.type, PointerType): - if isinstance(src, ConstantRef): - dest_label = self.labels[dest.name] - self.emitter.emit(LDA(Immediate(Byte(src.value)))) - self.emitter.emit(STA(IndirectY(dest_label))) - else: - raise NotImplementedError((src.type, dest.type)) - else: - raise NotImplementedError((src.type, dest.type)) else: raise NotImplementedError(opcode) diff --git a/src/sixtypical/evaluator.py b/src/sixtypical/evaluator.py index b0b7a42..65feb88 100644 --- a/src/sixtypical/evaluator.py +++ b/src/sixtypical/evaluator.py @@ -2,7 +2,7 @@ from sixtypical.ast import Program, Routine, Block, Instr from sixtypical.model import ( - ConstantRef, LocationRef, PartRef, + ConstantRef, LocationRef, PartRef, IndirectRef, REG_A, REG_X, REG_Y, FLAG_Z, FLAG_N, FLAG_V, FLAG_C ) @@ -191,15 +191,12 @@ class Evaluator(object): while context.get(src) == 0: self.eval_block(instr.block, context) elif opcode == 'copy': - context.set(dest, context.get(src)) - # these are trashed; so could be anything really - context.set(REG_A, 0) - context.set(FLAG_Z, 0) - context.set(FLAG_N, 0) - elif opcode == 'copy[]': - addr = context.get(dest) - # memloc = memory[addr + context.get(REG_Y)] - # context.set(memloc, context.get(src)) + if isinstance(src, IndirectRef): + raise NotImplementedError("this doesn't actually work") + src = src.ref + if isinstance(dest, IndirectRef): + raise NotImplementedError("this doesn't actually work") + dest = dest.ref context.set(dest, context.get(src)) # these are trashed; so could be anything really context.set(REG_A, 0) diff --git a/src/sixtypical/model.py b/src/sixtypical/model.py index b8419b7..b8b636a 100644 --- a/src/sixtypical/model.py +++ b/src/sixtypical/model.py @@ -87,7 +87,7 @@ class LocationRef(Ref): # but because we store the type in here and we want to treat # these objects as immutable, we compare the types, too. # Not sure if very wise. - return isinstance(other, LocationRef) and ( + return isinstance(other, self.__class__) and ( other.name == self.name and other.type == self.type ) @@ -101,6 +101,27 @@ class LocationRef(Ref): return isinstance(self.type, RoutineType) +class IndirectRef(Ref): + def __init__(self, ref): + self.ref = ref + + def __eq__(self, other): + return self.ref == other.ref + + def __hash__(self): + return hash(hash('[]') ^ hash(self.ref)) + + def __repr__(self): + return '%s(%r)' % (self.__class__.__name__, self.ref) + + @property + def name(self): + return '[{}]+y'.format(self.ref.name) + + def is_constant(self): + return False + + class PartRef(Ref): """For 'low byte of' location and 'high byte of' location modifiers. diff --git a/src/sixtypical/parser.py b/src/sixtypical/parser.py index 68f01d6..341c8d6 100644 --- a/src/sixtypical/parser.py +++ b/src/sixtypical/parser.py @@ -4,7 +4,7 @@ from sixtypical.ast import Program, Defn, Routine, Block, Instr from sixtypical.model import ( TYPE_BIT, TYPE_BYTE, TYPE_BYTE_TABLE, TYPE_WORD, TYPE_WORD_TABLE, RoutineType, VectorType, ExecutableType, BufferType, PointerType, - LocationRef, ConstantRef + LocationRef, ConstantRef, IndirectRef, ) from sixtypical.scanner import Scanner @@ -164,6 +164,16 @@ class Parser(object): self.scanner.scan() return loc + def indlocexpr(self): + if self.scanner.consume('['): + loc = self.locexpr() + self.scanner.expect(']') + self.scanner.expect('+') + self.scanner.expect('y') + return IndirectRef(loc) + else: + return self.locexpr() + def block(self): instrs = [] self.scanner.expect('{') @@ -234,19 +244,10 @@ class Parser(object): elif self.scanner.token in ("copy",): opcode = self.scanner.token self.scanner.scan() - src = self.locexpr() + src = self.indlocexpr() self.scanner.expect(',') - if self.scanner.consume('['): - dest = self.locexpr() - self.scanner.expect(']') - self.scanner.expect('+') - self.scanner.expect('y') - opcode = 'copy[]+y' - else: - dest = self.locexpr() - i = Instr(opcode=opcode, dest=dest, src=src) - #print repr(i) - return i + dest = self.indlocexpr() + return Instr(opcode=opcode, dest=dest, src=src) elif self.scanner.consume("with"): self.scanner.expect("interrupts") self.scanner.expect("off")