예제 #1
0
    def analyze_point_into(self, instr, context):
        if not isinstance(self.get_type(instr.pointer), PointerType):
            raise TypeMismatchError(instr, instr.pointer)
        if not TableType.is_a_table_type(self.get_type(instr.table),
                                         TYPE_BYTE):
            raise TypeMismatchError(instr, instr.table)

        # check that pointer is not yet associated with any table.

        if context.get_assoc(instr.pointer):
            raise ForbiddenWriteError(instr, instr.pointer)

        # associate pointer with table
        # (do not mark it as meaningful yet - that's reset's job.)

        context.set_assoc(instr.pointer, instr.table)
        context.set_unmeaningful(instr.pointer)

        self.analyze_block(instr.block, context)
        if context.encountered_gotos():
            raise IllegalJumpError(instr, instr)

        # unassociate pointer with table, mark as unmeaningful.

        context.set_assoc(instr.pointer, None)
        context.set_unmeaningful(instr.pointer)
예제 #2
0
 def assert_types_for_update_table(self, context, instr, dest, type_,
                                   offset):
     if not TableType.is_a_table_type(self.get_type(dest.ref), type_):
         raise TypeMismatchError(instr, '{}'.format(dest.ref.name))
     context.assert_meaningful(dest.index)
     context.assert_in_range(dest.index, dest.ref, offset)
     context.set_written(dest.ref)
예제 #3
0
    def analyze_point_into(self, instr, context):
        if not isinstance(self.get_type(instr.pointer), PointerType):
            raise TypeMismatchError(instr, instr.pointer)
        if not TableType.is_a_table_type(self.get_type(instr.table), TYPE_BYTE):
            raise TypeMismatchError(instr, instr.table)

        # check that pointer is not yet associated with any table.

        if context.get_assoc(instr.pointer):
            raise ForbiddenWriteError(instr, instr.pointer)

        # associate pointer with table
        # (do not mark it as meaningful yet - that's reset's job.)

        context.set_assoc(instr.pointer, instr.table)
        context.set_unmeaningful(instr.pointer)

        self.analyze_block(instr.block, context)
        if context.encountered_gotos():
            raise IllegalJumpError(instr, instr)

        # unassociate pointer with table, mark as unmeaningful.

        context.set_assoc(instr.pointer, None)
        context.set_unmeaningful(instr.pointer)
예제 #4
0
 def assert_types_for_read_table(self, context, instr, src, dest, type_,
                                 offset):
     if (not TableType.is_a_table_type(self.get_type(
             src.ref), type_)) or (not self.get_type(dest) == type_):
         raise TypeMismatchError(
             instr, '{} and {}'.format(src.ref.name, dest.name))
     context.assert_meaningful(src, src.index)
     context.assert_in_range(src.index, src.ref, offset)
예제 #5
0
    def defn_type(self):
        type_ = self.defn_type_term()

        if self.scanner.consume('table'):
            size = self.defn_size()
            if size <= 0 or size > 65536:
                self.syntax_error("Table size must be > 0 and <= 65536")
            type_ = TableType(type_, size)

        return type_
예제 #6
0
 def backpatched_type(type_):
     if isinstance(type_, TableType):
         return TableType(backpatched_type(type_.of_type), type_.size)
     elif isinstance(type_, VectorType):
         return VectorType(backpatched_type(type_.of_type))
     elif isinstance(type_, RoutineType):
         return RoutineType(
             frozenset([resolve(w) for w in type_.inputs]),
             frozenset([resolve(w) for w in type_.outputs]),
             frozenset([resolve(w) for w in type_.trashes]),
         )
     else:
         return type_
