mirror of
https://github.com/catseye/SixtyPical.git
synced 2025-01-24 01:35:50 +00:00
Require that the program does ^buf to get at the address of buf.
This commit is contained in:
parent
a95cbb0f47
commit
32389e4422
@ -7,6 +7,6 @@ routine main
|
||||
trashes a, z, n, ptr
|
||||
{
|
||||
ld y, 0
|
||||
copy buf, ptr
|
||||
copy ^buf, ptr
|
||||
copy 123, [ptr] + y
|
||||
}
|
||||
|
@ -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)
|
||||
|
@ -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]
|
||||
|
@ -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.
|
||||
|
||||
|
@ -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()
|
||||
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -328,7 +328,7 @@ Buffers and pointers.
|
||||
| pointer ptr
|
||||
|
|
||||
| routine main {
|
||||
| copy buf, ptr
|
||||
| copy ^buf, ptr
|
||||
| copy 123, [ptr] + y
|
||||
| }
|
||||
= ok
|
||||
|
Loading…
x
Reference in New Issue
Block a user