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:
parent
398b67cdcc
commit
4d1f9d0f3c
@ -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)
|
||||
|
@ -90,3 +90,8 @@ class For(Instr):
|
||||
|
||||
class WithInterruptsOff(Instr):
|
||||
child_attrs = ('block',)
|
||||
|
||||
|
||||
class Save(Instr):
|
||||
value_attrs = ('locations',)
|
||||
child_attrs = ('block',)
|
||||
|
@ -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)
|
||||
|
@ -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.
|
||||
|
@ -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
|
||||
|
Loading…
Reference in New Issue
Block a user