예제 #7
0
    def analyze_single_op(self, instr, context):

        opcode = instr.opcode
        dest = instr.dest
        src = instr.src

        if context.has_terminated():
            raise TerminatedContextError(instr, instr)

        if opcode == 'ld':
            if isinstance(src, IndexedRef):
                self.assert_types_for_read_table(context, instr, src, dest,
                                                 TYPE_BYTE, src.offset)
            elif isinstance(src, IndirectRef):
                # copying this analysis from the matching branch in `copy`, below
                if isinstance(
                        self.get_type(src.ref),
                        PointerType) and self.get_type(dest) == TYPE_BYTE:
                    pass
                else:
                    raise TypeMismatchError(instr, (src, dest))

                origin = context.get_assoc(src.ref)
                if not origin:
                    raise UnmeaningfulReadError(instr, src.ref)
                context.assert_meaningful(origin)

                context.assert_meaningful(src.ref, REG_Y)
            elif self.get_type(src) != self.get_type(dest):
                raise TypeMismatchError(
                    instr, '{} and {}'.format(src.name, dest.name))
            else:
                context.assert_meaningful(src)
                context.copy_range(src, dest)
            context.set_written(dest, FLAG_Z, FLAG_N)
        elif opcode == 'st':
            if isinstance(dest, IndexedRef):
                if self.get_type(src) != TYPE_BYTE:
                    raise TypeMismatchError(instr, (src, dest))
                self.assert_types_for_update_table(context, instr, dest,
                                                   TYPE_BYTE, dest.offset)
            elif isinstance(dest, IndirectRef):
                # copying this analysis from the matching branch in `copy`, below
                if isinstance(self.get_type(dest.ref),
                              PointerType) and self.get_type(src) == TYPE_BYTE:
                    pass
                else:
                    raise TypeMismatchError(instr, (src, dest))

                context.assert_meaningful(dest.ref, REG_Y)

                target = context.get_assoc(dest.ref)
                if not target:
                    raise ForbiddenWriteError(instr, dest.ref)
                context.set_written(target)

            elif self.get_type(src) != self.get_type(dest):
                raise TypeMismatchError(instr, '{} and {}'.format(src, dest))
            else:
                context.set_written(dest)
                # FIXME: context.copy_range(src, dest)   ?
            context.assert_meaningful(src)
        elif opcode == 'add':
            context.assert_meaningful(src, dest, FLAG_C)
            if isinstance(src, IndexedRef):
                self.assert_types_for_read_table(context, instr, src, dest,
                                                 TYPE_BYTE, src.offset)
            elif self.get_type(src) == TYPE_BYTE:
                self.assert_type(TYPE_BYTE, src, dest)
                if dest != REG_A:
                    context.set_touched(REG_A)
                    context.set_unmeaningful(REG_A)
            else:
                self.assert_type(TYPE_WORD, src)
                dest_type = self.get_type(dest)
                if dest_type == TYPE_WORD:
                    context.set_touched(REG_A)
                    context.set_unmeaningful(REG_A)
                elif isinstance(dest_type, PointerType):
                    context.set_touched(REG_A)
                    context.set_unmeaningful(REG_A)
                else:
                    self.assert_type(TYPE_WORD, dest)
            context.set_written(dest, FLAG_Z, FLAG_N, FLAG_C, FLAG_V)
            context.invalidate_range(dest)
        elif opcode == 'sub':
            context.assert_meaningful(src, dest, FLAG_C)
            if isinstance(src, IndexedRef):
                self.assert_types_for_read_table(context, instr, src, dest,
                                                 TYPE_BYTE, src.offset)
            elif self.get_type(src) == TYPE_BYTE:
                self.assert_type(TYPE_BYTE, src, dest)
                if dest != REG_A:
                    context.set_touched(REG_A)
                    context.set_unmeaningful(REG_A)
            else:
                self.assert_type(TYPE_WORD, src, dest)
                context.set_touched(REG_A)
                context.set_unmeaningful(REG_A)
            context.set_written(dest, FLAG_Z, FLAG_N, FLAG_C, FLAG_V)
            context.invalidate_range(dest)
        elif opcode == 'cmp':
            context.assert_meaningful(src, dest)
            if isinstance(src, IndexedRef):
                self.assert_types_for_read_table(context, instr, src, dest,
                                                 TYPE_BYTE, src.offset)
            elif self.get_type(src) == TYPE_BYTE:
                self.assert_type(TYPE_BYTE, src, dest)
            else:
                self.assert_type(TYPE_WORD, src, dest)
                context.set_touched(REG_A)
                context.set_unmeaningful(REG_A)
            context.set_written(FLAG_Z, FLAG_N, FLAG_C)
        elif opcode == 'and':
            if isinstance(src, IndexedRef):
                self.assert_types_for_read_table(context, instr, src, dest,
                                                 TYPE_BYTE, src.offset)
            else:
                self.assert_type(TYPE_BYTE, src, dest)
            context.assert_meaningful(src, dest)
            context.set_written(dest, FLAG_Z, FLAG_N)
            # If you AND the A register with a value V, the resulting value of A
            # cannot exceed the value of V; i.e. the maximum value of A becomes
            # the maximum value of V.
            if not isinstance(src, IndexedRef):
                context.set_top_of_range(dest, context.get_top_of_range(src))
        elif opcode in ('or', 'xor'):
            if isinstance(src, IndexedRef):
                self.assert_types_for_read_table(context, instr, src, dest,
                                                 TYPE_BYTE, src.offset)
            else:
                self.assert_type(TYPE_BYTE, src, dest)
            context.assert_meaningful(src, dest)
            context.set_written(dest, FLAG_Z, FLAG_N)
            context.invalidate_range(dest)
        elif opcode in ('inc', 'dec'):
            context.assert_meaningful(dest)
            if isinstance(dest, IndexedRef):
                self.assert_types_for_update_table(context, instr, dest,
                                                   TYPE_BYTE, dest.offset)
                context.set_written(dest.ref, FLAG_Z, FLAG_N)
                #context.invalidate_range(dest)
            else:
                self.assert_type(TYPE_BYTE, dest)
                context.set_written(dest, FLAG_Z, FLAG_N)
                bottom = context.get_bottom_of_range(dest)
                top = context.get_top_of_range(dest)
                if opcode == 'inc':
                    if bottom == top and top < 255:
                        context.set_range(dest, bottom + 1, top + 1)
                    else:
                        context.invalidate_range(dest)
                elif opcode == 'dec':
                    if bottom == top and bottom > 0:
                        context.set_range(dest, bottom - 1, top - 1)
                    else:
                        context.invalidate_range(dest)
                else:
                    raise NotImplementedError
        elif opcode in ('shl', 'shr'):
            context.assert_meaningful(dest, FLAG_C)
            if isinstance(dest, IndexedRef):
                self.assert_types_for_update_table(context, instr, dest,
                                                   TYPE_BYTE, dest.offset)
                context.set_written(dest.ref, FLAG_Z, FLAG_N, FLAG_C)
                #context.invalidate_range(dest)
            else:
                self.assert_type(TYPE_BYTE, dest)
                context.set_written(dest, FLAG_Z, FLAG_N, FLAG_C)
                context.invalidate_range(dest)
        elif opcode == 'copy':
            if dest == REG_A:
                raise ForbiddenWriteError(
                    instr,
                    "{} cannot be used as destination for copy".format(dest))

            # 1. check that their types are compatible

            if isinstance(src, (LocationRef, ConstantRef)) and isinstance(
                    dest, IndirectRef):
                if self.get_type(src) == TYPE_BYTE and isinstance(
                        self.get_type(dest.ref), PointerType):
                    pass
                else:
                    raise TypeMismatchError(instr, (src, dest))
            elif isinstance(src, IndirectRef) and isinstance(
                    dest, LocationRef):
                if isinstance(
                        self.get_type(src.ref),
                        PointerType) and self.get_type(dest) == TYPE_BYTE:
                    pass
                else:
                    raise TypeMismatchError(instr, (src, dest))
            elif isinstance(src, IndirectRef) and isinstance(
                    dest, IndirectRef):
                if isinstance(self.get_type(src.ref),
                              PointerType) and isinstance(
                                  self.get_type(dest.ref), PointerType):
                    pass
                else:
                    raise TypeMismatchError(instr, (src, dest))

            elif isinstance(src, (LocationRef, ConstantRef)) and isinstance(
                    dest, IndexedRef):
                if self.get_type(
                        src) == TYPE_WORD and TableType.is_a_table_type(
                            self.get_type(dest.ref), TYPE_WORD):
                    pass
                elif (isinstance(self.get_type(src), VectorType)
                      and isinstance(self.get_type(dest.ref), TableType)
                      and RoutineType.executable_types_compatible(
                          self.get_type(src).of_type,
                          self.get_type(dest.ref).of_type)):
                    pass
                elif (isinstance(self.get_type(src), RoutineType)
                      and isinstance(self.get_type(dest.ref), TableType)
                      and RoutineType.executable_types_compatible(
                          self.get_type(src),
                          self.get_type(dest.ref).of_type)):
                    pass
                else:
                    raise TypeMismatchError(instr, (src, dest))
                context.assert_in_range(dest.index, dest.ref, dest.offset)

            elif isinstance(src, IndexedRef) and isinstance(dest, LocationRef):
                if TableType.is_a_table_type(
                        self.get_type(src.ref),
                        TYPE_WORD) and self.get_type(dest) == TYPE_WORD:
                    pass
                elif (isinstance(self.get_type(src.ref), TableType)
                      and isinstance(self.get_type(dest), VectorType)
                      and RoutineType.executable_types_compatible(
                          self.get_type(src.ref).of_type,
                          self.get_type(dest).of_type)):
                    pass
                else:
                    raise TypeMismatchError(instr, (src, dest))
                context.assert_in_range(src.index, src.ref, src.offset)

            elif isinstance(src, (LocationRef, ConstantRef)) and isinstance(
                    dest, LocationRef):
                if self.get_type(src) == self.get_type(dest):
                    pass
                elif isinstance(self.get_type(src),
                                RoutineType) and isinstance(
                                    self.get_type(dest), VectorType):
                    self.assert_affected_within('inputs', self.get_type(src),
                                                self.get_type(dest).of_type)
                    self.assert_affected_within('outputs', self.get_type(src),
                                                self.get_type(dest).of_type)
                    self.assert_affected_within('trashes', self.get_type(src),
                                                self.get_type(dest).of_type)
                else:
                    raise TypeMismatchError(instr, (src, dest))
            else:
                raise TypeMismatchError(instr, (src, dest))

            # 2. check that the context is meaningful

            if isinstance(src, (LocationRef, ConstantRef)) and isinstance(
                    dest, IndirectRef):
                context.assert_meaningful(src, dest.ref, REG_Y)

                target = context.get_assoc(dest.ref)
                if not target:
                    raise ForbiddenWriteError(instr, dest.ref)
                context.set_written(target)

            elif isinstance(src, IndirectRef) and isinstance(
                    dest, LocationRef):
                context.assert_meaningful(src.ref, REG_Y)

                origin = context.get_assoc(src.ref)
                if not origin:
                    raise UnmeaningfulReadError(instr, src.ref)
                context.assert_meaningful(origin)

                context.set_written(dest)

            elif isinstance(src, IndirectRef) and isinstance(
                    dest, IndirectRef):
                context.assert_meaningful(src.ref, dest.ref, REG_Y)

                origin = context.get_assoc(src.ref)
                if not origin:
                    raise UnmeaningfulReadError(instr, src.ref)
                context.assert_meaningful(origin)

                target = context.get_assoc(dest.ref)
                if not target:
                    raise ForbiddenWriteError(instr, dest.ref)
                context.set_written(target)

            elif isinstance(src, LocationRef) and isinstance(dest, IndexedRef):
                context.assert_meaningful(src, dest.ref, dest.index)
                context.set_written(dest.ref)
            elif isinstance(src, ConstantRef) and isinstance(dest, IndexedRef):
                context.assert_meaningful(src, dest.ref, dest.index)
                context.set_written(dest.ref)
            elif isinstance(src, IndexedRef) and isinstance(dest, LocationRef):
                context.assert_meaningful(src.ref, src.index)
                context.set_written(dest)
            else:
                context.assert_meaningful(src)
                context.set_written(dest)

            context.set_touched(REG_A, FLAG_Z, FLAG_N)
            context.set_unmeaningful(REG_A, FLAG_Z, FLAG_N)

        elif opcode == 'trash':
            context.set_touched(instr.dest)
            context.set_unmeaningful(instr.dest)
        elif opcode == 'nop':
            pass
        else:
            raise NotImplementedError(opcode)
