mirror of
https://github.com/catseye/SixtyPical.git
synced 2024-11-25 23:49:17 +00:00
Make ld parse to a IndexedRef or IndirectRef (latter still todo.)
This commit is contained in:
parent
f87c07e52a
commit
34daad0e56
@ -1,7 +1,7 @@
|
|||||||
SixtyPical
|
SixtyPical
|
||||||
==========
|
==========
|
||||||
|
|
||||||
_Version 0.11. Work-in-progress, everything is subject to change._
|
_Version 0.12. Work-in-progress, everything is subject to change._
|
||||||
|
|
||||||
SixtyPical is a very low-level programming language, similar to 6502 assembly,
|
SixtyPical is a very low-level programming language, similar to 6502 assembly,
|
||||||
with static analysis through abstract interpretation.
|
with static analysis through abstract interpretation.
|
||||||
|
@ -127,6 +127,9 @@ class Context(object):
|
|||||||
if kwargs.get('message'):
|
if kwargs.get('message'):
|
||||||
message += ' (%s)' % kwargs['message']
|
message += ' (%s)' % kwargs['message']
|
||||||
raise exception_class(message)
|
raise exception_class(message)
|
||||||
|
elif isinstance(ref, IndexedRef):
|
||||||
|
self.assert_meaningful(ref.ref, **kwargs)
|
||||||
|
self.assert_meaningful(ref.index, **kwargs)
|
||||||
else:
|
else:
|
||||||
raise NotImplementedError(ref)
|
raise NotImplementedError(ref)
|
||||||
|
|
||||||
@ -236,14 +239,16 @@ class Analyzer(object):
|
|||||||
src = instr.src
|
src = instr.src
|
||||||
|
|
||||||
if opcode == 'ld':
|
if opcode == 'ld':
|
||||||
if instr.index:
|
if isinstance(src, IndexedRef):
|
||||||
if TableType.is_a_table_type(src.type, TYPE_BYTE) and dest.type == TYPE_BYTE:
|
if TableType.is_a_table_type(src.ref.type, TYPE_BYTE) and dest.type == TYPE_BYTE:
|
||||||
pass
|
pass
|
||||||
else:
|
else:
|
||||||
raise TypeMismatchError('%s and %s in %s' %
|
raise TypeMismatchError('%s and %s in %s' %
|
||||||
(src.name, dest.name, self.current_routine.name)
|
(src.ref.name, dest.name, self.current_routine.name)
|
||||||
)
|
)
|
||||||
context.assert_meaningful(instr.index)
|
context.assert_meaningful(src.index)
|
||||||
|
elif isinstance(src, IndirectRef):
|
||||||
|
raise NotImplementedError
|
||||||
elif src.type != dest.type:
|
elif src.type != dest.type:
|
||||||
raise TypeMismatchError('%s and %s in %s' %
|
raise TypeMismatchError('%s and %s in %s' %
|
||||||
(src.name, dest.name, self.current_routine.name)
|
(src.name, dest.name, self.current_routine.name)
|
||||||
@ -352,6 +357,9 @@ class Analyzer(object):
|
|||||||
context.assert_meaningful(src)
|
context.assert_meaningful(src)
|
||||||
|
|
||||||
elif opcode == 'copy':
|
elif opcode == 'copy':
|
||||||
|
if dest == REG_A:
|
||||||
|
raise ForbiddenWriteError("{} cannot be used as destination for copy".format(dest))
|
||||||
|
|
||||||
# 1. check that their types are compatible
|
# 1. check that their types are compatible
|
||||||
|
|
||||||
if isinstance(src, AddressRef) and isinstance(dest, LocationRef):
|
if isinstance(src, AddressRef) and isinstance(dest, LocationRef):
|
||||||
|
@ -131,9 +131,9 @@ class Compiler(object):
|
|||||||
self.emitter.emit(TYA())
|
self.emitter.emit(TYA())
|
||||||
elif isinstance(src, ConstantRef):
|
elif isinstance(src, ConstantRef):
|
||||||
self.emitter.emit(LDA(Immediate(Byte(src.value))))
|
self.emitter.emit(LDA(Immediate(Byte(src.value))))
|
||||||
elif instr.index == REG_X:
|
elif isinstance(src, IndexedRef) and src.index == REG_X:
|
||||||
self.emitter.emit(LDA(AbsoluteX(self.labels[src.name])))
|
self.emitter.emit(LDA(AbsoluteX(self.labels[src.name])))
|
||||||
elif instr.index == REG_Y:
|
elif isinstance(src, IndexedRef) and src.index == REG_Y:
|
||||||
self.emitter.emit(LDA(AbsoluteY(self.labels[src.name])))
|
self.emitter.emit(LDA(AbsoluteY(self.labels[src.name])))
|
||||||
else:
|
else:
|
||||||
self.emitter.emit(LDA(Absolute(self.labels[src.name])))
|
self.emitter.emit(LDA(Absolute(self.labels[src.name])))
|
||||||
@ -142,7 +142,7 @@ class Compiler(object):
|
|||||||
self.emitter.emit(TAX())
|
self.emitter.emit(TAX())
|
||||||
elif isinstance(src, ConstantRef):
|
elif isinstance(src, ConstantRef):
|
||||||
self.emitter.emit(LDX(Immediate(Byte(src.value))))
|
self.emitter.emit(LDX(Immediate(Byte(src.value))))
|
||||||
elif instr.index == REG_Y:
|
elif isinstance(src, IndexedRef) and src.index == REG_Y:
|
||||||
self.emitter.emit(LDX(AbsoluteY(self.labels[src.name])))
|
self.emitter.emit(LDX(AbsoluteY(self.labels[src.name])))
|
||||||
else:
|
else:
|
||||||
self.emitter.emit(LDX(Absolute(self.labels[src.name])))
|
self.emitter.emit(LDX(Absolute(self.labels[src.name])))
|
||||||
@ -151,7 +151,7 @@ class Compiler(object):
|
|||||||
self.emitter.emit(TAY())
|
self.emitter.emit(TAY())
|
||||||
elif isinstance(src, ConstantRef):
|
elif isinstance(src, ConstantRef):
|
||||||
self.emitter.emit(LDY(Immediate(Byte(src.value))))
|
self.emitter.emit(LDY(Immediate(Byte(src.value))))
|
||||||
elif instr.index == REG_X:
|
elif isinstance(src, IndexedRef) and src.index == REG_X:
|
||||||
self.emitter.emit(LDY(AbsoluteX(self.labels[src.name])))
|
self.emitter.emit(LDY(AbsoluteX(self.labels[src.name])))
|
||||||
else:
|
else:
|
||||||
self.emitter.emit(LDY(Absolute(self.labels[src.name])))
|
self.emitter.emit(LDY(Absolute(self.labels[src.name])))
|
||||||
|
@ -202,7 +202,8 @@ class IndexedRef(Ref):
|
|||||||
|
|
||||||
@property
|
@property
|
||||||
def name(self):
|
def name(self):
|
||||||
return '{}+{}'.format(self.ref.name, self.index.name)
|
return self.ref.name
|
||||||
|
#return '{}+{}'.format(self.ref.name, self.index.name)
|
||||||
|
|
||||||
def is_constant(self):
|
def is_constant(self):
|
||||||
return False
|
return False
|
||||||
|
@ -316,7 +316,15 @@ class Parser(object):
|
|||||||
self.scanner.expect('forever')
|
self.scanner.expect('forever')
|
||||||
return Instr(opcode='repeat', dest=None, src=src,
|
return Instr(opcode='repeat', dest=None, src=src,
|
||||||
block=block, inverted=inverted)
|
block=block, inverted=inverted)
|
||||||
elif self.scanner.token in ("ld", "add", "sub", "cmp", "and", "or", "xor"):
|
elif self.scanner.token in ("ld",):
|
||||||
|
# the same as add, sub, cmp etc below, except supports an indlocexpr for the src
|
||||||
|
opcode = self.scanner.token
|
||||||
|
self.scanner.scan()
|
||||||
|
dest = self.locexpr()
|
||||||
|
self.scanner.expect(',')
|
||||||
|
src = self.indlocexpr()
|
||||||
|
return Instr(opcode=opcode, dest=dest, src=src, index=None)
|
||||||
|
elif self.scanner.token in ("add", "sub", "cmp", "and", "or", "xor"):
|
||||||
opcode = self.scanner.token
|
opcode = self.scanner.token
|
||||||
self.scanner.scan()
|
self.scanner.scan()
|
||||||
dest = self.locexpr()
|
dest = self.locexpr()
|
||||||
|
@ -1462,6 +1462,21 @@ Can `copy` from a `byte` to a `byte`.
|
|||||||
| }
|
| }
|
||||||
= ok
|
= ok
|
||||||
|
|
||||||
|
The understanding is that, because `copy` trashes `a`, `a` cannot be used
|
||||||
|
as the destination of a `copy`.
|
||||||
|
|
||||||
|
| byte source : 0
|
||||||
|
| byte dest
|
||||||
|
|
|
||||||
|
| routine main
|
||||||
|
| inputs source
|
||||||
|
| outputs dest
|
||||||
|
| trashes a, z, n
|
||||||
|
| {
|
||||||
|
| copy source, a
|
||||||
|
| }
|
||||||
|
? ForbiddenWriteError
|
||||||
|
|
||||||
Can `copy` from a `word` to a `word`.
|
Can `copy` from a `word` to a `word`.
|
||||||
|
|
||||||
| word source : 0
|
| word source : 0
|
||||||
@ -1504,9 +1519,7 @@ Can't `copy` from a `word` to a `byte`.
|
|||||||
| }
|
| }
|
||||||
? TypeMismatchError
|
? TypeMismatchError
|
||||||
|
|
||||||
### copy[] ###
|
### Buffers and pointers ###
|
||||||
|
|
||||||
Buffers and pointers.
|
|
||||||
|
|
||||||
Note that `^buf` is a constant value, so it by itself does not require `buf` to be
|
Note that `^buf` is a constant value, so it by itself does not require `buf` to be
|
||||||
listed in any input/output sets.
|
listed in any input/output sets.
|
||||||
@ -1588,6 +1601,24 @@ Read through a pointer.
|
|||||||
| }
|
| }
|
||||||
= ok
|
= ok
|
||||||
|
|
||||||
|
Read through a pointer to the `a` register. Note that
|
||||||
|
this is done with `ld`, not `copy`.
|
||||||
|
|
||||||
|
| buffer[2048] buf
|
||||||
|
| pointer ptr
|
||||||
|
| byte foo
|
||||||
|
|
|
||||||
|
| routine main
|
||||||
|
| inputs buf
|
||||||
|
| outputs foo
|
||||||
|
| trashes a, y, z, n, ptr
|
||||||
|
| {
|
||||||
|
| ld y, 0
|
||||||
|
| copy ^buf, ptr
|
||||||
|
| ld a, [ptr] + y
|
||||||
|
| }
|
||||||
|
= ok
|
||||||
|
|
||||||
### routines ###
|
### routines ###
|
||||||
|
|
||||||
Routines are constants. You need not, and in fact cannot, specify a constant
|
Routines are constants. You need not, and in fact cannot, specify a constant
|
||||||
|
@ -846,7 +846,7 @@ Read through a pointer, into a byte storage location, or the `a` register.
|
|||||||
| ld y, 0
|
| ld y, 0
|
||||||
| copy ^buf, ptr
|
| copy ^buf, ptr
|
||||||
| copy [ptr] + y, foo
|
| copy [ptr] + y, foo
|
||||||
| copy [ptr] + y, a
|
| ld a, [ptr] + y
|
||||||
| }
|
| }
|
||||||
= $080D LDY #$00
|
= $080D LDY #$00
|
||||||
= $080F LDA #$1F
|
= $080F LDA #$1F
|
||||||
|
Loading…
Reference in New Issue
Block a user