git @ Cat's Eye Technologies SixtyPical / 55331e9
Statics are always writeable. Statics are always meaningful. Chris Pressey 3 years ago
4 changed file(s) with 53 addition(s) and 8 deletion(s). Raw diff Collapse all Expand all
5050
5151 class IncompatibleConstraintsError(ConstraintsError):
5252 pass
53
54
55 def routine_has_static(routine, ref):
56 if not hasattr(routine, 'statics'):
57 return False
58 return ref in [static.location for static in routine.statics]
5359
5460
5561 class Context(object):
111117 def assert_meaningful(self, *refs, **kwargs):
112118 exception_class = kwargs.get('exception_class', UnmeaningfulReadError)
113119 for ref in refs:
120 # statics are always meaningful
121 if routine_has_static(self.routine, ref):
122 continue
114123 if ref.is_constant() or ref in self.routines:
115124 pass
116125 elif isinstance(ref, LocationRef):
128137 def assert_writeable(self, *refs, **kwargs):
129138 exception_class = kwargs.get('exception_class', ForbiddenWriteError)
130139 for ref in refs:
140 # statics are always writeable
141 if routine_has_static(self.routine, ref):
142 continue
131143 if ref not in self._writeable:
132144 message = '%s in %s' % (ref.name, self.routine.name)
133145 if kwargs.get('message'):
230242 for ref in type_.outputs:
231243 context.assert_meaningful(ref, exception_class=UnmeaningfulOutputError)
232244 for ref in context.each_touched():
233 if ref not in type_.outputs and ref not in type_.trashes:
245 if ref not in type_.outputs and ref not in type_.trashes and not routine_has_static(routine, ref):
234246 message = '%s in %s' % (ref.name, routine.name)
235247 raise ForbiddenWriteError(message)
236248 self.current_routine = None
144144 # just to be sure.
145145 equal = isinstance(other, self.__class__) and other.name == self.name
146146 if equal:
147 assert other.type == self.type
147 assert other.type == self.type, repr((self, other))
148148 return equal
149149
150150 def __hash__(self):
1212 def __init__(self, ast_node, model):
1313 self.ast_node = ast_node
1414 self.model = model
15
16 def __repr__(self):
17 return "%s(%r, %r)" % (self.__class__.__name__, self.ast_node, self.model)
1518
1619
1720 class Parser(object):
220223 else:
221224 statics = self.statics()
222225
223 self.current_statics = {}
224 for defn in statics:
225 name = defn.name
226 if name in self.symbols or name in self.current_statics:
227 raise SyntaxError('Symbol "%s" already declared' % name)
228 self.current_statics[name] = SymEntry(defn, defn.location)
226 self.current_statics = self.compose_statics_dict(statics)
229227 block = self.block()
230228 self.current_statics = {}
231229
235233 name=name, block=block, addr=addr,
236234 location=location, statics=statics
237235 )
236
237 def compose_statics_dict(self, statics):
238 c = {}
239 for defn in statics:
240 name = defn.name
241 if name in self.symbols or name in self.current_statics:
242 raise SyntaxError('Symbol "%s" already declared' % name)
243 c[name] = SymEntry(defn, defn.location)
244 return c
238245
239246 def labels(self):
240247 accum = []
22822282 | copy foo, vec
22832283 | }
22842284 = ok
2285
2286 ### static ###
2287
2288 When memory locations are defined static to a routine, they cannot be
2289 directly input, nor directly output; and since they are always initialized,
2290 they cannot be trashed. Thus, they really don't participate in the analysis.
2291
2292 | define foo routine
2293 | inputs x
2294 | outputs x
2295 | trashes z, n
2296 | static byte t : 0
2297 | {
2298 | st x, t
2299 | inc t
2300 | ld x, t
2301 | }
2302 |
2303 | define main routine
2304 | trashes a, x, z, n
2305 | static byte t : 0
2306 | {
2307 | ld x, t
2308 | call foo
2309 | }
2310 = ok