예제 #8
0
    def compile_copy(self, instr, src, dest):

        if isinstance(src, (IndirectRef, IndexedRef)):
            src_ref_type = self.get_type(src.ref)
        else:
            src_type = self.get_type(src)

        if isinstance(dest, (IndirectRef, IndexedRef)):
            dest_ref_type = self.get_type(dest.ref)
        else:
            dest_type = self.get_type(dest)

        if isinstance(src, ConstantRef) and isinstance(
                dest, IndirectRef) and src_type == TYPE_BYTE and isinstance(
                    dest_ref_type, PointerType):
            ### copy 123, [ptr] + y
            dest_label = self.get_label(dest.ref.name)
            self.emitter.emit(LDA(Immediate(Byte(src.value))))
            self.emitter.emit(STA(IndirectY(dest_label)))
        elif isinstance(src, LocationRef) and isinstance(
                dest, IndirectRef) and src_type == TYPE_BYTE and isinstance(
                    dest_ref_type, PointerType):
            ### copy b, [ptr] + y
            src_label = self.get_label(src.name)
            dest_label = self.get_label(dest.ref.name)
            self.emitter.emit(LDA(Absolute(src_label)))
            self.emitter.emit(STA(IndirectY(dest_label)))
        elif isinstance(src, IndirectRef) and isinstance(
                dest, LocationRef) and dest_type == TYPE_BYTE and isinstance(
                    src_ref_type, PointerType):
            ### copy [ptr] + y, b
            src_label = self.get_label(src.ref.name)
            dest_label = self.get_label(dest.name)
            self.emitter.emit(LDA(IndirectY(src_label)))
            self.emitter.emit(STA(Absolute(dest_label)))
        elif isinstance(src, IndirectRef) and isinstance(
                dest, IndirectRef) and isinstance(
                    src_ref_type, PointerType) and isinstance(
                        dest_ref_type, PointerType):
            ### copy [ptra] + y, [ptrb] + y
            src_label = self.get_label(src.ref.name)
            dest_label = self.get_label(dest.ref.name)
            self.emitter.emit(LDA(IndirectY(src_label)))
            self.emitter.emit(STA(IndirectY(dest_label)))
        elif isinstance(src, LocationRef) and isinstance(
                dest, IndexedRef
        ) and src_type == TYPE_WORD and TableType.is_a_table_type(
                dest_ref_type, TYPE_WORD):
            ### copy w, wtab + y
            src_label = self.get_label(src.name)
            dest_label = self.get_label(dest.ref.name)
            mode = self.addressing_mode_for_index(dest.index)
            self.emitter.emit(LDA(Absolute(src_label)))
            self.emitter.emit(STA(mode(Offset(dest_label, dest.offset.value))))
            self.emitter.emit(LDA(Absolute(Offset(src_label, 1))))
            self.emitter.emit(
                STA(mode(Offset(dest_label, dest.offset.value + 256))))
        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):
            ### copy vec, vtab + y
            # FIXME this is the exact same as above - can this be simplified?
            src_label = self.get_label(src.name)
            dest_label = self.get_label(dest.ref.name)
            mode = self.addressing_mode_for_index(dest.index)
            self.emitter.emit(LDA(Absolute(src_label)))
            self.emitter.emit(STA(mode(Offset(dest_label, dest.offset.value))))
            self.emitter.emit(LDA(Absolute(Offset(src_label, 1))))
            self.emitter.emit(
                STA(mode(Offset(dest_label, dest.offset.value + 256))))
        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):
            ### copy routine, vtab + y
            src_label = self.get_label(src.name)
            dest_label = self.get_label(dest.ref.name)
            mode = self.addressing_mode_for_index(dest.index)
            self.emitter.emit(LDA(Immediate(HighAddressByte(src_label))))
            self.emitter.emit(STA(mode(Offset(dest_label, dest.offset.value))))
            self.emitter.emit(LDA(Immediate(LowAddressByte(src_label))))
            self.emitter.emit(
                STA(mode(Offset(dest_label, dest.offset.value + 256))))
        elif isinstance(src, ConstantRef) and isinstance(
                dest, IndexedRef
        ) and src_type == TYPE_WORD and TableType.is_a_table_type(
                dest_ref_type, TYPE_WORD):
            ### copy 9999, wtab + y
            dest_label = self.get_label(dest.ref.name)
            mode = self.addressing_mode_for_index(dest.index)
            self.emitter.emit(LDA(Immediate(Byte(src.low_byte()))))
            self.emitter.emit(STA(mode(Offset(dest_label, dest.offset.value))))
            self.emitter.emit(LDA(Immediate(Byte(src.high_byte()))))
            self.emitter.emit(
                STA(mode(Offset(dest_label, dest.offset.value + 256))))
        elif isinstance(src, IndexedRef) and isinstance(
                dest, LocationRef) and TableType.is_a_table_type(
                    src_ref_type, TYPE_WORD) and dest_type == TYPE_WORD:
            ### copy wtab + y, w
            src_label = self.get_label(src.ref.name)
            dest_label = self.get_label(dest.name)
            mode = self.addressing_mode_for_index(src.index)
            self.emitter.emit(LDA(mode(Offset(src_label, src.offset.value))))
            self.emitter.emit(STA(Absolute(dest_label)))
            self.emitter.emit(
                LDA(mode(Offset(src_label, src.offset.value + 256))))
            self.emitter.emit(STA(Absolute(Offset(dest_label, 1))))
        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):
            ### copy vtab + y, vec
            # FIXME this is the exact same as above - can this be simplified?
            src_label = self.get_label(src.ref.name)
            dest_label = self.get_label(dest.name)
            mode = self.addressing_mode_for_index(src.index)
            self.emitter.emit(LDA(mode(Offset(src_label, src.offset.value))))
            self.emitter.emit(STA(Absolute(dest_label)))
            self.emitter.emit(
                LDA(mode(Offset(src_label, src.offset.value + 256))))
            self.emitter.emit(STA(Absolute(Offset(dest_label, 1))))
        elif src_type == TYPE_BYTE and dest_type == TYPE_BYTE and not isinstance(
                src, ConstantRef):
            ### copy b1, b2
            src_label = self.get_label(src.name)
            dest_label = self.get_label(dest.name)
            self.emitter.emit(LDA(Absolute(src_label)))
            self.emitter.emit(STA(Absolute(dest_label)))
        elif src_type == TYPE_WORD and dest_type == TYPE_WORD and isinstance(
                src, ConstantRef):
            ### copy 9999, w
            dest_label = self.get_label(dest.name)
            self.emitter.emit(LDA(Immediate(Byte(src.low_byte()))))
            self.emitter.emit(STA(Absolute(dest_label)))
            self.emitter.emit(LDA(Immediate(Byte(src.high_byte()))))
            self.emitter.emit(STA(Absolute(Offset(dest_label, 1))))
        elif src_type == TYPE_WORD and dest_type == TYPE_WORD and not isinstance(
                src, ConstantRef):
            ### copy w1, w2
            src_label = self.get_label(src.name)
            dest_label = self.get_label(dest.name)
            self.emitter.emit(LDA(Absolute(src_label)))
            self.emitter.emit(STA(Absolute(dest_label)))
            self.emitter.emit(LDA(Absolute(Offset(src_label, 1))))
            self.emitter.emit(STA(Absolute(Offset(dest_label, 1))))
        elif isinstance(src_type, VectorType) and isinstance(
                dest_type, VectorType):
            ### copy v1, v2
            src_label = self.get_label(src.name)
            dest_label = self.get_label(dest.name)
            self.emitter.emit(LDA(Absolute(src_label)))
            self.emitter.emit(STA(Absolute(dest_label)))
            self.emitter.emit(LDA(Absolute(Offset(src_label, 1))))
            self.emitter.emit(STA(Absolute(Offset(dest_label, 1))))
        elif isinstance(src_type, RoutineType) and isinstance(
                dest_type, VectorType):
            ### copy routine, vec
            src_label = self.get_label(src.name)
            dest_label = self.get_label(dest.name)
            self.emitter.emit(LDA(Immediate(HighAddressByte(src_label))))
            self.emitter.emit(STA(Absolute(dest_label)))
            self.emitter.emit(LDA(Immediate(LowAddressByte(src_label))))
            self.emitter.emit(STA(Absolute(Offset(dest_label, 1))))
        else:
            raise NotImplementedError(src_type)
