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:
parent
4990493b11
commit
e1cf162a5b
@ -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):
|
||||
|
@ -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])))
|
||||
|
@ -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')
|
||||
|
@ -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:
|
||||
|
@ -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"
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user