mirror of
https://github.com/catseye/SixtyPical.git
synced 2025-01-09 10:30:13 +00:00
First cut at implementing save
. Only the most basic tests though.
This commit is contained in:
parent
398b67cdcc
commit
4d1f9d0f3c
@ -1,6 +1,6 @@
|
|||||||
# encoding: UTF-8
|
# encoding: UTF-8
|
||||||
|
|
||||||
from sixtypical.ast import Program, Routine, Block, Instr, SingleOp, If, Repeat, For, WithInterruptsOff
|
from sixtypical.ast import Program, Routine, Block, Instr, SingleOp, If, Repeat, For, WithInterruptsOff, Save
|
||||||
from sixtypical.model import (
|
from sixtypical.model import (
|
||||||
TYPE_BYTE, TYPE_WORD,
|
TYPE_BYTE, TYPE_WORD,
|
||||||
TableType, BufferType, PointerType, VectorType, RoutineType,
|
TableType, BufferType, PointerType, VectorType, RoutineType,
|
||||||
@ -269,7 +269,7 @@ class Context(object):
|
|||||||
self._writeable.remove(ref)
|
self._writeable.remove(ref)
|
||||||
|
|
||||||
def set_writeable(self, *refs):
|
def set_writeable(self, *refs):
|
||||||
"""Intended to be used for implementing analyzing `for`."""
|
"""Intended to be used for implementing analyzing `for`, but also used in `save`."""
|
||||||
for ref in refs:
|
for ref in refs:
|
||||||
self._writeable.add(ref)
|
self._writeable.add(ref)
|
||||||
|
|
||||||
@ -292,6 +292,41 @@ class Context(object):
|
|||||||
self.assert_in_range(dest.index, dest.ref)
|
self.assert_in_range(dest.index, dest.ref)
|
||||||
self.set_written(dest.ref)
|
self.set_written(dest.ref)
|
||||||
|
|
||||||
|
def extract(self, location):
|
||||||
|
"""Used in `save`."""
|
||||||
|
baton = (
|
||||||
|
location,
|
||||||
|
location in self._touched,
|
||||||
|
self._range.get(location, None),
|
||||||
|
location in self._writeable,
|
||||||
|
)
|
||||||
|
|
||||||
|
if location in self._touched:
|
||||||
|
self._touched.remove(location)
|
||||||
|
self.set_unmeaningful(location)
|
||||||
|
self.set_writeable(location)
|
||||||
|
|
||||||
|
return baton
|
||||||
|
|
||||||
|
def re_introduce(self, baton):
|
||||||
|
"""Used in `save`."""
|
||||||
|
location, was_touched, was_range, was_writeable = baton
|
||||||
|
|
||||||
|
if was_touched:
|
||||||
|
self._touched.add(location)
|
||||||
|
elif location in self._touched:
|
||||||
|
self._touched.remove(location)
|
||||||
|
|
||||||
|
if was_range is not None:
|
||||||
|
self._range[location] = was_range
|
||||||
|
elif location in self._range:
|
||||||
|
del self._range[location]
|
||||||
|
|
||||||
|
if was_writeable:
|
||||||
|
self._writeable.add(location)
|
||||||
|
elif location in self._writeable:
|
||||||
|
self._writeable.remove(location)
|
||||||
|
|
||||||
|
|
||||||
class Analyzer(object):
|
class Analyzer(object):
|
||||||
|
|
||||||
@ -385,6 +420,8 @@ class Analyzer(object):
|
|||||||
self.analyze_for(instr, context)
|
self.analyze_for(instr, context)
|
||||||
elif isinstance(instr, WithInterruptsOff):
|
elif isinstance(instr, WithInterruptsOff):
|
||||||
self.analyze_block(instr.block, context)
|
self.analyze_block(instr.block, context)
|
||||||
|
elif isinstance(instr, Save):
|
||||||
|
self.analyze_save(instr, context)
|
||||||
else:
|
else:
|
||||||
raise NotImplementedError
|
raise NotImplementedError
|
||||||
|
|
||||||
@ -730,3 +767,13 @@ class Analyzer(object):
|
|||||||
# after it is executed, we know the range of the loop variable.
|
# after it is executed, we know the range of the loop variable.
|
||||||
context.set_range(instr.dest, instr.final, instr.final)
|
context.set_range(instr.dest, instr.final, instr.final)
|
||||||
context.set_writeable(instr.dest)
|
context.set_writeable(instr.dest)
|
||||||
|
|
||||||
|
def analyze_save(self, instr, context):
|
||||||
|
if len(instr.locations) != 1:
|
||||||
|
raise NotImplementedError("Only 1 location in save is supported right now")
|
||||||
|
location = instr.locations[0]
|
||||||
|
|
||||||
|
baton = context.extract(location)
|
||||||
|
self.analyze_block(instr.block, context)
|
||||||
|
# TODO assert no goto was encountered
|
||||||
|
context.re_introduce(baton)
|
||||||
|
@ -90,3 +90,8 @@ class For(Instr):
|
|||||||
|
|
||||||
class WithInterruptsOff(Instr):
|
class WithInterruptsOff(Instr):
|
||||||
child_attrs = ('block',)
|
child_attrs = ('block',)
|
||||||
|
|
||||||
|
|
||||||
|
class Save(Instr):
|
||||||
|
value_attrs = ('locations',)
|
||||||
|
child_attrs = ('block',)
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
# encoding: UTF-8
|
# encoding: UTF-8
|
||||||
|
|
||||||
from sixtypical.ast import Program, Defn, Routine, Block, SingleOp, If, Repeat, For, WithInterruptsOff
|
from sixtypical.ast import Program, Defn, Routine, Block, SingleOp, If, Repeat, For, WithInterruptsOff, Save
|
||||||
from sixtypical.model import (
|
from sixtypical.model import (
|
||||||
TYPE_BIT, TYPE_BYTE, TYPE_WORD,
|
TYPE_BIT, TYPE_BYTE, TYPE_WORD,
|
||||||
RoutineType, VectorType, TableType, BufferType, PointerType,
|
RoutineType, VectorType, TableType, BufferType, PointerType,
|
||||||
@ -470,6 +470,10 @@ class Parser(object):
|
|||||||
self.scanner.expect("off")
|
self.scanner.expect("off")
|
||||||
block = self.block()
|
block = self.block()
|
||||||
return WithInterruptsOff(self.scanner.line_number, block=block)
|
return WithInterruptsOff(self.scanner.line_number, block=block)
|
||||||
|
elif self.scanner.consume("save"):
|
||||||
|
locations = self.locexprs()
|
||||||
|
block = self.block()
|
||||||
|
return Save(self.scanner.line_number, locations=locations, block=block)
|
||||||
elif self.scanner.consume("trash"):
|
elif self.scanner.consume("trash"):
|
||||||
dest = self.locexpr()
|
dest = self.locexpr()
|
||||||
return SingleOp(self.scanner.line_number, opcode='trash', src=None, dest=dest)
|
return SingleOp(self.scanner.line_number, opcode='trash', src=None, dest=dest)
|
||||||
|
@ -1938,6 +1938,21 @@ initialized at the start of that loop.
|
|||||||
| }
|
| }
|
||||||
? UnmeaningfulReadError: y
|
? UnmeaningfulReadError: y
|
||||||
|
|
||||||
|
### save ###
|
||||||
|
|
||||||
|
Basic neutral test.
|
||||||
|
|
||||||
|
| routine main
|
||||||
|
| inputs a, x
|
||||||
|
| outputs a, x
|
||||||
|
| trashes z, n
|
||||||
|
| {
|
||||||
|
| save x {
|
||||||
|
| ld a, 0
|
||||||
|
| }
|
||||||
|
| }
|
||||||
|
= ok
|
||||||
|
|
||||||
### copy ###
|
### copy ###
|
||||||
|
|
||||||
Can't `copy` from a memory location that isn't initialized.
|
Can't `copy` from a memory location that isn't initialized.
|
||||||
|
@ -161,6 +161,20 @@ Basic "open-faced for" loops, up and down.
|
|||||||
| }
|
| }
|
||||||
= ok
|
= ok
|
||||||
|
|
||||||
|
Other blocks.
|
||||||
|
|
||||||
|
| routine main trashes a, x, c, z, v {
|
||||||
|
| with interrupts off {
|
||||||
|
| save a, x, c {
|
||||||
|
| ld a, 0
|
||||||
|
| }
|
||||||
|
| }
|
||||||
|
| save a, x, c {
|
||||||
|
| ld a, 0
|
||||||
|
| }
|
||||||
|
| }
|
||||||
|
= ok
|
||||||
|
|
||||||
User-defined memory addresses of different types.
|
User-defined memory addresses of different types.
|
||||||
|
|
||||||
| byte byt
|
| byte byt
|
||||||
|
Loading…
Reference in New Issue
Block a user