예제 #9
0
    def compile_program(self, program, compilation_roster=None):
        assert isinstance(program, Program)

        declarations = []

        for defn in program.defns:
            length = self.compute_length_of_defn(defn)
            label = Label(defn.name, addr=defn.addr, length=length)
            self.labels[defn.name] = label
            declarations.append(
                (defn, self.symtab.fetch_global_type(defn.name), label))

        for routine in program.routines:
            self.routines[routine.name] = routine
            label = Label(routine.name)
            if routine.addr is not None:
                label.set_addr(routine.addr)
            self.labels[routine.name] = label

            self.current_routine = routine
            local_labels = {}
            for defn in routine.locals:
                length = self.compute_length_of_defn(defn)
                label = Label(defn.name, addr=defn.addr, length=length)
                local_labels[defn.name] = label
                declarations.append(
                    (defn,
                     self.symtab.fetch_local_type(routine.name,
                                                  defn.name), label))
            self.routine_locals[routine.name] = local_labels
            self.current_routine = None

        if compilation_roster is None:
            compilation_roster = [['main']] + [[routine.name]
                                               for routine in program.routines
                                               if routine.name != 'main']

        for roster_row in compilation_roster:
            for routine_name in roster_row[0:-1]:
                self.compile_routine(self.routines[routine_name],
                                     skip_final_goto=True)
            routine_name = roster_row[-1]
            self.compile_routine(self.routines[routine_name])

        for location, label in self.trampolines.items():
            self.emitter.resolve_label(label)
            self.emitter.emit(JMP(Indirect(self.get_label(location.name))))
            self.emitter.emit(RTS())

        # initialized data
        for defn, type_, label in declarations:
            if defn.initial is not None:
                initial_data = None
                if type_ == TYPE_BYTE:
                    initial_data = Byte(defn.initial)
                elif type_ == TYPE_WORD:
                    initial_data = Word(defn.initial)
                elif TableType.is_a_table_type(type_, TYPE_BYTE):
                    initial_data = Table([Byte(i) for i in defn.initial],
                                         type_.size)
                elif TableType.is_a_table_type(type_, TYPE_WORD):
                    initial_data = Table([Word(i) for i in defn.initial],
                                         type_.size)
                else:
                    raise NotImplementedError(type_)
                label.set_length(initial_data.size())
                self.emitter.resolve_label(label)
                self.emitter.emit(initial_data)

        # uninitialized, "BSS" data
        for defn, type_, label in declarations:
            if defn.initial is None and defn.addr is None:
                self.emitter.resolve_bss_label(label)
