git @ Cat's Eye Technologies SixtyPical / e1cf162
Refs have types. Chris Pressey 6 years ago
5 changed file(s) with 88 addition(s) and 40 deletion(s). Raw diff Collapse all Expand all
3535
3636 class Context():
3737 def __init__(self, inputs, outputs, trashes):
38 self._store = {}
38 self._store = {} # Ref -> INITALIZED/UNINITIALIZED
3939 self._writeables = set()
4040
4141 for ref in inputs:
42 self._store.setdefault(ref.name, INITIALIZED)
42 self._store.setdefault(ref, INITIALIZED)
4343 output_names = set()
4444 for ref in outputs:
4545 output_names.add(ref.name)
46 self._store.setdefault(ref.name, UNINITIALIZED)
46 self._store.setdefault(ref, UNINITIALIZED)
4747 self._writeables.add(ref.name)
4848 for ref in trashes:
4949 if ref.name in output_names:
5050 raise UsageClashError(ref.name)
51 self._store.setdefault(ref.name, UNINITIALIZED)
51 self._store.setdefault(ref, UNINITIALIZED)
5252 self._writeables.add(ref.name)
5353
5454 def clone(self):
6464 def each_initialized(self):
6565 for key, value in self._store.iteritems():
6666 if value == INITIALIZED:
67 yield LocationRef(key)
67 yield key
6868
6969 def assert_initialized(self, *refs, **kwargs):
7070 exception_class = kwargs.get('exception_class', UninitializedAccessError)
9494 if isinstance(ref, ConstantRef):
9595 return INITIALIZED
9696 elif isinstance(ref, LocationRef):
97 if ref.name not in self._store:
97 if ref not in self._store:
9898 return UNINITIALIZED
99 return self._store[ref.name]
99 return self._store[ref]
100100 else:
101101 raise ValueError(ref)
102102
103103 def set(self, ref, value):
104104 assert isinstance(ref, LocationRef)
105 self._store[ref.name] = value
105 self._store[ref] = value
106106
107107
108108 def analyze_program(program):
22 from sixtypical.ast import Program, Routine, Block, Instr
33 from sixtypical.model import (
44 ConstantRef, LocationRef,
5 TYPE_BIT,
56 REG_A, REG_X, REG_Y, FLAG_Z, FLAG_N, FLAG_V, FLAG_C
67 )
78 from sixtypical.emitter import Label, Byte
9899 else:
99100 raise UnsupportedOpcodeError(instr)
100101 elif opcode == 'st':
101 if dest == FLAG_C and src == ConstantRef(0):
102 if dest == FLAG_C and src == ConstantRef(TYPE_BIT, 0):
102103 self.emitter.emit(CLC())
103 elif dest == FLAG_C and src == ConstantRef(1):
104 elif dest == FLAG_C and src == ConstantRef(TYPE_BIT, 1):
104105 self.emitter.emit(SEC())
105106 elif src == REG_A:
106107 self.emitter.emit(STA(Absolute(self.labels[dest.name])))
00 """Data/storage model for SixtyPical."""
11
2 class LocationRef(object):
2 class Type(object):
33 def __init__(self, name):
44 self.name = name
55
66 def __repr__(self):
7 return 'LocationRef(%r)' % self.name
7 return 'Type(%r)' % self.name
88
99 def __eq__(self, other):
10 return isinstance(other, LocationRef) and other.name == self.name
10 return isinstance(other, Type) and other.name == self.name
11
12 def __hash__(self):
13 return hash(self.name)
1114
1215
13 class ConstantRef(object):
14 def __init__(self, value):
16 TYPE_BIT = Type('bit')
17 TYPE_BYTE = Type('byte')
18 TYPE_BYTE_TABLE = Type('byte table')
19
20
21 class Ref(object):
22 pass
23
24
25 class LocationRef(Ref):
26 def __init__(self, type, name):
27 self.type = type
28 self.name = name
29
30 def __eq__(self, other):
31 # Ordinarily there will only be one ref with a given name,
32 # but because we store the type in here and we want to treat
33 # these objects as immutable, we compare the types, too.
34 # Not sure if very wise.
35 return isinstance(other, LocationRef) and (
36 other.name == self.name and other.type == self.type
37 )
38
39 def __hash__(self):
40 return hash(self.name + str(self.type))
41
42 def __repr__(self):
43 return '%s(%r, %r)' % (self.__class__.__name__, self.type, self.name)
44
45
46 class ConstantRef(Ref):
47 def __init__(self, type, value):
48 self.type = type
1549 self.value = value
1650
1751 def __repr__(self):
1852 return 'ConstantRef(%r)' % self.value
1953
2054 def __eq__(self, other):
21 return isinstance(other, ConstantRef) and other.value == self.value
55 return isinstance(other, ConstantRef) and (
56 other.type == self.type and other.value == self.value
57 )
58
59 def __hash__(self):
60 return hash(str(self.value) + str(self.type))
61
62 def __repr__(self):
63 return '%s(%r, %r)' % (self.__class__.__name__, self.type, self.value)
2264
2365
24 # TODO type=byte
66 REG_A = LocationRef(TYPE_BYTE, 'a')
67 REG_X = LocationRef(TYPE_BYTE, 'x')
68 REG_Y = LocationRef(TYPE_BYTE, 'y')
2569
26 REG_A = LocationRef('a')
27 REG_X = LocationRef('x')
28 REG_Y = LocationRef('y')
29
30 # TODO type=bit
31
32 FLAG_Z = LocationRef('z')
33 FLAG_C = LocationRef('c')
34 FLAG_N = LocationRef('n')
35 FLAG_V = LocationRef('v')
70 FLAG_Z = LocationRef(TYPE_BIT, 'z')
71 FLAG_C = LocationRef(TYPE_BIT, 'c')
72 FLAG_N = LocationRef(TYPE_BIT, 'n')
73 FLAG_V = LocationRef(TYPE_BIT, 'v')
22 import re
33
44 from sixtypical.ast import Program, Defn, Routine, Block, Instr
5 from sixtypical.model import LocationRef, ConstantRef
5 from sixtypical.model import (
6 TYPE_BIT, TYPE_BYTE, LocationRef, ConstantRef
7 )
68
79
810 class Scanner(object):
6971 return False
7072
7173
74 class SymEntry(object):
75 def __init__(self, ast_node, model):
76 self.ast_node = ast_node
77 self.model = model
78
79
7280 class Parser(object):
7381 def __init__(self, text):
7482 self.scanner = Scanner(text)
75 self.symbols = {}
83 self.symbols = {} # token -> SymEntry
7684
7785 def lookup(self, name):
78 if name in self.symbols:
79 return LocationRef(name)
80 else:
81 raise KeyError(name)
86 return self.symbols[name].model
8287
8388 def program(self):
8489 defns = []
8893 name = defn.name
8994 if name in self.symbols:
9095 raise KeyError(name)
91 self.symbols[name] = defn
96 self.symbols[name] = SymEntry(defn, LocationRef(TYPE_BYTE, name))
9297 defns.append(defn)
9398 while self.scanner.on('routine'):
9499 routine = self.routine()
95100 name = routine.name
96101 if name in self.symbols:
97102 raise KeyError(name)
98 self.symbols[name] = routine
103 self.symbols[name] = SymEntry(routine, None)
99104 routines.append(routine)
100105 self.scanner.check_type('EOF')
101106 return Program(defns=defns, routines=routines)
145150 return accum
146151
147152 def locexpr(self):
148 if self.scanner.token in ('a', 'x', 'y', 'c', 'z', 'n', 'v'):
149 loc = LocationRef(self.scanner.token)
153 if self.scanner.token in ('a', 'x', 'y'):
154 loc = LocationRef(TYPE_BYTE, self.scanner.token)
155 self.scanner.scan()
156 return loc
157 elif self.scanner.token in ('c', 'z', 'n', 'v'):
158 loc = LocationRef(TYPE_BIT, self.scanner.token)
150159 self.scanner.scan()
151160 return loc
152161 elif self.scanner.token in ('on', 'off'):
153 loc = ConstantRef(1 if self.scanner.token == 'on' else 0)
162 loc = ConstantRef(TYPE_BIT, 1 if self.scanner.token == 'on' else 0)
154163 self.scanner.scan()
155164 return loc
156165 elif self.scanner.on_type('integer literal'):
157 loc = ConstantRef(int(self.scanner.token))
166 loc = ConstantRef(TYPE_BYTE, int(self.scanner.token))
158167 self.scanner.scan()
159168 return loc
160169 else:
66 [Falderal]: http://catseye.tc/node/Falderal
77
88 -> Functionality "Analyze SixtyPical program" is implemented by
9 -> shell command "bin/sixtypical --analyze %(test-body-file) && echo ok"
9 -> shell command "bin/sixtypical --analyze --traceback %(test-body-file) && echo ok"
1010
1111 -> Tests for functionality "Analyze SixtyPical program"
1212