1
0
mirror of https://github.com/catseye/SixtyPical.git synced 2025-01-08 19:30:29 +00:00

First cut at implementing save. Only the most basic tests though.

This commit is contained in:
Chris Pressey 2018-04-19 13:18:52 +01:00
parent 398b67cdcc
commit 4d1f9d0f3c
5 changed files with 88 additions and 3 deletions

View File

@ -1,6 +1,6 @@
# 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 (
TYPE_BYTE, TYPE_WORD,
TableType, BufferType, PointerType, VectorType, RoutineType,
@ -269,7 +269,7 @@ class Context(object):
self._writeable.remove(ref)
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:
self._writeable.add(ref)
@ -292,6 +292,41 @@ class Context(object):
self.assert_in_range(dest.index, 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):
@ -385,6 +420,8 @@ class Analyzer(object):
self.analyze_for(instr, context)
elif isinstance(instr, WithInterruptsOff):
self.analyze_block(instr.block, context)
elif isinstance(instr, Save):
self.analyze_save(instr, context)
else:
raise NotImplementedError
@ -730,3 +767,13 @@ class Analyzer(object):
# after it is executed, we know the range of the loop variable.
context.set_range(instr.dest, instr.final, instr.final)
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)

View File

@ -90,3 +90,8 @@ class For(Instr):
class WithInterruptsOff(Instr):
child_attrs = ('block',)
class Save(Instr):
value_attrs = ('locations',)
child_attrs = ('block',)

View File

@ -1,6 +1,6 @@
# 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 (
TYPE_BIT, TYPE_BYTE, TYPE_WORD,
RoutineType, VectorType, TableType, BufferType, PointerType,
@ -470,6 +470,10 @@ class Parser(object):
self.scanner.expect("off")
block = self.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"):
dest = self.locexpr()
return SingleOp(self.scanner.line_number, opcode='trash', src=None, dest=dest)

View File

@ -1938,6 +1938,21 @@ initialized at the start of that loop.
| }
? UnmeaningfulReadError: y
### save ###
Basic neutral test.
| routine main
| inputs a, x
| outputs a, x
| trashes z, n
| {
| save x {
| ld a, 0
| }
| }
= ok
### copy ###
Can't `copy` from a memory location that isn't initialized.

View File

@ -161,6 +161,20 @@ Basic "open-faced for" loops, up and down.
| }
= 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.
| byte byt