예제 #10
0
    def analyze_single_op(self, instr, context):

        opcode = instr.opcode
        dest = instr.dest
        src = instr.src

        if context.has_terminated():
            raise TerminatedContextError(instr, instr)

        if opcode == 'ld':
            if isinstance(src, IndexedRef):
                self.assert_types_for_read_table(context, instr, src, dest, TYPE_BYTE, src.offset)
            elif isinstance(src, IndirectRef):
                # copying this analysis from the matching branch in `copy`, below
                if isinstance(self.get_type(src.ref), PointerType) and self.get_type(dest) == TYPE_BYTE:
                    pass
                else:
                    raise TypeMismatchError(instr, (src, dest))

                origin = context.get_assoc(src.ref)
                if not origin:
                    raise UnmeaningfulReadError(instr, src.ref)
                context.assert_meaningful(origin)

                context.assert_meaningful(src.ref, REG_Y)
            elif self.get_type(src) != self.get_type(dest):
                raise TypeMismatchError(instr, '{} and {}'.format(src.name, dest.name))
            else:
                context.assert_meaningful(src)
                context.copy_range(src, dest)
            context.set_written(dest, FLAG_Z, FLAG_N)
        elif opcode == 'st':
            if isinstance(dest, IndexedRef):
                if self.get_type(src) != TYPE_BYTE:
                    raise TypeMismatchError(instr, (src, dest))
                self.assert_types_for_update_table(context, instr, dest, TYPE_BYTE, dest.offset)
            elif isinstance(dest, IndirectRef):
                # copying this analysis from the matching branch in `copy`, below
                if isinstance(self.get_type(dest.ref), PointerType) and self.get_type(src) == TYPE_BYTE:
                    pass
                else:
                    raise TypeMismatchError(instr, (src, dest))

                context.assert_meaningful(dest.ref, REG_Y)

                target = context.get_assoc(dest.ref)
                if not target:
                    raise ForbiddenWriteError(instr, dest.ref)
                context.set_written(target)

            elif self.get_type(src) != self.get_type(dest):
                raise TypeMismatchError(instr, '{} and {}'.format(src, dest))
            else:
                context.set_written(dest)
                # FIXME: context.copy_range(src, dest)   ?
            context.assert_meaningful(src)
        elif opcode == 'add':
            context.assert_meaningful(src, dest, FLAG_C)
            if isinstance(src, IndexedRef):
                self.assert_types_for_read_table(context, instr, src, dest, TYPE_BYTE, src.offset)
            elif self.get_type(src) == TYPE_BYTE:
                self.assert_type(TYPE_BYTE, src, dest)
                if dest != REG_A:
                    context.set_touched(REG_A)
                    context.set_unmeaningful(REG_A)
            else:
                self.assert_type(TYPE_WORD, src)
                dest_type = self.get_type(dest)
                if dest_type == TYPE_WORD:
                    context.set_touched(REG_A)
                    context.set_unmeaningful(REG_A)
                elif isinstance(dest_type, PointerType):
                    context.set_touched(REG_A)
                    context.set_unmeaningful(REG_A)
                else:
                    self.assert_type(TYPE_WORD, dest)
            context.set_written(dest, FLAG_Z, FLAG_N, FLAG_C, FLAG_V)
            context.invalidate_range(dest)
        elif opcode == 'sub':
            context.assert_meaningful(src, dest, FLAG_C)
            if isinstance(src, IndexedRef):
                self.assert_types_for_read_table(context, instr, src, dest, TYPE_BYTE, src.offset)
            elif self.get_type(src) == TYPE_BYTE:
                self.assert_type(TYPE_BYTE, src, dest)
                if dest != REG_A:
                    context.set_touched(REG_A)
                    context.set_unmeaningful(REG_A)
            else:
                self.assert_type(TYPE_WORD, src, dest)
                context.set_touched(REG_A)
                context.set_unmeaningful(REG_A)
            context.set_written(dest, FLAG_Z, FLAG_N, FLAG_C, FLAG_V)
            context.invalidate_range(dest)
        elif opcode == 'cmp':
            context.assert_meaningful(src, dest)
            if isinstance(src, IndexedRef):
                self.assert_types_for_read_table(context, instr, src, dest, TYPE_BYTE, src.offset)
            elif self.get_type(src) == TYPE_BYTE:
                self.assert_type(TYPE_BYTE, src, dest)
            else:
                self.assert_type(TYPE_WORD, src, dest)
                context.set_touched(REG_A)
                context.set_unmeaningful(REG_A)
            context.set_written(FLAG_Z, FLAG_N, FLAG_C)
        elif opcode == 'and':
            if isinstance(src, IndexedRef):
                self.assert_types_for_read_table(context, instr, src, dest, TYPE_BYTE, src.offset)
            else:
                self.assert_type(TYPE_BYTE, src, dest)
            context.assert_meaningful(src, dest)
            context.set_written(dest, FLAG_Z, FLAG_N)
            # If you AND the A register with a value V, the resulting value of A
            # cannot exceed the value of V; i.e. the maximum value of A becomes
            # the maximum value of V.
            if not isinstance(src, IndexedRef):
                context.set_top_of_range(dest, context.get_top_of_range(src))
        elif opcode in ('or', 'xor'):
            if isinstance(src, IndexedRef):
                self.assert_types_for_read_table(context, instr, src, dest, TYPE_BYTE, src.offset)
            else:
                self.assert_type(TYPE_BYTE, src, dest)
            context.assert_meaningful(src, dest)
            context.set_written(dest, FLAG_Z, FLAG_N)
            context.invalidate_range(dest)
        elif opcode in ('inc', 'dec'):
            context.assert_meaningful(dest)
            if isinstance(dest, IndexedRef):
                self.assert_types_for_update_table(context, instr, dest, TYPE_BYTE, dest.offset)
                context.set_written(dest.ref, FLAG_Z, FLAG_N)
                #context.invalidate_range(dest)
            else:
                self.assert_type(TYPE_BYTE, dest)
                context.set_written(dest, FLAG_Z, FLAG_N)
                bottom = context.get_bottom_of_range(dest)
                top = context.get_top_of_range(dest)
                if opcode == 'inc':
                    if bottom == top and top < 255:
                        context.set_range(dest, bottom + 1, top + 1)
                    else:
                        context.invalidate_range(dest)
                elif opcode == 'dec':
                    if bottom == top and bottom > 0:
                        context.set_range(dest, bottom - 1, top - 1)
                    else:
                        context.invalidate_range(dest)
                else:
                    raise NotImplementedError
        elif opcode in ('shl', 'shr'):
            context.assert_meaningful(dest, FLAG_C)
            if isinstance(dest, IndexedRef):
                self.assert_types_for_update_table(context, instr, dest, TYPE_BYTE, dest.offset)
                context.set_written(dest.ref, FLAG_Z, FLAG_N, FLAG_C)
                #context.invalidate_range(dest)
            else:
                self.assert_type(TYPE_BYTE, dest)
                context.set_written(dest, FLAG_Z, FLAG_N, FLAG_C)
                context.invalidate_range(dest)
        elif opcode == 'copy':
            if dest == REG_A:
                raise ForbiddenWriteError(instr, "{} cannot be used as destination for copy".format(dest))

            # 1. check that their types are compatible

            if isinstance(src, (LocationRef, ConstantRef)) and isinstance(dest, IndirectRef):
                if self.get_type(src) == TYPE_BYTE and isinstance(self.get_type(dest.ref), PointerType):
                    pass
                else:
                    raise TypeMismatchError(instr, (src, dest))
            elif isinstance(src, IndirectRef) and isinstance(dest, LocationRef):
                if isinstance(self.get_type(src.ref), PointerType) and self.get_type(dest) == TYPE_BYTE:
                    pass
                else:
                    raise TypeMismatchError(instr, (src, dest))
            elif isinstance(src, IndirectRef) and isinstance(dest, IndirectRef):
                if isinstance(self.get_type(src.ref), PointerType) and isinstance(self.get_type(dest.ref), PointerType):
                    pass
                else:
                    raise TypeMismatchError(instr, (src, dest))

            elif isinstance(src, (LocationRef, ConstantRef)) and isinstance(dest, IndexedRef):
                if self.get_type(src) == TYPE_WORD and TableType.is_a_table_type(self.get_type(dest.ref), TYPE_WORD):
                    pass
                elif (isinstance(self.get_type(src), VectorType) and isinstance(self.get_type(dest.ref), TableType) and
                      RoutineType.executable_types_compatible(self.get_type(src).of_type, self.get_type(dest.ref).of_type)):
                    pass
                elif (isinstance(self.get_type(src), RoutineType) and isinstance(self.get_type(dest.ref), TableType) and
                      RoutineType.executable_types_compatible(self.get_type(src), self.get_type(dest.ref).of_type)):
                    pass
                else:
                    raise TypeMismatchError(instr, (src, dest))
                context.assert_in_range(dest.index, dest.ref, dest.offset)

            elif isinstance(src, IndexedRef) and isinstance(dest, LocationRef):
                if TableType.is_a_table_type(self.get_type(src.ref), TYPE_WORD) and self.get_type(dest) == TYPE_WORD:
                    pass
                elif (isinstance(self.get_type(src.ref), TableType) and isinstance(self.get_type(dest), VectorType) and
                      RoutineType.executable_types_compatible(self.get_type(src.ref).of_type, self.get_type(dest).of_type)):
                    pass
                else:
                    raise TypeMismatchError(instr, (src, dest))
                context.assert_in_range(src.index, src.ref, src.offset)

            elif isinstance(src, (LocationRef, ConstantRef)) and isinstance(dest, LocationRef):
                if self.get_type(src) == self.get_type(dest):
                    pass
                elif isinstance(self.get_type(src), RoutineType) and isinstance(self.get_type(dest), VectorType):
                    self.assert_affected_within('inputs', self.get_type(src), self.get_type(dest).of_type)
                    self.assert_affected_within('outputs', self.get_type(src), self.get_type(dest).of_type)
                    self.assert_affected_within('trashes', self.get_type(src), self.get_type(dest).of_type)
                else:
                    raise TypeMismatchError(instr, (src, dest))
            else:
                raise TypeMismatchError(instr, (src, dest))

            # 2. check that the context is meaningful

            if isinstance(src, (LocationRef, ConstantRef)) and isinstance(dest, IndirectRef):
                context.assert_meaningful(src, dest.ref, REG_Y)

                target = context.get_assoc(dest.ref)
                if not target:
                    raise ForbiddenWriteError(instr, dest.ref)
                context.set_written(target)

            elif isinstance(src, IndirectRef) and isinstance(dest, LocationRef):
                context.assert_meaningful(src.ref, REG_Y)

                origin = context.get_assoc(src.ref)
                if not origin:
                    raise UnmeaningfulReadError(instr, src.ref)
                context.assert_meaningful(origin)

                context.set_written(dest)

            elif isinstance(src, IndirectRef) and isinstance(dest, IndirectRef):
                context.assert_meaningful(src.ref, dest.ref, REG_Y)

                origin = context.get_assoc(src.ref)
                if not origin:
                    raise UnmeaningfulReadError(instr, src.ref)
                context.assert_meaningful(origin)

                target = context.get_assoc(dest.ref)
                if not target:
                    raise ForbiddenWriteError(instr, dest.ref)
                context.set_written(target)

            elif isinstance(src, LocationRef) and isinstance(dest, IndexedRef):
                context.assert_meaningful(src, dest.ref, dest.index)
                context.set_written(dest.ref)
            elif isinstance(src, ConstantRef) and isinstance(dest, IndexedRef):
                context.assert_meaningful(src, dest.ref, dest.index)
                context.set_written(dest.ref)
            elif isinstance(src, IndexedRef) and isinstance(dest, LocationRef):
                context.assert_meaningful(src.ref, src.index)
                context.set_written(dest)
            else:
                context.assert_meaningful(src)
                context.set_written(dest)

            context.set_touched(REG_A, FLAG_Z, FLAG_N)
            context.set_unmeaningful(REG_A, FLAG_Z, FLAG_N)

        elif opcode == 'trash':
            context.set_touched(instr.dest)
            context.set_unmeaningful(instr.dest)
        elif opcode == 'nop':
            pass
        else:
            raise NotImplementedError(opcode)
예제 #11
0
 def assert_types_for_update_table(self, context, instr, dest, type_, offset):
     if not TableType.is_a_table_type(self.get_type(dest.ref), type_):
         raise TypeMismatchError(instr, '{}'.format(dest.ref.name))
     context.assert_meaningful(dest.index)
     context.assert_in_range(dest.index, dest.ref, offset)
     context.set_written(dest.ref)
예제 #12
0
 def assert_types_for_read_table(self, context, instr, src, dest, type_, offset):
     if (not TableType.is_a_table_type(self.get_type(src.ref), type_)) or (not self.get_type(dest) == type_):
         raise TypeMismatchError(instr, '{} and {}'.format(src.ref.name, dest.name))
     context.assert_meaningful(src, src.index)
     context.assert_in_range(src.index, src.ref, offset)