1
0
mirror of https://github.com/catseye/SixtyPical.git synced 2024-11-25 23:49:17 +00:00

Refs have types.

This commit is contained in:
Chris Pressey 2015-10-18 17:23:01 +01:00
parent 4990493b11
commit e1cf162a5b
5 changed files with 88 additions and 40 deletions

View File

@ -36,20 +36,20 @@ class UsageClashError(StaticAnalysisError):
class Context():
def __init__(self, inputs, outputs, trashes):
self._store = {}
self._store = {} # Ref -> INITALIZED/UNINITIALIZED
self._writeables = set()
for ref in inputs:
self._store.setdefault(ref.name, INITIALIZED)
self._store.setdefault(ref, INITIALIZED)
output_names = set()
for ref in outputs:
output_names.add(ref.name)
self._store.setdefault(ref.name, UNINITIALIZED)
self._store.setdefault(ref, UNINITIALIZED)
self._writeables.add(ref.name)
for ref in trashes:
if ref.name in output_names:
raise UsageClashError(ref.name)
self._store.setdefault(ref.name, UNINITIALIZED)
self._store.setdefault(ref, UNINITIALIZED)
self._writeables.add(ref.name)
def clone(self):
@ -65,7 +65,7 @@ class Context():
def each_initialized(self):
for key, value in self._store.iteritems():
if value == INITIALIZED:
yield LocationRef(key)
yield key
def assert_initialized(self, *refs, **kwargs):
exception_class = kwargs.get('exception_class', UninitializedAccessError)
@ -95,15 +95,15 @@ class Context():
if isinstance(ref, ConstantRef):
return INITIALIZED
elif isinstance(ref, LocationRef):
if ref.name not in self._store:
if ref not in self._store:
return UNINITIALIZED
return self._store[ref.name]
return self._store[ref]
else:
raise ValueError(ref)
def set(self, ref, value):
assert isinstance(ref, LocationRef)
self._store[ref.name] = value
self._store[ref] = value
def analyze_program(program):

View File

@ -3,6 +3,7 @@
from sixtypical.ast import Program, Routine, Block, Instr
from sixtypical.model import (
ConstantRef, LocationRef,
TYPE_BIT,
REG_A, REG_X, REG_Y, FLAG_Z, FLAG_N, FLAG_V, FLAG_C
)
from sixtypical.emitter import Label, Byte
@ -99,9 +100,9 @@ class Compiler(object):
else:
raise UnsupportedOpcodeError(instr)
elif opcode == 'st':
if dest == FLAG_C and src == ConstantRef(0):
if dest == FLAG_C and src == ConstantRef(TYPE_BIT, 0):
self.emitter.emit(CLC())
elif dest == FLAG_C and src == ConstantRef(1):
elif dest == FLAG_C and src == ConstantRef(TYPE_BIT, 1):
self.emitter.emit(SEC())
elif src == REG_A:
self.emitter.emit(STA(Absolute(self.labels[dest.name])))

View File

