git @ Cat's Eye Technologies SixtyPical / a0328b8
Store type information in SymbolTable shared across phases. Chris Pressey 2 years ago
7 changed file(s) with 268 addition(s) and 241 deletion(s). Raw diff Collapse all Expand all
1818 import sys
1919 import traceback
2020
21 from sixtypical.parser import Parser, ParsingContext, merge_programs
21 from sixtypical.parser import Parser, SymbolTable, merge_programs
2222 from sixtypical.analyzer import Analyzer
2323 from sixtypical.outputter import outputter_class_for
2424 from sixtypical.compiler import Compiler
2525
2626
2727 def process_input_files(filenames, options):
28 context = ParsingContext()
28 symtab = SymbolTable()
2929
3030 programs = []
3131
3232 for filename in options.filenames:
3333 text = open(filename).read()
34 parser = Parser(context, text, filename)
34 parser = Parser(symtab, text, filename)
3535 if options.debug:
36 print(context)
36 print(symtab)
3737 program = parser.program()
3838 programs.append(program)
3939
4242
4343 program = merge_programs(programs)
4444
45 analyzer = Analyzer(debug=options.debug)
45 analyzer = Analyzer(symtab, debug=options.debug)
4646
4747 try:
4848 analyzer.analyze_program(program)
6363 sys.stdout.write(json.dumps(data, indent=4, sort_keys=True, separators=(',', ':')))
6464 sys.stdout.write("\n")
6565
66 fa = FallthruAnalyzer(debug=options.debug)
66 fa = FallthruAnalyzer(symtab, debug=options.debug)
6767 fa.analyze_program(program)
6868 compilation_roster = fa.serialize()
6969 dump(compilation_roster)
8181 with open(options.output, 'wb') as fh:
8282 outputter = outputter_class_for(options.output_format)(fh, start_addr=start_addr)
8383 outputter.write_prelude()
84 compiler = Compiler(outputter.emitter)
84 compiler = Compiler(symtab, outputter.emitter)
8585 compiler.compile_program(program, compilation_roster=compilation_roster)
8686 outputter.write_postlude()
8787 if options.debug:
7979 pass
8080
8181
82 def routine_has_static(routine, ref):
83 if not hasattr(routine, 'statics'):
84 return False
85 for static in routine.statics:
86 if static.location == ref:
87 return True
88 return False
89
90
91 class Context(object):
82 class AnalysisContext(object):
9283 """
9384 A location is touched if it was changed (or even potentially
9485 changed) during this routine, or some routine called by this routine.
10798 lists of this routine. A location can also be temporarily marked
10899 unwriteable in certain contexts, such as `for` loops.
109100 """
110 def __init__(self, routines, routine, inputs, outputs, trashes):
111 self.routines = routines # LocationRef -> Routine (AST node)
101 def __init__(self, symtab, routine, inputs, outputs, trashes):
102 self.symtab = symtab
112103 self.routine = routine # Routine (AST node)
113104 self._touched = set() # {LocationRef}
114105 self._range = dict() # LocationRef -> (Int, Int)
118109 self._pointer_assoc = dict()
119110
120111 for ref in inputs:
121 if ref.is_constant():
112 if self.is_constant(ref):
122113 raise ConstantConstraintError(self.routine, ref.name)
123 self._range[ref] = ref.max_range()
114 self._range[ref] = self.max_range(ref)
124115 output_names = set()
125116 for ref in outputs:
126 if ref.is_constant():
117 if self.is_constant(ref):
127118 raise ConstantConstraintError(self.routine, ref.name)
128119 output_names.add(ref.name)
129120 self._writeable.add(ref)
130121 for ref in trashes:
131 if ref.is_constant():
122 if self.is_constant(ref):
132123 raise ConstantConstraintError(self.routine, ref.name)
133124 if ref.name in output_names:
134125 raise InconsistentConstraintsError(self.routine, ref.name)
135126 self._writeable.add(ref)
136127
137128 def __str__(self):
138 return "Context(\n _touched={},\n _range={},\n _writeable={}\n)".format(
129 return "{}(\n _touched={},\n _range={},\n _writeable={}\n)".format(
130 self.__class__.__name__,
139131 LocationRef.format_set(self._touched), LocationRef.format_set(self._range), LocationRef.format_set(self._writeable)
140132 )
141133
142134 def to_json_data(self):
143 type_ = self.routine.location.type
135 type_ = self.symtab.fetch_global_type(self.routine.name)
144136 return {
145137 'routine_inputs': ','.join(sorted(loc.name for loc in type_.inputs)),
146138 'routine_outputs': ','.join(sorted(loc.name for loc in type_.outputs)),
153145 }
154146
155147 def clone(self):
156 c = Context(self.routines, self.routine, [], [], [])
148 c = AnalysisContext(self.symtab, self.routine, [], [], [])
157149 c._touched = set(self._touched)
158150 c._range = dict(self._range)
159151 c._writeable = set(self._writeable)
168160 We do not replace the gotos_encountered for technical reasons. (In `analyze_if`,
169161 we merge those sets afterwards; at the end of `analyze_routine`, they are not distinct in the
170162 set of contexts we are updating from, and we want to retain our own.)"""
171 self.routines = other.routines
172163 self.routine = other.routine
173164 self._touched = set(other._touched)
174165 self._range = dict(other._range)
192183 exception_class = kwargs.get('exception_class', UnmeaningfulReadError)
193184 for ref in refs:
194185 # statics are always meaningful
195 if routine_has_static(self.routine, ref):
186 if self.symtab.fetch_static_ref(self.routine.name, ref.name):
196187 continue
197 if ref.is_constant() or ref in self.routines:
188 if self.is_constant(ref):
198189 pass
199190 elif isinstance(ref, LocationRef):
200191 if ref not in self._range:
212203 exception_class = kwargs.get('exception_class', ForbiddenWriteError)
213204 for ref in refs:
214205 # statics are always writeable
215 if routine_has_static(self.routine, ref):
206 if self.symtab.fetch_static_ref(self.routine.name, ref.name):
216207 continue
217208 if ref not in self._writeable:
218209 message = ref.name
233224 if outside in self._range:
234225 outside_range = self._range[outside]
235226 else:
236 outside_range = outside.max_range()
227 outside_range = self.max_range(outside)
237228
238229 if (inside_range[0] + offset.value) < outside_range[0] or (inside_range[1] + offset.value) > outside_range[1]:
239230 raise RangeExceededError(self.routine,
250241 def set_meaningful(self, *refs):
251242 for ref in refs:
252243 if ref not in self._range:
253 self._range[ref] = ref.max_range()
244 self._range[ref] = self.max_range(ref)
254245
255246 def set_top_of_range(self, ref, top):
256247 self.assert_meaningful(ref)
292283 if src in self._range:
293284 src_range = self._range[src]
294285 else:
295 src_range = src.max_range()
286 src_range = self.max_range(src)
296287 self._range[dest] = src_range
297288
298289 def invalidate_range(self, ref):
299290 self.assert_meaningful(ref)
300 self._range[ref] = ref.max_range()
291 self._range[ref] = self.max_range(ref)
301292
302293 def set_unmeaningful(self, *refs):
303294 for ref in refs:
334325
335326 def has_terminated(self):
336327 return self._terminated
337
338 def assert_types_for_read_table(self, instr, src, dest, type_, offset):
339 if (not TableType.is_a_table_type(src.ref.type, type_)) or (not dest.type == type_):
340 raise TypeMismatchError(instr, '{} and {}'.format(src.ref.name, dest.name))
341 self.assert_meaningful(src, src.index)
342 self.assert_in_range(src.index, src.ref, offset)
343
344 def assert_types_for_update_table(self, instr, dest, type_, offset):
345 if not TableType.is_a_table_type(dest.ref.type, type_):
346 raise TypeMismatchError(instr, '{}'.format(dest.ref.name))
347 self.assert_meaningful(dest.index)
348 self.assert_in_range(dest.index, dest.ref, offset)
349 self.set_written(dest.ref)
350328
351329 def extract(self, location):
352330 """Sets the given location as writeable in the context, and returns a 'baton' representing
389367 def set_assoc(self, pointer, table):
390368 self._pointer_assoc[pointer] = table
391369
370 def is_constant(self, ref):
371 """read-only means that the program cannot change the value
372 of a location. constant means that the value of the location
373 will not change during the lifetime of the program."""
374 if isinstance(ref, ConstantRef):
375 return True
376 if isinstance(ref, (IndirectRef, IndexedRef)):
377 return False
378 if isinstance(ref, LocationRef):
379 type_ = self.symtab.fetch_global_type(ref.name)
380 return isinstance(type_, RoutineType)
381 raise NotImplementedError
382
383 def max_range(self, ref):
384 if isinstance(ref, ConstantRef):
385 return (ref.value, ref.value)
386 elif self.symtab.has_static(self.routine.name, ref.name):
387 return self.symtab.fetch_static_type(self.routine.name, ref.name).max_range
388 else:
389 return self.symtab.fetch_global_type(ref.name).max_range
390
392391
393392 class Analyzer(object):
394393
395 def __init__(self, debug=False):
394 def __init__(self, symtab, debug=False):
395 self.symtab = symtab
396396 self.current_routine = None
397 self.routines = {}
398397 self.debug = debug
399398 self.exit_contexts_map = {}
400399
400 # - - - - helper methods - - - -
401
402 def get_type_for_name(self, name):
403 if self.current_routine and self.symtab.has_static(self.current_routine.name, name):
404 return self.symtab.fetch_static_type(self.current_routine.name, name)
405 return self.symtab.fetch_global_type(name)
406
407 def get_type(self, ref):
408 if isinstance(ref, ConstantRef):
409 return ref.type
410 if not isinstance(ref, LocationRef):
411 raise NotImplementedError
412 return self.get_type_for_name(ref.name)
413
401414 def assert_type(self, type_, *locations):
402415 for location in locations:
403 if location.type != type_:
416 if self.get_type(location) != type_:
404417 raise TypeMismatchError(self.current_routine, location.name)
405418
406419 def assert_affected_within(self, name, affecting_type, limiting_type):
418431 )
419432 raise IncompatibleConstraintsError(self.current_routine, message)
420433
434 def assert_types_for_read_table(self, context, instr, src, dest, type_, offset):
435 if (not TableType.is_a_table_type(self.get_type(src.ref), type_)) or (not self.get_type(dest) == type_):
436 raise TypeMismatchError(instr, '{} and {}'.format(src.ref.name, dest.name))
437 context.assert_meaningful(src, src.index)
438 context.assert_in_range(src.index, src.ref, offset)
439
440 def assert_types_for_update_table(self, context, instr, dest, type_, offset):
441 if not TableType.is_a_table_type(self.get_type(dest.ref), type_):
442 raise TypeMismatchError(instr, '{}'.format(dest.ref.name))
443 context.assert_meaningful(dest.index)
444 context.assert_in_range(dest.index, dest.ref, offset)
445 context.set_written(dest.ref)
446
447 # - - - - visitor methods - - - -
448
421449 def analyze_program(self, program):
422450 assert isinstance(program, Program)
423 self.routines = {r.location: r for r in program.routines}
424451 for routine in program.routines:
425452 context = self.analyze_routine(routine)
426453 routine.encountered_gotos = list(context.encountered_gotos()) if context else []
432459 return None
433460
434461 self.current_routine = routine
435 type_ = routine.location.type
436 context = Context(self.routines, routine, type_.inputs, type_.outputs, type_.trashes)
462 type_ = self.get_type_for_name(routine.name)
463 context = AnalysisContext(self.symtab, routine, type_.inputs, type_.outputs, type_.trashes)
437464 self.exit_contexts = []
438465
439466 self.analyze_block(routine.block, context)
477504
478505 # if something was touched, then it should have been declared to be writable.
479506 for ref in context.each_touched():
480 if ref not in type_.outputs and ref not in type_.trashes and not routine_has_static(routine, ref):
507 # FIXME once we have namedtuples, go back to comparing the ref directly!
508 outputs_names = [r.name for r in type_.outputs]
509 trashes_names = [r.name for r in type_.trashes]
510 if ref.name not in outputs_names and ref.name not in trashes_names and not self.symtab.has_static(routine.name, ref.name):
481511 raise ForbiddenWriteError(routine, ref.name)
482512
483513 self.exit_contexts = None
524554
525555 if opcode == 'ld':
526556 if isinstance(src, IndexedRef):
527 context.assert_types_for_read_table(instr, src, dest, TYPE_BYTE, src.offset)
557 self.assert_types_for_read_table(context, instr, src, dest, TYPE_BYTE, src.offset)
528558 elif isinstance(src, IndirectRef):
529559 # copying this analysis from the matching branch in `copy`, below
530 if isinstance(src.ref.type, PointerType) and dest.type == TYPE_BYTE:
560 if isinstance(self.get_type(src.ref), PointerType) and self.get_type(dest) == TYPE_BYTE:
531561 pass
532562 else:
533563 raise TypeMismatchError(instr, (src, dest))
538568 context.assert_meaningful(origin)
539569
540570 context.assert_meaningful(src.ref, REG_Y)
541 elif src.type != dest.type:
571 elif self.get_type(src) != self.get_type(dest):
542572 raise TypeMismatchError(instr, '{} and {}'.format(src.name, dest.name))
543573 else:
544574 context.assert_meaningful(src)
546576 context.set_written(dest, FLAG_Z, FLAG_N)
547577 elif opcode == 'st':
548578 if isinstance(dest, IndexedRef):
549 if src.type != TYPE_BYTE:
579 if self.get_type(src) != TYPE_BYTE:
550580 raise TypeMismatchError(instr, (src, dest))
551 context.assert_types_for_update_table(instr, dest, TYPE_BYTE, dest.offset)
581 self.assert_types_for_update_table(context, instr, dest, TYPE_BYTE, dest.offset)
552582 elif isinstance(dest, IndirectRef):
553583 # copying this analysis from the matching branch in `copy`, below
554 if isinstance(dest.ref.type, PointerType) and src.type == TYPE_BYTE:
584 if isinstance(self.get_type(dest.ref), PointerType) and self.get_type(src) == TYPE_BYTE:
555585 pass
556586 else:
557587 raise TypeMismatchError(instr, (src, dest))
564594 context.set_touched(target)
565595 context.set_written(target)
566596
567 elif src.type != dest.type:
597 elif self.get_type(src) != self.get_type(dest):
568598 raise TypeMismatchError(instr, '{} and {}'.format(src, dest))
569599 else:
570600 context.set_written(dest)
573603 elif opcode == 'add':
574604 context.assert_meaningful(src, dest, FLAG_C)
575605 if isinstance(src, IndexedRef):
576 context.assert_types_for_read_table(instr, src, dest, TYPE_BYTE, src.offset)
577 elif src.type == TYPE_BYTE:
606 self.assert_types_for_read_table(context, instr, src, dest, TYPE_BYTE, src.offset)
607 elif self.get_type(src) == TYPE_BYTE:
578608 self.assert_type(TYPE_BYTE, src, dest)
579609 if dest != REG_A:
580610 context.set_touched(REG_A)
581611 context.set_unmeaningful(REG_A)
582612 else:
583613 self.assert_type(TYPE_WORD, src)
584 if dest.type == TYPE_WORD:
614 dest_type = self.get_type(dest)
615 if dest_type == TYPE_WORD:
585616 context.set_touched(REG_A)
586617 context.set_unmeaningful(REG_A)
587 elif isinstance(dest.type, PointerType):
618 elif isinstance(dest_type, PointerType):
588619 context.set_touched(REG_A)
589620 context.set_unmeaningful(REG_A)
590621 else:
594625 elif opcode == 'sub':
595626 context.assert_meaningful(src, dest, FLAG_C)
596627 if isinstance(src, IndexedRef):
597 context.assert_types_for_read_table(instr, src, dest, TYPE_BYTE, src.offset)
598 elif src.type == TYPE_BYTE:
628 self.assert_types_for_read_table(context, instr, src, dest, TYPE_BYTE, src.offset)
629 elif self.get_type(src) == TYPE_BYTE:
599630 self.assert_type(TYPE_BYTE, src, dest)
600631 if dest != REG_A:
601632 context.set_touched(REG_A)
609640 elif opcode == 'cmp':
610641 context.assert_meaningful(src, dest)
611642 if isinstance(src, IndexedRef):
612 context.assert_types_for_read_table(instr, src, dest, TYPE_BYTE, src.offset)
613 elif src.type == TYPE_BYTE:
643 self.assert_types_for_read_table(context, instr, src, dest, TYPE_BYTE, src.offset)
644 elif self.get_type(src) == TYPE_BYTE:
614645 self.assert_type(TYPE_BYTE, src, dest)
615646 else:
616647 self.assert_type(TYPE_WORD, src, dest)
619650 context.set_written(FLAG_Z, FLAG_N, FLAG_C)
620651 elif opcode == 'and':
621652 if isinstance(src, IndexedRef):
622 context.assert_types_for_read_table(instr, src, dest, TYPE_BYTE, src.offset)
653 self.assert_types_for_read_table(context, instr, src, dest, TYPE_BYTE, src.offset)
623654 else:
624655 self.assert_type(TYPE_BYTE, src, dest)
625656 context.assert_meaningful(src, dest)
631662 context.set_top_of_range(dest, context.get_top_of_range(src))
632663 elif opcode in ('or', 'xor'):
633664 if isinstance(src, IndexedRef):
634 context.assert_types_for_read_table(instr, src, dest, TYPE_BYTE, src.offset)
665 self.assert_types_for_read_table(context, instr, src, dest, TYPE_BYTE, src.offset)
635666 else:
636667 self.assert_type(TYPE_BYTE, src, dest)
637668 context.assert_meaningful(src, dest)
640671 elif opcode in ('inc', 'dec'):
641672 context.assert_meaningful(dest)
642673 if isinstance(dest, IndexedRef):
643 context.assert_types_for_update_table(instr, dest, TYPE_BYTE, dest.offset)
674 self.assert_types_for_update_table(context, instr, dest, TYPE_BYTE, dest.offset)
644675 context.set_written(dest.ref, FLAG_Z, FLAG_N)
645676 #context.invalidate_range(dest)
646677 else:
663694 elif opcode in ('shl', 'shr'):
664695 context.assert_meaningful(dest, FLAG_C)
665696 if isinstance(dest, IndexedRef):
666 context.assert_types_for_update_table(instr, dest, TYPE_BYTE, dest.offset)
697 self.assert_types_for_update_table(context, instr, dest, TYPE_BYTE, dest.offset)
667698 context.set_written(dest.ref, FLAG_Z, FLAG_N, FLAG_C)
668699 #context.invalidate_range(dest)
669700 else:
677708 # 1. check that their types are compatible
678709
679710 if isinstance(src, (LocationRef, ConstantRef)) and isinstance(dest, IndirectRef):
680 if src.type == TYPE_BYTE and isinstance(dest.ref.type, PointerType):
711 if self.get_type(src) == TYPE_BYTE and isinstance(self.get_type(dest.ref), PointerType):
681712 pass
682713 else:
683714 raise TypeMismatchError(instr, (src, dest))
684715 elif isinstance(src, IndirectRef) and isinstance(dest, LocationRef):
685 if isinstance(src.ref.type, PointerType) and dest.type == TYPE_BYTE:
716 if isinstance(self.get_type(src.ref), PointerType) and self.get_type(dest) == TYPE_BYTE:
686717 pass
687718 else:
688719 raise TypeMismatchError(instr, (src, dest))
689720 elif isinstance(src, IndirectRef) and isinstance(dest, IndirectRef):
690 if isinstance(src.ref.type, PointerType) and isinstance(dest.ref.type, PointerType):
721 if isinstance(self.get_type(src.ref), PointerType) and isinstance(self.get_type(dest.ref), PointerType):
691722 pass
692723 else:
693724 raise TypeMismatchError(instr, (src, dest))
694725
695726 elif isinstance(src, (LocationRef, ConstantRef)) and isinstance(dest, IndexedRef):
696 if src.type == TYPE_WORD and TableType.is_a_table_type(dest.ref.type, TYPE_WORD):
727 if self.get_type(src) == TYPE_WORD and TableType.is_a_table_type(self.get_type(dest.ref), TYPE_WORD):
697728 pass
698 elif (isinstance(src.type, VectorType) and isinstance(dest.ref.type, TableType) and
699 RoutineType.executable_types_compatible(src.type.of_type, dest.ref.type.of_type)):
729 elif (isinstance(self.get_type(src), VectorType) and isinstance(self.get_type(dest.ref), TableType) and
730 RoutineType.executable_types_compatible(self.get_type(src).of_type, self.get_type(dest.ref).of_type)):
700731 pass
701 elif (isinstance(src.type, RoutineType) and isinstance(dest.ref.type, TableType) and
702 RoutineType.executable_types_compatible(src.type, dest.ref.type.of_type)):
732 elif (isinstance(self.get_type(src), RoutineType) and isinstance(self.get_type(dest.ref), TableType) and
733 RoutineType.executable_types_compatible(self.get_type(src), self.get_type(dest.ref).of_type)):
703734 pass
704735 else:
705736 raise TypeMismatchError(instr, (src, dest))
706737 context.assert_in_range(dest.index, dest.ref, dest.offset)
707738
708739 elif isinstance(src, IndexedRef) and isinstance(dest, LocationRef):
709 if TableType.is_a_table_type(src.ref.type, TYPE_WORD) and dest.type == TYPE_WORD:
740 if TableType.is_a_table_type(self.get_type(src.ref), TYPE_WORD) and self.get_type(dest) == TYPE_WORD:
710741 pass
711 elif (isinstance(src.ref.type, TableType) and isinstance(dest.type, VectorType) and
712 RoutineType.executable_types_compatible(src.ref.type.of_type, dest.type.of_type)):
742 elif (isinstance(self.get_type(src.ref), TableType) and isinstance(self.get_type(dest), VectorType) and
743 RoutineType.executable_types_compatible(self.get_type(src.ref).of_type, self.get_type(dest).of_type)):
713744 pass
714745 else:
715746 raise TypeMismatchError(instr, (src, dest))
716747 context.assert_in_range(src.index, src.ref, src.offset)
717748
718749 elif isinstance(src, (LocationRef, ConstantRef)) and isinstance(dest, LocationRef):
719 if src.type == dest.type:
750 if self.get_type(src) == self.get_type(dest):
720751 pass
721 elif isinstance(src.type, RoutineType) and isinstance(dest.type, VectorType):
722 self.assert_affected_within('inputs', src.type, dest.type.of_type)
723 self.assert_affected_within('outputs', src.type, dest.type.of_type)
724 self.assert_affected_within('trashes', src.type, dest.type.of_type)
752 elif isinstance(self.get_type(src), RoutineType) and isinstance(self.get_type(dest), VectorType):
753 self.assert_affected_within('inputs', self.get_type(src), self.get_type(dest).of_type)
754 self.assert_affected_within('outputs', self.get_type(src), self.get_type(dest).of_type)
755 self.assert_affected_within('trashes', self.get_type(src), self.get_type(dest).of_type)
725756 else:
726757 raise TypeMismatchError(instr, (src, dest))
727758 else:
788819 raise NotImplementedError(opcode)
789820
790821 def analyze_call(self, instr, context):
791 type = instr.location.type
822 type = self.get_type(instr.location)
792823 if not isinstance(type, (RoutineType, VectorType)):
793824 raise TypeMismatchError(instr, instr.location)
794825 if isinstance(type, VectorType):
804835
805836 def analyze_goto(self, instr, context):
806837 location = instr.location
807 type_ = location.type
838 type_ = self.get_type(instr.location)
808839
809840 if not isinstance(type_, (RoutineType, VectorType)):
810841 raise TypeMismatchError(instr, location)
817848
818849 # and that this routine's trashes and output constraints are a
819850 # superset of the called routine's
820 current_type = self.current_routine.location.type
851 current_type = self.get_type_for_name(self.current_routine.name)
821852 self.assert_affected_within('outputs', type_, current_type)
822853 self.assert_affected_within('trashes', type_, current_type)
823854
968999 context.set_unmeaningful(REG_A)
9691000
9701001 def analyze_point_into(self, instr, context):
971 if not isinstance(instr.pointer.type, PointerType):
1002 if not isinstance(self.get_type(instr.pointer), PointerType):
9721003 raise TypeMismatchError(instr, instr.pointer)
973 if not TableType.is_a_table_type(instr.table.type, TYPE_BYTE):
1004 if not TableType.is_a_table_type(self.get_type(instr.table), TYPE_BYTE):
9741005 raise TypeMismatchError(instr, instr.table)
9751006
9761007 # check that pointer is not yet associated with any table.
5353
5454
5555 class Defn(AST):
56 value_attrs = ('name', 'addr', 'initial', 'location',)
56 value_attrs = ('name', 'addr', 'initial',)
5757
5858
5959 class Routine(AST):
60 value_attrs = ('name', 'addr', 'initial', 'location',)
60 value_attrs = ('name', 'addr', 'initial',)
6161 children_attrs = ('statics',)
6262 child_attrs = ('block',)
6363
2929
3030
3131 class Compiler(object):
32 def __init__(self, emitter):
32 def __init__(self, symtab, emitter):
33 self.symtab = symtab
3334 self.emitter = emitter
3435 self.routines = {} # routine.name -> Routine
3536 self.routine_statics = {} # routine.name -> { static.name -> Label }
3738 self.trampolines = {} # Location -> Label
3839 self.current_routine = None
3940
40 # helper methods
41 # - - - - helper methods - - - -
42
43 def get_type_for_name(self, name):
44 if self.current_routine and self.symtab.has_static(self.current_routine.name, name):
45 return self.symtab.fetch_static_type(self.current_routine.name, name)
46 return self.symtab.fetch_global_type(name)
47
48 def get_type(self, ref):
49 if isinstance(ref, ConstantRef):
50 return ref.type
51 if not isinstance(ref, LocationRef):
52 raise NotImplementedError
53 return self.get_type_for_name(ref.name)
4154
4255 def addressing_mode_for_index(self, index):
4356 if index == REG_X:
4962
5063 def compute_length_of_defn(self, defn):
5164 length = None
52 type_ = defn.location.type
65 type_ = self.get_type_for_name(defn.name)
5366 if type_ == TYPE_BYTE:
5467 length = 1
5568 elif type_ == TYPE_WORD or isinstance(type_, (PointerType, VectorType)):
7386 else:
7487 return Absolute(label)
7588
76 # visitor methods
89 # - - - - visitor methods - - - -
7790
7891 def compile_program(self, program, compilation_roster=None):
7992 assert isinstance(program, Program)
8093
81 defn_labels = []
94 declarations = []
8295
8396 for defn in program.defns:
8497 length = self.compute_length_of_defn(defn)
8598 label = Label(defn.name, addr=defn.addr, length=length)
8699 self.labels[defn.name] = label
87 defn_labels.append((defn, label))
100 declarations.append((defn, self.symtab.fetch_global_type(defn.name), label))
88101
89102 for routine in program.routines:
90103 self.routines[routine.name] = routine
94107 self.labels[routine.name] = label
95108
96109 if hasattr(routine, 'statics'):
110 self.current_routine = routine
97111 static_labels = {}
98112 for defn in routine.statics:
99113 length = self.compute_length_of_defn(defn)
100114 label = Label(defn.name, addr=defn.addr, length=length)
101115 static_labels[defn.name] = label
102 defn_labels.append((defn, label))
116 declarations.append((defn, self.symtab.fetch_static_type(routine.name, defn.name), label))
103117 self.routine_statics[routine.name] = static_labels
118 self.current_routine = None
104119
105120 if compilation_roster is None:
106121 compilation_roster = [['main']] + [[routine.name] for routine in program.routines if routine.name != 'main']
117132 self.emitter.emit(RTS())
118133
119134 # initialized data
120 for defn, label in defn_labels:
135 for defn, type_, label in declarations:
121136 if defn.initial is not None:
122137 initial_data = None
123 type_ = defn.location.type
124138 if type_ == TYPE_BYTE:
125139 initial_data = Byte(defn.initial)
126140 elif type_ == TYPE_WORD:
136150 self.emitter.emit(initial_data)
137151
138152 # uninitialized, "BSS" data
139 for defn, label in defn_labels:
153 for defn, type_, label in declarations:
140154 if defn.initial is None and defn.addr is None:
141155 self.emitter.resolve_bss_label(label)
142156
198212 self.emitter.emit(LDA(AbsoluteX(Offset(self.get_label(src.ref.name), src.offset.value))))
199213 elif isinstance(src, IndexedRef) and src.index == REG_Y:
200214 self.emitter.emit(LDA(AbsoluteY(Offset(self.get_label(src.ref.name), src.offset.value))))
201 elif isinstance(src, IndirectRef) and isinstance(src.ref.type, PointerType):
215 elif isinstance(src, IndirectRef) and isinstance(self.get_type(src.ref), PointerType):
202216 self.emitter.emit(LDA(IndirectY(self.get_label(src.ref.name))))
203217 else:
204218 self.emitter.emit(LDA(self.absolute_or_zero_page(self.get_label(src.name))))
240254 REG_Y: AbsoluteY,
241255 }[dest.index]
242256 operand = mode_cls(Offset(self.get_label(dest.ref.name), dest.offset.value))
243 elif isinstance(dest, IndirectRef) and isinstance(dest.ref.type, PointerType):
257 elif isinstance(dest, IndirectRef) and isinstance(self.get_type(dest.ref), PointerType):
244258 operand = IndirectY(self.get_label(dest.ref.name))
245259 else:
246260 operand = self.absolute_or_zero_page(self.get_label(dest.name))
259273 self.emitter.emit(ADC(mode(Offset(self.get_label(src.ref.name), src.offset.value))))
260274 else:
261275 self.emitter.emit(ADC(Absolute(self.get_label(src.name))))
262 elif isinstance(dest, LocationRef) and src.type == TYPE_BYTE and dest.type == TYPE_BYTE:
276 elif isinstance(dest, LocationRef) and self.get_type(src) == TYPE_BYTE and self.get_type(dest) == TYPE_BYTE:
263277 if isinstance(src, ConstantRef):
264278 dest_label = self.get_label(dest.name)
265279 self.emitter.emit(LDA(Absolute(dest_label)))
273287 self.emitter.emit(STA(Absolute(dest_label)))
274288 else:
275289 raise UnsupportedOpcodeError(instr)
276 elif isinstance(dest, LocationRef) and src.type == TYPE_WORD and dest.type == TYPE_WORD:
290 elif isinstance(dest, LocationRef) and self.get_type(src) == TYPE_WORD and self.get_type(dest) == TYPE_WORD:
277291 if isinstance(src, ConstantRef):
278292 dest_label = self.get_label(dest.name)
279293 self.emitter.emit(LDA(Absolute(dest_label)))
293307 self.emitter.emit(STA(Absolute(Offset(dest_label, 1))))
294308 else:
295309 raise UnsupportedOpcodeError(instr)
296 elif isinstance(dest, LocationRef) and src.type == TYPE_WORD and isinstance(dest.type, PointerType):
310 elif isinstance(dest, LocationRef) and self.get_type(src) == TYPE_WORD and isinstance(self.get_type(dest), PointerType):
297311 if isinstance(src, ConstantRef):
298312 dest_label = self.get_label(dest.name)
299313 self.emitter.emit(LDA(ZeroPage(dest_label)))
326340 self.emitter.emit(SBC(mode(Offset(self.get_label(src.ref.name), src.offset.value))))
327341 else:
328342 self.emitter.emit(SBC(Absolute(self.get_label(src.name))))
329 elif isinstance(dest, LocationRef) and src.type == TYPE_BYTE and dest.type == TYPE_BYTE:
343 elif isinstance(dest, LocationRef) and self.get_type(src) == TYPE_BYTE and self.get_type(dest) == TYPE_BYTE:
330344 if isinstance(src, ConstantRef):
331345 dest_label = self.get_label(dest.name)
332346 self.emitter.emit(LDA(Absolute(dest_label)))
340354 self.emitter.emit(STA(Absolute(dest_label)))
341355 else:
342356 raise UnsupportedOpcodeError(instr)
343 elif isinstance(dest, LocationRef) and src.type == TYPE_WORD and dest.type == TYPE_WORD:
357 elif isinstance(dest, LocationRef) and self.get_type(src) == TYPE_WORD and self.get_type(dest) == TYPE_WORD:
344358 if isinstance(src, ConstantRef):
345359 dest_label = self.get_label(dest.name)
346360 self.emitter.emit(LDA(Absolute(dest_label)))
408422 def compile_call(self, instr):
409423 location = instr.location
410424 label = self.get_label(instr.location.name)
411 if isinstance(location.type, RoutineType):
425 location_type = self.get_type(location)
426 if isinstance(location_type, RoutineType):
412427 self.emitter.emit(JSR(Absolute(label)))
413 elif isinstance(location.type, VectorType):
428 elif isinstance(location_type, VectorType):
414429 trampoline = self.trampolines.setdefault(
415430 location, Label(location.name + '_trampoline')
416431 )
417432 self.emitter.emit(JSR(Absolute(trampoline)))
418433 else:
419 raise NotImplementedError
434 raise NotImplementedError(location_type)
420435
421436 def compile_goto(self, instr):
422437 self.final_goto_seen = True
425440 else:
426441 location = instr.location
427442 label = self.get_label(instr.location.name)
428 if isinstance(location.type, RoutineType):
443 location_type = self.get_type(location)
444 if isinstance(location_type, RoutineType):
429445 self.emitter.emit(JMP(Absolute(label)))
430 elif isinstance(location.type, VectorType):
446 elif isinstance(location_type, VectorType):
431447 self.emitter.emit(JMP(Indirect(label)))
432448 else:
433 raise NotImplementedError
449 raise NotImplementedError(location_type)
434450
435451 def compile_cmp(self, instr, src, dest):
436452 """`instr` is only for reporting purposes"""
437 if isinstance(src, LocationRef) and src.type == TYPE_WORD:
453 if isinstance(src, LocationRef) and self.get_type(src) == TYPE_WORD:
438454 src_label = self.get_label(src.name)
439455 dest_label = self.get_label(dest.name)
440456 self.emitter.emit(LDA(Absolute(dest_label)))
445461 self.emitter.emit(CMP(Absolute(Offset(src_label, 1))))
446462 self.emitter.resolve_label(end_label)
447463 return
448 if isinstance(src, ConstantRef) and src.type == TYPE_WORD:
464 if isinstance(src, ConstantRef) and self.get_type(src) == TYPE_WORD:
449465 dest_label = self.get_label(dest.name)
450466 self.emitter.emit(LDA(Absolute(dest_label)))
451467 self.emitter.emit(CMP(Immediate(Byte(src.low_byte()))))
496512 self.emitter.emit(DEC(Absolute(self.get_label(dest.name))))
497513
498514 def compile_copy(self, instr, src, dest):
499 if isinstance(src, ConstantRef) and isinstance(dest, IndirectRef) and src.type == TYPE_BYTE and isinstance(dest.ref.type, PointerType):
515
516 if isinstance(src, (IndirectRef, IndexedRef)):
517 src_ref_type = self.get_type(src.ref)
518 else:
519 src_type = self.get_type(src)
520
521 if isinstance(dest, (IndirectRef, IndexedRef)):
522 dest_ref_type = self.get_type(dest.ref)
523 else:
524 dest_type = self.get_type(dest)
525
526 if isinstance(src, ConstantRef) and isinstance(dest, IndirectRef) and src_type == TYPE_BYTE and isinstance(dest_ref_type, PointerType):
500527 ### copy 123, [ptr] + y
501528 dest_label = self.get_label(dest.ref.name)
502529 self.emitter.emit(LDA(Immediate(Byte(src.value))))
503530 self.emitter.emit(STA(IndirectY(dest_label)))
504 elif isinstance(src, LocationRef) and isinstance(dest, IndirectRef) and src.type == TYPE_BYTE and isinstance(dest.ref.type, PointerType):
531 elif isinstance(src, LocationRef) and isinstance(dest, IndirectRef) and src_type == TYPE_BYTE and isinstance(dest_ref_type, PointerType):
505532 ### copy b, [ptr] + y
506533 src_label = self.get_label(src.name)
507534 dest_label = self.get_label(dest.ref.name)
508535 self.emitter.emit(LDA(Absolute(src_label)))
509536 self.emitter.emit(STA(IndirectY(dest_label)))
510 elif isinstance(src, IndirectRef) and isinstance(dest, LocationRef) and dest.type == TYPE_BYTE and isinstance(src.ref.type, PointerType):
537 elif isinstance(src, IndirectRef) and isinstance(dest, LocationRef) and dest_type == TYPE_BYTE and isinstance(src_ref_type, PointerType):
511538 ### copy [ptr] + y, b
512539 src_label = self.get_label(src.ref.name)
513540 dest_label = self.get_label(dest.name)
514541 self.emitter.emit(LDA(IndirectY(src_label)))
515542 self.emitter.emit(STA(Absolute(dest_label)))
516 elif isinstance(src, IndirectRef) and isinstance(dest, IndirectRef) and isinstance(src.ref.type, PointerType) and isinstance(dest.ref.type, PointerType):
543 elif isinstance(src, IndirectRef) and isinstance(dest, IndirectRef) and isinstance(src_ref_type, PointerType) and isinstance(dest_ref_type, PointerType):
517544 ### copy [ptra] + y, [ptrb] + y
518545 src_label = self.get_label(src.ref.name)
519546 dest_label = self.get_label(dest.ref.name)
520547 self.emitter.emit(LDA(IndirectY(src_label)))
521548 self.emitter.emit(STA(IndirectY(dest_label)))
522 elif isinstance(src, LocationRef) and isinstance(dest, IndexedRef) and src.type == TYPE_WORD and TableType.is_a_table_type(dest.ref.type, TYPE_WORD):
549 elif isinstance(src, LocationRef) and isinstance(dest, IndexedRef) and src_type == TYPE_WORD and TableType.is_a_table_type(dest_ref_type, TYPE_WORD):
523550 ### copy w, wtab + y
524551 src_label = self.get_label(src.name)
525552 dest_label = self.get_label(dest.ref.name)
528555 self.emitter.emit(STA(mode(Offset(dest_label, dest.offset.value))))
529556 self.emitter.emit(LDA(Absolute(Offset(src_label, 1))))
530557 self.emitter.emit(STA(mode(Offset(dest_label, dest.offset.value + 256))))
531 elif isinstance(src, LocationRef) and isinstance(dest, IndexedRef) and isinstance(src.type, VectorType) and isinstance(dest.ref.type, TableType) and isinstance(dest.ref.type.of_type, VectorType):
558 elif isinstance(src, LocationRef) and isinstance(dest, IndexedRef) and isinstance(src_type, VectorType) and isinstance(dest_ref_type, TableType) and isinstance(dest_ref_type.of_type, VectorType):
532559 ### copy vec, vtab + y
533560 # FIXME this is the exact same as above - can this be simplified?
534561 src_label = self.get_label(src.name)
538565 self.emitter.emit(STA(mode(Offset(dest_label, dest.offset.value))))
539566 self.emitter.emit(LDA(Absolute(Offset(src_label, 1))))
540567 self.emitter.emit(STA(mode(Offset(dest_label, dest.offset.value + 256))))
541 elif isinstance(src, LocationRef) and isinstance(dest, IndexedRef) and isinstance(src.type, RoutineType) and isinstance(dest.ref.type, TableType) and isinstance(dest.ref.type.of_type, VectorType):
568 elif isinstance(src, LocationRef) and isinstance(dest, IndexedRef) and isinstance(src_type, RoutineType) and isinstance(dest_ref_type, TableType) and isinstance(dest_ref_type.of_type, VectorType):
542569 ### copy routine, vtab + y
543570 src_label = self.get_label(src.name)
544571 dest_label = self.get_label(dest.ref.name)
547574 self.emitter.emit(STA(mode(Offset(dest_label, dest.offset.value))))
548575 self.emitter.emit(LDA(Immediate(LowAddressByte(src_label))))
549576 self.emitter.emit(STA(mode(Offset(dest_label, dest.offset.value + 256))))
550 elif isinstance(src, ConstantRef) and isinstance(dest, IndexedRef) and src.type == TYPE_WORD and TableType.is_a_table_type(dest.ref.type, TYPE_WORD):
577 elif isinstance(src, ConstantRef) and isinstance(dest, IndexedRef) and src_type == TYPE_WORD and TableType.is_a_table_type(dest_ref_type, TYPE_WORD):
551578 ### copy 9999, wtab + y
552579 dest_label = self.get_label(dest.ref.name)
553580 mode = self.addressing_mode_for_index(dest.index)
555582 self.emitter.emit(STA(mode(Offset(dest_label, dest.offset.value))))
556583 self.emitter.emit(LDA(Immediate(Byte(src.high_byte()))))
557584 self.emitter.emit(STA(mode(Offset(dest_label, dest.offset.value + 256))))
558 elif isinstance(src, IndexedRef) and isinstance(dest, LocationRef) and TableType.is_a_table_type(src.ref.type, TYPE_WORD) and dest.type == TYPE_WORD:
585 elif isinstance(src, IndexedRef) and isinstance(dest, LocationRef) and TableType.is_a_table_type(src_ref_type, TYPE_WORD) and dest_type == TYPE_WORD:
559586 ### copy wtab + y, w
560587 src_label = self.get_label(src.ref.name)
561588 dest_label = self.get_label(dest.name)
564591 self.emitter.emit(STA(Absolute(dest_label)))
565592 self.emitter.emit(LDA(mode(Offset(src_label, src.offset.value + 256))))
566593 self.emitter.emit(STA(Absolute(Offset(dest_label, 1))))
567 elif isinstance(src, IndexedRef) and isinstance(dest, LocationRef) and isinstance(dest.type, VectorType) and isinstance(src.ref.type, TableType) and isinstance(src.ref.type.of_type, VectorType):
594 elif isinstance(src, IndexedRef) and isinstance(dest, LocationRef) and isinstance(dest_type, VectorType) and isinstance(src_ref_type, TableType) and isinstance(src_ref_type.of_type, VectorType):
568595 ### copy vtab + y, vec
569596 # FIXME this is the exact same as above - can this be simplified?
570597 src_label = self.get_label(src.ref.name)
574601 self.emitter.emit(STA(Absolute(dest_label)))
575602 self.emitter.emit(LDA(mode(Offset(src_label, src.offset.value + 256))))
576603 self.emitter.emit(STA(Absolute(Offset(dest_label, 1))))
577 elif src.type == TYPE_BYTE and dest.type == TYPE_BYTE and not isinstance(src, ConstantRef):
604 elif src_type == TYPE_BYTE and dest_type == TYPE_BYTE and not isinstance(src, ConstantRef):
578605 ### copy b1, b2
579606 src_label = self.get_label(src.name)
580607 dest_label = self.get_label(dest.name)
581608 self.emitter.emit(LDA(Absolute(src_label)))
582609 self.emitter.emit(STA(Absolute(dest_label)))
583 elif src.type == TYPE_WORD and dest.type == TYPE_WORD and isinstance(src, ConstantRef):
610 elif src_type == TYPE_WORD and dest_type == TYPE_WORD and isinstance(src, ConstantRef):
584611 ### copy 9999, w
585612 dest_label = self.get_label(dest.name)
586613 self.emitter.emit(LDA(Immediate(Byte(src.low_byte()))))
587614 self.emitter.emit(STA(Absolute(dest_label)))
588615 self.emitter.emit(LDA(Immediate(Byte(src.high_byte()))))
589616 self.emitter.emit(STA(Absolute(Offset(dest_label, 1))))
590 elif src.type == TYPE_WORD and dest.type == TYPE_WORD and not isinstance(src, ConstantRef):
617 elif src_type == TYPE_WORD and dest_type == TYPE_WORD and not isinstance(src, ConstantRef):
591618 ### copy w1, w2
592619 src_label = self.get_label(src.name)
593620 dest_label = self.get_label(dest.name)
595622 self.emitter.emit(STA(Absolute(dest_label)))
596623 self.emitter.emit(LDA(Absolute(Offset(src_label, 1))))
597624 self.emitter.emit(STA(Absolute(Offset(dest_label, 1))))
598 elif isinstance(src.type, VectorType) and isinstance(dest.type, VectorType):
625 elif isinstance(src_type, VectorType) and isinstance(dest_type, VectorType):
599626 ### copy v1, v2
600627 src_label = self.get_label(src.name)
601628 dest_label = self.get_label(dest.name)
603630 self.emitter.emit(STA(Absolute(dest_label)))
604631 self.emitter.emit(LDA(Absolute(Offset(src_label, 1))))
605632 self.emitter.emit(STA(Absolute(Offset(dest_label, 1))))
606 elif isinstance(src.type, RoutineType) and isinstance(dest.type, VectorType):
633 elif isinstance(src_type, RoutineType) and isinstance(dest_type, VectorType):
607634 ### copy routine, vec
608635 src_label = self.get_label(src.name)
609636 dest_label = self.get_label(dest.name)
612639 self.emitter.emit(LDA(Immediate(LowAddressByte(src_label))))
613640 self.emitter.emit(STA(Absolute(Offset(dest_label, 1))))
614641 else:
615 raise NotImplementedError(src.type)
642 raise NotImplementedError(src_type)
616643
617644 def compile_if(self, instr):
618645 cls = {
66
77 class FallthruAnalyzer(object):
88
9 def __init__(self, debug=False):
9 def __init__(self, symtab, debug=False):
10 self.symtab = symtab
1011 self.debug = debug
1112
1213 def analyze_program(self, program):
1516 self.fallthru_map = {}
1617 for routine in program.routines:
1718 encountered_gotos = list(routine.encountered_gotos)
18 if len(encountered_gotos) == 1 and isinstance(encountered_gotos[0].type, RoutineType):
19 if len(encountered_gotos) == 1 and isinstance(self.symtab.fetch_global_type(encountered_gotos[0].name), RoutineType):
1920 self.fallthru_map[routine.name] = encountered_gotos[0].name
2021 else:
2122 self.fallthru_map[routine.name] = None
5656
5757 class VectorType(Type):
5858 """This memory location contains the address of some other type (currently, only RoutineType)."""
59 max_range = (0, 0)
60
5961 def __init__(self, of_type):
6062 self.of_type = of_type
6163
9193
9294
9395 class PointerType(Type):
96 max_range = (0, 0)
97
9498 def __init__(self):
9599 self.name = 'pointer'
96100
99103
100104
101105 class Ref(object):
102 def is_constant(self):
103 """read-only means that the program cannot change the value
104 of a location. constant means that the value of the location
105 will not change during the lifetime of the program."""
106 raise NotImplementedError("class {} must implement is_constant()".format(self.__class__.__name__))
107
108 def max_range(self):
109 raise NotImplementedError("class {} must implement max_range()".format(self.__class__.__name__))
106 pass
110107
111108
112109 class LocationRef(Ref):
113110 def __init__(self, type, name):
114 self.type = type
115111 self.name = name
116112
117113 def __eq__(self, other):
118 # Ordinarily there will only be one ref with a given name,
119 # but because we store the type in here and we want to treat
120 # these objects as immutable, we compare the types, too,
121 # just to be sure.
122 equal = isinstance(other, self.__class__) and other.name == self.name
123 if equal:
124 assert other.type == self.type, repr((self, other))
125 return equal
126
127 def __hash__(self):
128 return hash(self.name + repr(self.type))
129
130 def __repr__(self):
131 return '%s(%r, %r)' % (self.__class__.__name__, self.type, self.name)
114 return self.__class__ is other.__class__ and self.name == other.name
115
116 def __hash__(self):
117 return hash(self.name)
118
119 def __repr__(self):
120 return '%s(%r)' % (self.__class__.__name__, self.name)
132121
133122 def __str__(self):
134 return "{}:{}".format(self.name, self.type)
135
136 def is_constant(self):
137 return isinstance(self.type, RoutineType)
138
139 def max_range(self):
140 try:
141 return self.type.max_range
142 except:
143 return (0, 0)
123 return self.name
144124
145125 @classmethod
146126 def format_set(cls, location_refs):
163143 @property
164144 def name(self):
165145 return '[{}]+y'.format(self.ref.name)
166
167 def is_constant(self):
168 return False
169146
170147
171148 class IndexedRef(Ref):
187164 def name(self):
188165 return '{}+{}+{}'.format(self.ref.name, self.offset, self.index.name)
189166
190 def is_constant(self):
191 return False
192
193167
194168 class ConstantRef(Ref):
195169 def __init__(self, type, value):
206180
207181 def __repr__(self):
208182 return '%s(%r, %r)' % (self.__class__.__name__, self.type, self.value)
209
210 def is_constant(self):
211 return True
212
213 def max_range(self):
214 return (self.value, self.value)
215183
216184 def high_byte(self):
217185 return (self.value >> 8) & 255
2727 return "%s(%r)" % (self.__class__.__name__, self.name)
2828
2929
30 class ParsingContext(object):
30 class SymbolTable(object):
3131 def __init__(self):
32 self.symbols = {} # token -> SymEntry
33 self.statics = {} # token -> SymEntry
34 self.typedefs = {} # token -> Type AST
35 self.consts = {} # token -> Loc
32 self.symbols = {} # symbol name -> SymEntry
33 self.statics = {} # routine name -> (symbol name -> SymEntry)
34 self.typedefs = {} # type name -> Type AST
35 self.consts = {} # const name -> ConstantRef
3636
3737 for name in ('a', 'x', 'y'):
3838 self.symbols[name] = SymEntry(None, TYPE_BYTE)
4242 def __str__(self):
4343 return "Symbols: {}\nStatics: {}\nTypedefs: {}\nConsts: {}".format(self.symbols, self.statics, self.typedefs, self.consts)
4444
45 def fetch_ref(self, name):
46 if name in self.statics:
47 return LocationRef(self.statics[name].type_, name)
45 def has_static(self, routine_name, name):
46 return name in self.statics.get(routine_name, {})
47
48 def fetch_global_type(self, name):
49 return self.symbols[name].type_
50
51 def fetch_static_type(self, routine_name, name):
52 return self.statics[routine_name][name].type_
53
54 def fetch_global_ref(self, name):
4855 if name in self.symbols:
4956 return LocationRef(self.symbols[name].type_, name)
5057 return None
5158
59 def fetch_static_ref(self, routine_name, name):
60 routine_statics = self.statics.get(routine_name, {})
61 if name in routine_statics:
62 return LocationRef(routine_statics[name].type_, name)
63 return None
64
5265
5366 class Parser(object):
54 def __init__(self, context, text, filename):
55 self.context = context
67 def __init__(self, symtab, text, filename):
68 self.symtab = symtab
5669 self.scanner = Scanner(text, filename)
70 self.current_routine_name = None
5771
5872 def syntax_error(self, msg):
5973 self.scanner.syntax_error(msg)
6074
61 def lookup(self, name):
62 model = self.context.fetch_ref(name)
75 def lookup(self, name, allow_forward=False, routine_name=None):
76 model = self.symtab.fetch_global_ref(name)
77 if model is None and routine_name:
78 model = self.symtab.fetch_static_ref(routine_name, name)
79 if model is None and allow_forward:
80 return ForwardReference(name)
6381 if model is None:
6482 self.syntax_error('Undefined symbol "{}"'.format(name))
6583 return model
6684
67 def declare(self, name, ast_node, type_, static=False):
68 if self.context.fetch_ref(name):
85 def declare(self, name, ast_node, type_):
86 if self.symtab.fetch_global_ref(name):
6987 self.syntax_error('Symbol "%s" already declared' % name)
70 if static:
71 self.context.statics[name] = SymEntry(ast_node, type_)
72 else:
73 self.context.symbols[name] = SymEntry(ast_node, type_)
74
75 def clear_statics(self):
76 self.context.statics = {}
88 self.symtab.symbols[name] = SymEntry(ast_node, type_)
89
90 def declare_static(self, routine_name, name, ast_node, type_):
91 if self.symtab.fetch_global_ref(name):
92 self.syntax_error('Symbol "%s" already declared' % name)
93 self.symtab.statics.setdefault(routine_name, {})[name] = SymEntry(ast_node, type_)
7794
7895 # ---- symbol resolution
7996
94111 type_.outputs = set([resolve(w) for w in type_.outputs])
95112 type_.trashes = set([resolve(w) for w in type_.trashes])
96113
97 for defn in program.defns:
98 backpatch_constraint_labels(defn.location.type)
99 for routine in program.routines:
100 backpatch_constraint_labels(routine.location.type)
114 for name, symentry in self.symtab.symbols.items():
115 backpatch_constraint_labels(symentry.type_)
101116
102117 def resolve_fwd_reference(obj, field):
103118 field_value = getattr(obj, field, None)
109124
110125 for node in program.all_children():
111126 if isinstance(node, SingleOp):
112 resolve_fwd_reference(node, 'location')
113127 resolve_fwd_reference(node, 'src')
114128 resolve_fwd_reference(node, 'dest')
115129 if isinstance(node, (Call, GoTo)):
126140 if self.scanner.on('const'):
127141 self.defn_const()
128142 typenames = ['byte', 'word', 'table', 'vector', 'pointer'] # 'routine',
129 typenames.extend(self.context.typedefs.keys())
143 typenames.extend(self.symtab.typedefs.keys())
130144 while self.scanner.on(*typenames):
131145 type_, defn = self.defn()
132146 self.declare(defn.name, defn, type_)
134148 while self.scanner.consume('define'):
135149 name = self.scanner.token
136150 self.scanner.scan()
151 self.current_routine_name = name
137152 type_, routine = self.routine(name)
138153 self.declare(name, routine, type_)
139154 routines.append(routine)
155 self.current_routine_name = None
140156 self.scanner.check_type('EOF')
141157
142158 program = Program(self.scanner.line_number, defns=defns, routines=routines)
147163 self.scanner.expect('typedef')
148164 type_ = self.defn_type()
149165 name = self.defn_name()
150 if name in self.context.typedefs:
166 if name in self.symtab.typedefs:
151167 self.syntax_error('Type "%s" already declared' % name)
152 self.context.typedefs[name] = type_
168 self.symtab.typedefs[name] = type_
153169 return type_
154170
155171 def defn_const(self):
156172 self.scanner.expect('const')
157173 name = self.defn_name()
158 if name in self.context.consts:
174 if name in self.symtab.consts:
159175 self.syntax_error('Const "%s" already declared' % name)
160176 loc = self.const()
161 self.context.consts[name] = loc
177 self.symtab.consts[name] = loc
162178 return loc
163179
164180 def defn(self):
188204 if initial is not None and addr is not None:
189205 self.syntax_error("Definition cannot have both initial value and explicit address")
190206
191 location = LocationRef(type_, name)
192
193 return type_, Defn(self.scanner.line_number, name=name, addr=addr, initial=initial, location=location)
207 return type_, Defn(self.scanner.line_number, name=name, addr=addr, initial=initial)
194208
195209 def const(self):
196210 if self.scanner.token in ('on', 'off'):
207221 loc = ConstantRef(TYPE_WORD, int(self.scanner.token))
208222 self.scanner.scan()
209223 return loc
210 elif self.scanner.token in self.context.consts:
211 loc = self.context.consts[self.scanner.token]
224 elif self.scanner.token in self.symtab.consts:
225 loc = self.symtab.consts[self.scanner.token]
212226 self.scanner.scan()
213227 return loc
214228 else:
256270 else:
257271 type_name = self.scanner.token
258272 self.scanner.scan()
259 if type_name not in self.context.typedefs:
273 if type_name not in self.symtab.typedefs:
260274 self.syntax_error("Undefined type '%s'" % type_name)
261 type_ = self.context.typedefs[type_name]
275 type_ = self.symtab.typedefs[type_name]
262276
263277 return type_
264278
296310 self.scanner.scan()
297311 else:
298312 statics = self.statics()
299
300 self.clear_statics()
301 for defn in statics:
302 self.declare(defn.name, defn, defn.location.type, static=True)
303313 block = self.block()
304 self.clear_statics()
305
306314 addr = None
307 location = LocationRef(type_, name)
308 return type_, Routine(
309 self.scanner.line_number,
310 name=name, block=block, addr=addr,
311 location=location, statics=statics,
312 )
315 return type_, Routine(self.scanner.line_number, name=name, block=block, addr=addr, statics=statics)
313316
314317 def labels(self):
315318 accum = []
333336 return accum
334337
335338 def locexpr(self):
336 if self.scanner.token in ('on', 'off', 'word') or self.scanner.token in self.context.consts or self.scanner.on_type('integer literal'):
339 if self.scanner.token in ('on', 'off', 'word') or self.scanner.token in self.symtab.consts or self.scanner.on_type('integer literal'):
337340 return self.const()
338341 else:
339342 name = self.scanner.token
340343 self.scanner.scan()
341 loc = self.context.fetch_ref(name)
342 if loc:
343 return loc
344 else:
345 return ForwardReference(name)
344 return self.lookup(name, allow_forward=True, routine_name=self.current_routine_name)
346345
347346 def indlocexpr(self):
348347 if self.scanner.consume('['):
360359 index = None
361360 offset = ConstantRef(TYPE_BYTE, 0)
362361 if self.scanner.consume('+'):
363 if self.scanner.token in self.context.consts or self.scanner.on_type('integer literal'):
362 if self.scanner.token in self.symtab.consts or self.scanner.on_type('integer literal'):
364363 offset = self.const()
365364 self.scanner.expect('+')
366365 index = self.locexpr()
373372 type_, defn = self.defn()
374373 if defn.initial is None:
375374 self.syntax_error("Static definition {} must have initial value".format(defn))
375 self.declare_static(self.current_routine_name, defn.name, defn, type_)
376376 defns.append(defn)
377377 return defns
378378