diff --git a/eg/buffer.60p b/eg/buffer.60p index 5b63103..8783a11 100644 --- a/eg/buffer.60p +++ b/eg/buffer.60p @@ -7,6 +7,6 @@ routine main trashes a, z, n, ptr { ld y, 0 - copy buf, ptr + copy ^buf, ptr copy 123, [ptr] + y } diff --git a/src/sixtypical/analyzer.py b/src/sixtypical/analyzer.py index 60e2718..7f61bd5 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, IndirectRef, + ConstantRef, LocationRef, IndirectRef, AddressRef, REG_A, REG_Y, FLAG_Z, FLAG_N, FLAG_V, FLAG_C ) @@ -113,7 +113,7 @@ class Context(object): def assert_meaningful(self, *refs, **kwargs): exception_class = kwargs.get('exception_class', UnmeaningfulReadError) for ref in refs: - if isinstance(ref, ConstantRef) or ref in self.routines: + if ref.is_constant() or ref in self.routines: pass elif isinstance(ref, LocationRef): if ref not in self._meaningful: @@ -293,34 +293,38 @@ class Analyzer(object): context.assert_meaningful(src) elif opcode == 'copy': - # check that their types are compatible + # 1. check that their types are compatible 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): - pass - elif isinstance(src.type, BufferType) and \ - isinstance(dest.type, PointerType): - pass + elif isinstance(src, AddressRef): + if isinstance(src.ref.type, BufferType) and isinstance(dest.type, PointerType): + pass + else: + raise TypeMismatchError((src, dest)) + + elif isinstance(src, (LocationRef, ConstantRef)) and isinstance(dest, LocationRef): + if src.type == dest.type: + pass + elif isinstance(src.type, ExecutableType) and \ + isinstance(dest.type, VectorType): + # if dealing with routines and vectors, + # check that they're not incompatible + if not (src.type.inputs <= dest.type.inputs): + raise IncompatibleConstraintsError(src.type.inputs - dest.type.inputs) + if not (src.type.outputs <= dest.type.outputs): + raise IncompatibleConstraintsError(src.type.outputs - dest.type.outputs) + if not (src.type.trashes <= dest.type.trashes): + raise IncompatibleConstraintsError(src.type.trashes - dest.type.trashes) + else: + raise TypeMismatchError((src, dest)) else: raise TypeMismatchError((src, dest)) - # if dealing with routines and vectors, - # check that they're not incompatible - if isinstance(src.type, ExecutableType) and \ - isinstance(dest.type, VectorType): - if not (src.type.inputs <= dest.type.inputs): - raise IncompatibleConstraintsError(src.type.inputs - dest.type.inputs) - if not (src.type.outputs <= dest.type.outputs): - raise IncompatibleConstraintsError(src.type.outputs - dest.type.outputs) - if not (src.type.trashes <= dest.type.trashes): - raise IncompatibleConstraintsError(src.type.trashes - dest.type.trashes) + # 2. check that the context is meaningful if isinstance(dest, IndirectRef): context.assert_meaningful(src, REG_Y) diff --git a/src/sixtypical/compiler.py b/src/sixtypical/compiler.py index eb5aee5..c4f8495 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, IndirectRef, + ConstantRef, LocationRef, IndirectRef, AddressRef, TYPE_BIT, TYPE_BYTE, TYPE_WORD, BufferType, PointerType, RoutineType, VectorType, REG_A, REG_X, REG_Y, FLAG_C ) @@ -284,6 +284,16 @@ class Compiler(object): raise NotImplementedError((src, dest)) else: raise NotImplementedError((src, dest)) + elif isinstance(src, AddressRef) and isinstance(dest, LocationRef) and \ + isinstance(src.ref.type, BufferType) and isinstance(dest.type, PointerType): + src_label = self.labels[src.ref.name] + dest_label = self.labels[dest.name] + self.emitter.emit(LDA(Immediate(HighAddressByte(src_label)))) + self.emitter.emit(STA(ZeroPage(dest_label))) + self.emitter.emit(LDA(Immediate(LowAddressByte(src_label)))) + self.emitter.emit(STA(ZeroPage(Offset(dest_label, 1)))) + elif not isinstance(src, (ConstantRef, LocationRef)) or not isinstance(dest, LocationRef): + raise NotImplementedError((src, dest)) elif src.type == TYPE_BYTE and dest.type == TYPE_BYTE: if isinstance(src, ConstantRef): raise NotImplementedError @@ -308,14 +318,6 @@ class Compiler(object): self.emitter.emit(STA(Absolute(dest_label))) self.emitter.emit(LDA(Absolute(Offset(src_label, 1)))) self.emitter.emit(STA(Absolute(Offset(dest_label, 1)))) - elif isinstance(src.type, BufferType) and isinstance(dest.type, PointerType): - # TODO: this maybe should not be the 'copy' opcode at all that means this - src_label = self.labels[src.name] - dest_label = self.labels[dest.name] - self.emitter.emit(LDA(Immediate(HighAddressByte(src_label)))) - self.emitter.emit(STA(ZeroPage(dest_label))) - self.emitter.emit(LDA(Immediate(LowAddressByte(src_label)))) - self.emitter.emit(STA(ZeroPage(Offset(dest_label, 1)))) elif isinstance(src.type, VectorType) and isinstance(dest.type, VectorType): src_label = self.labels[src.name] dest_label = self.labels[dest.name] diff --git a/src/sixtypical/model.py b/src/sixtypical/model.py index b8b636a..449285b 100644 --- a/src/sixtypical/model.py +++ b/src/sixtypical/model.py @@ -109,7 +109,7 @@ class IndirectRef(Ref): return self.ref == other.ref def __hash__(self): - return hash(hash('[]') ^ hash(self.ref)) + return hash(self.__class__.name) ^ hash(self.ref) def __repr__(self): return '%s(%r)' % (self.__class__.__name__, self.ref) @@ -122,6 +122,27 @@ class IndirectRef(Ref): return False +class AddressRef(Ref): + def __init__(self, ref): + self.ref = ref + + def __eq__(self, other): + return self.ref == other.ref + + def __hash__(self): + return hash(self.__class__.name) ^ hash(self.ref) + + def __repr__(self): + return '%s(%r)' % (self.__class__.__name__, self.ref) + + @property + def name(self): + return '^{}'.format(self.ref.name) + + def is_constant(self): + return True + + 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 341c8d6..872070d 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, IndirectRef, + LocationRef, ConstantRef, IndirectRef, AddressRef, ) from sixtypical.scanner import Scanner @@ -171,6 +171,9 @@ class Parser(object): self.scanner.expect('+') self.scanner.expect('y') return IndirectRef(loc) + elif self.scanner.consume('^'): + loc = self.locexpr() + return AddressRef(loc) else: return self.locexpr() diff --git a/src/sixtypical/scanner.py b/src/sixtypical/scanner.py index 3663e9c..fd48b3b 100644 --- a/src/sixtypical/scanner.py +++ b/src/sixtypical/scanner.py @@ -29,7 +29,7 @@ class Scanner(object): self.token = None self.type = 'EOF' return - if self.scan_pattern(r'\,|\@|\+|\:|\<|\>|\{|\}|\[|\]', 'operator'): + if self.scan_pattern(r'\,|\@|\+|\:|\<|\>|\{|\}|\[|\]|\^', 'operator'): return if self.scan_pattern(r'\d+', 'integer literal'): return diff --git a/tests/SixtyPical Analysis.md b/tests/SixtyPical Analysis.md index 4b48df9..31b8186 100644 --- a/tests/SixtyPical Analysis.md +++ b/tests/SixtyPical Analysis.md @@ -1176,19 +1176,18 @@ Can't `copy` from a `word` to a `byte`. Buffers and pointers. -Note that `copy buf, ptr` should probably be `copy ^buf, ptr` and `^buf` should not -be considered "reading" buf and should not require it in `inputs` for that reason. +Note that `^buf` is not considered "reading" buf, so does not require it in `inputs`. +TODO: It *should* require it in `outputs`. | buffer[2048] buf | pointer ptr | | routine main - | inputs buf - | outputs buf, y + | outputs y | trashes a, z, n, ptr | { | ld y, 0 - | copy buf, ptr + | copy ^buf, ptr | copy 123, [ptr] + y | } = ok @@ -1199,11 +1198,9 @@ It does use `y`. | pointer ptr | | routine main - | inputs buf - | outputs buf | trashes a, z, n, ptr | { - | copy buf, ptr + | copy ^buf, ptr | copy 123, [ptr] + y | } ? UnmeaningfulReadError diff --git a/tests/SixtyPical Compilation.md b/tests/SixtyPical Compilation.md index 5e2df28..95d6785 100644 --- a/tests/SixtyPical Compilation.md +++ b/tests/SixtyPical Compilation.md @@ -353,7 +353,7 @@ Buffers and pointers. | trashes a, z, n, ptr | { | ld y, 0 - | copy buf, ptr + | copy ^buf, ptr | } = 00c0a000a90b85fea9c085ff60 @@ -363,12 +363,11 @@ Writing through a pointer. | pointer ptr @ 254 | | routine main - | inputs buf | outputs buf, y | trashes a, z, n, ptr | { | ld y, 0 - | copy buf, ptr + | copy ^buf, ptr | copy 123, [ptr] + y | } = 00c0a000a90f85fea9c085ffa97b91fe60 diff --git a/tests/SixtyPical Syntax.md b/tests/SixtyPical Syntax.md index 66c761f..b6f4fc0 100644 --- a/tests/SixtyPical Syntax.md +++ b/tests/SixtyPical Syntax.md @@ -328,7 +328,7 @@ Buffers and pointers. | pointer ptr | | routine main { - | copy buf, ptr + | copy ^buf, ptr | copy 123, [ptr] + y | } = ok