@ -1,36 +1,74 @@
"""Data/storage model for SixtyPical."""
class LocationRef(object):
class Type(object):
def __init__(self, name):
self.name = name
def __repr__(self):
return 'LocationRef(%r)' % self.name
return 'Type(%r)' % self.name
def __eq__(self, other):
return isinstance(other, LocationRef) and other.name == self.name
return isinstance(other, Type) and other.name == self.name
def __hash__(self):
return hash(self.name)
class ConstantRef(object):
def __init__(self, value):
TYPE_BIT = Type('bit')
TYPE_BYTE = Type('byte')
TYPE_BYTE_TABLE = Type('byte table')
class Ref(object):
pass
class LocationRef(Ref):
def __init__(self, type, name):
self.type = type
self.name = name
def __eq__(self, other):
# Ordinarily there will only be one ref with a given name,
# but because we store the type in here and we want to treat
# these objects as immutable, we compare the types, too.
# Not sure if very wise.
return isinstance(other, LocationRef) and (
other.name == self.name and other.type == self.type
)
def __hash__(self):
return hash(self.name + str(self.type))
def __repr__(self):
return '%s(%r, %r)' % (self.__class__.__name__, self.type, self.name)
class ConstantRef(Ref):
def __init__(self, type, value):
self.type = type
self.value = value
def __repr__(self):
return 'ConstantRef(%r)' % self.value
def __eq__(self, other):
return isinstance(other, ConstantRef) and other.value == self.value
return isinstance(other, ConstantRef) and (
other.type == self.type and other.value == self.value
)
def __hash__(self):
return hash(str(self.value) + str(self.type))
def __repr__(self):
return '%s(%r, %r)' % (self.__class__.__name__, self.type, self.value)
# TODO type=byte
REG_A = LocationRef(TYPE_BYTE, 'a')
REG_X = LocationRef(TYPE_BYTE, 'x')
REG_Y = LocationRef(TYPE_BYTE, 'y')
REG_A = LocationRef('a')
REG_X = LocationRef('x')
REG_Y = LocationRef('y')
# TODO type=bit
FLAG_Z = LocationRef('z')
FLAG_C = LocationRef('c')
FLAG_N = LocationRef('n')
FLAG_V = LocationRef('v')
FLAG_Z = LocationRef(TYPE_BIT, 'z')
FLAG_C = LocationRef(TYPE_BIT, 'c')
FLAG_N = LocationRef(TYPE_BIT, 'n')
FLAG_V = LocationRef(TYPE_BIT, 'v')

View File

@ -3,7 +3,9 @@
import re
from sixtypical.ast import Program, Defn, Routine, Block, Instr
from sixtypical.model import LocationRef, ConstantRef
from sixtypical.model import (
TYPE_BIT, TYPE_BYTE, LocationRef, ConstantRef
)
class Scanner(object):
@ -70,16 +72,19 @@ class Scanner(object):
return False
class SymEntry(object):
def __init__(self, ast_node, model):
self.ast_node = ast_node
self.model = model
class Parser(object):
def __init__(self, text):
self.scanner = Scanner(text)
self.symbols = {}
self.symbols = {} # token -> SymEntry
def lookup(self, name):
if name in self.symbols:
return LocationRef(name)
else:
raise KeyError(name)
return self.symbols[name].model
def program(self):
defns = []
@ -89,14 +94,14 @@ class Parser(object):
name = defn.name
if name in self.symbols:
raise KeyError(name)
self.symbols[name] = defn
self.symbols[name] = SymEntry(defn, LocationRef(TYPE_BYTE, name))
defns.append(defn)
while self.scanner.on('routine'):
routine = self.routine()
name = routine.name
if name in self.symbols:
raise KeyError(name)
self.symbols[name] = routine
self.symbols[name] = SymEntry(routine, None)
routines.append(routine)
self.scanner.check_type('EOF')
return Program(defns=defns, routines=routines)
@ -146,16 +151,20 @@ class Parser(object):
return accum
def locexpr(self):
if self.scanner.token in ('a', 'x', 'y', 'c', 'z', 'n', 'v'):
loc = LocationRef(self.scanner.token)
if self.scanner.token in ('a', 'x', 'y'):
loc = LocationRef(TYPE_BYTE, self.scanner.token)
self.scanner.scan()
return loc
elif self.scanner.token in ('c', 'z', 'n', 'v'):
loc = LocationRef(TYPE_BIT, self.scanner.token)
self.scanner.scan()
return loc
elif self.scanner.token in ('on', 'off'):
loc = ConstantRef(1 if self.scanner.token == 'on' else 0)
loc = ConstantRef(TYPE_BIT, 1 if self.scanner.token == 'on' else 0)
self.scanner.scan()
return loc
elif self.scanner.on_type('integer literal'):
loc = ConstantRef(int(self.scanner.token))
loc = ConstantRef(TYPE_BYTE, int(self.scanner.token))
self.scanner.scan()
return loc
else:

View File

@ -7,7 +7,7 @@ static analysis rules.
[Falderal]: http://catseye.tc/node/Falderal
-> Functionality "Analyze SixtyPical program" is implemented by
-> shell command "bin/sixtypical --analyze %(test-body-file) && echo ok"
-> shell command "bin/sixtypical --analyze --traceback %(test-body-file) && echo ok"
-> Tests for functionality "Analyze SixtyPical program"