示例#1
0
 def __init__(self, ctl, address, addr_str, operation, comment_index,
              comment, preserve_base):
     self.ctl = ctl
     self.address = address
     self.addr_str = addr_str
     self.comment_index = comment_index
     self.comment = comment
     self.operation = operation
     if operation:
         self.inst_ctl = get_instruction_ctl(operation)
         if self.inst_ctl == 'C':
             size = get_size(operation, address)
             length = [get_operand_bases(operation, preserve_base), size]
         elif self.inst_ctl == 'B':
             size, length = get_defb_length(self.operation, preserve_base)
         elif self.inst_ctl == 'T':
             size, length = get_defb_length(self.operation, preserve_base)
         elif self.inst_ctl == 'W':
             size, length = get_defw_length(self.operation, preserve_base)
         else:
             size, length = get_defs_length(self.operation, preserve_base)
         self.end = address + size
         self.lengths = [length]
     else:
         self.inst_ctl = 'I'
示例#2
0
    def write_sub_block(self, ctl, entry_ctl, comment, instructions, lengths):
        length = 0
        sublengths = []
        address = instructions[0].address
        if ctl == 'C':
            # Compute the sublengths for a 'C' sub-block
            for i, instruction in enumerate(instructions):
                addr = instruction.address
                if i < len(instructions) - 1:
                    sublength = instructions[i + 1].address - addr
                else:
                    sublength = get_size(instruction.operation, addr)
                if sublength > 0:
                    length += sublength
                    bases = instruction.bases
                    if sublengths and bases == sublengths[-1][0]:
                        sublengths[-1][1] += sublength
                    else:
                        sublengths.append([bases, sublength])
            if not any(comment) and len(sublengths) > 1 and entry_ctl == 'c':
                if not sublengths[-1][0]:
                    length -= sublengths.pop()[1]
                if not sublengths[0][0]:
                    sublength = sublengths.pop(0)[1]
                    length -= sublength
                    address += sublength
            lengths = ','.join(['{}{}'.format(*s) for s in sublengths])
            if len(sublengths) > 1:
                lengths = '{},{}'.format(length, lengths)
        elif ctl in 'BSTW':
            # Compute the sublengths for a 'B', 'S', 'T' or 'W' sub-block
            for statement in instructions:
                length += statement.size
                sublengths.append(statement.length)
            while len(sublengths) > 1 and sublengths[-1] == sublengths[-2]:
                sublengths.pop()
            lengths = '{},{}'.format(length, get_lengths(sublengths))

        addr_str = self.addr_str(address)
        if lengths:
            lengths = ',{}'.format(lengths)
        if isinstance(comment, str):
            write_line('{} {}{} {}'.format(ctl, addr_str, lengths, comment).rstrip())
        else:
            # Remove redundant trailing blank lines
            min_comments = min(len(instructions) - 1, 1)
            while len(comment) > min_comments and comment[-1] == ['']:
                comment.pop()
            self._write_lines(comment, ctl, addr_str + lengths, True)
示例#3
0
    def write_sub_block(self, ctl, entry_ctl, comment, instructions, lengths):
        length = 0
        sublengths = []
        address = instructions[0].address
        if ctl == 'c':
            # Compute the sublengths for a 'C' sub-block
            for i, instruction in enumerate(instructions):
                addr = instruction.address
                if i < len(instructions) - 1:
                    sublength = instructions[i + 1].address - addr
                else:
                    sublength = get_size(instruction.operation, addr)
                if sublength > 0:
                    length += sublength
                    bases = instruction.bases
                    if sublengths and bases == sublengths[-1][0]:
                        sublengths[-1][1] += sublength
                    else:
                        sublengths.append([bases, sublength])
            if not comment and len(sublengths) > 1 and entry_ctl == 'c':
                if not sublengths[-1][0]:
                    length -= sublengths.pop()[1]
                if not sublengths[0][0]:
                    sublength = sublengths.pop(0)[1]
                    length -= sublength
                    address += sublength
            lengths = ','.join(['{}{}'.format(*s) for s in sublengths])
            if len(sublengths) > 1:
                lengths = '{},{}'.format(length, lengths)
        elif ctl in 'bstw':
            # Compute the sublengths for a 'B', 'S', 'T' or 'W' sub-block
            for statement in instructions:
                length += statement.size
                sublengths.append(statement.length)
            while len(sublengths) > 1 and sublengths[-1] == sublengths[-2]:
                sublengths.pop()
            lengths = '{},{}'.format(length, get_lengths(sublengths))

        if ctl == entry_ctl:
            sub_block_ctl = ' '
        else:
            sub_block_ctl = ctl.upper()
        addr_str = self.addr_str(address)
        if lengths:
            lengths = ',{}'.format(lengths)
        write_line('{} {}{} {}'.format(sub_block_ctl, addr_str, lengths,
                                       comment).rstrip())
示例#4
0
    def write_sub_block(self, ctl, entry_ctl, comment, instructions, lengths):
        length = 0
        sublengths = []
        address = instructions[0].address
        if ctl == 'c':
            # Compute the sublengths for a 'C' sub-block
            for i, instruction in enumerate(instructions):
                addr = instruction.address
                if i < len(instructions) - 1:
                    sublength = instructions[i + 1].address - addr
                else:
                    sublength = get_size(instruction.operation, addr)
                if sublength > 0:
                    length += sublength
                    bases = instruction.bases
                    if sublengths and bases == sublengths[-1][0]:
                        sublengths[-1][1] += sublength
                    else:
                        sublengths.append([bases, sublength])
            if not comment and len(sublengths) > 1 and entry_ctl == 'c':
                if not sublengths[-1][0]:
                    length -= sublengths.pop()[1]
                if not sublengths[0][0]:
                    sublength = sublengths.pop(0)[1]
                    length -= sublength
                    address += sublength
            lengths = ','.join(['{}{}'.format(*s) for s in sublengths])
            if len(sublengths) > 1:
                lengths = '{},{}'.format(length, lengths)
        elif ctl in 'bstw':
            # Compute the sublengths for a 'B', 'S', 'T' or 'W' sub-block
            for statement in instructions:
                length += statement.size
                sublengths.append(statement.length)
            while len(sublengths) > 1 and sublengths[-1] == sublengths[-2]:
                sublengths.pop()
            lengths = '{},{}'.format(length, get_lengths(sublengths))

        if ctl == entry_ctl:
            sub_block_ctl = ' '
        else:
            sub_block_ctl = ctl.upper()
        addr_str = self.addr_str(address)
        if lengths:
            lengths = ',{}'.format(lengths)
        write_line('{} {}{} {}'.format(sub_block_ctl, addr_str, lengths, comment).rstrip())
示例#5
0
 def __init__(self, ctl, address, addr_str, operation, comment_index, comment, preserve_base):
     self.ctl = ctl
     self.address = address
     self.addr_str = addr_str
     self.comment_index = comment_index
     self.comment = comment
     self.operation = operation
     if operation:
         self.inst_ctl = get_instruction_ctl(operation)
         if self.inst_ctl == 'C':
             size = get_size(operation, address)
             length = [get_operand_bases(operation, preserve_base), size]
         elif self.inst_ctl == 'B':
             size, length = get_defb_length(self.operation, preserve_base)
         elif self.inst_ctl == 'T':
             size, length = get_defb_length(self.operation, preserve_base)
         elif self.inst_ctl == 'W':
             size, length = get_defw_length(self.operation, preserve_base)
         else:
             size, length = get_defs_length(self.operation, preserve_base)
         self.end = address + size
         self.lengths = [length]
     else:
         self.inst_ctl = 'I'
示例#6
0
    def _parse_skool(self, skoolfile, min_address, max_address):
        map_entry = None
        instruction = None
        comments = []
        ignores = []
        address_comments = []
        for line in skoolfile:
            if line.startswith(';'):
                if self.mode.include:
                    comments.append(line[2:].rstrip())
                instruction = None
                address_comments.append((None, None))
                continue

            if line.startswith('@'):
                self._parse_asm_directive(line[1:].rstrip(), ignores, len(comments))
                continue

            if not self.mode.include:
                continue

            s_line = line.strip()
            if not s_line:
                instruction = None
                address_comments.append((None, None))
                if comments and map_entry:
                    map_entry.end_comment = join_comments(comments, True)
                comments[:] = []
                map_entry = None
                continue

            if s_line.startswith(';'):
                if map_entry and instruction:
                    # This is an instruction comment continuation line
                    address_comments[-1][1] = '{} {}'.format(address_comments[-1][1], s_line[1:].lstrip())
                continue # pragma: no cover

            # This line contains an instruction
            instruction, address_comment = self._parse_instruction(line)
            address = instruction.address
            if address < min_address:
                continue
            if address >= max_address:
                map_entry = None
                break
            ctl = instruction.ctl
            if ctl in DIRECTIVES:
                start_comment, desc, details, registers = parse_comment_block(comments, ignores, self.mode)
                map_entry = Entry(ctl, desc, details, registers, self.mode.entry_ignoreua)
                instruction.mid_block_comment = start_comment
                map_entry.asm_directives = extract_entry_asm_directives(instruction.asm_directives)
                self.memory_map.append(map_entry)
                comments[:] = []
                instruction.ignoremrcua = self.mode.ignoremrcua
            elif ctl in 'dr':
                # This is a data definition entry or a remote entry
                map_entry = None

            if map_entry:
                address_comments.append([instruction, address_comment])
                map_entry.add_instruction(instruction)
                if comments:
                    instruction.mid_block_comment = join_comments(comments, True)
                    comments[:] = []
                    instruction.ignoremrcua = 0 in ignores
                    instruction.ignoreua = any(ignores)
                elif ignores:
                    instruction.ignoreua = True

            ignores[:] = []

        if comments and map_entry:
            map_entry.end_comment = join_comments(comments, True)
            map_entry.ignoreua[END] = len(ignores) > 0

        last_entry = None
        last_instruction = None
        for entry in self.memory_map:
            entry.sort_instructions()
            if last_entry is None or last_entry.address < entry.address:
                last_entry = entry
            end_instruction = entry.instructions[-1]
            if last_instruction is None or last_instruction.address < end_instruction.address:
                last_instruction = end_instruction
        if last_entry is not None and last_entry.ctl != 'i':
            address = last_instruction.address
            self.end_address = address + (get_size(last_instruction.operation, address) or 1)

        parse_address_comments(address_comments)
示例#7
0
 def _calculate_entry_sizes(self):
     for entry in self.memory_map:
         address = max([i.address for i in entry.instructions if i.address is not None])
         last_instruction = self.get_instruction(address)
         entry.size = address + (get_size(last_instruction.operation, address) or 1) - entry.address
示例#8
0
    def _parse_skool(self, skoolfile, min_address, max_address):
        map_entry = None
        instruction = None
        address_comments = []
        for line in skoolfile:
            if line.startswith(';'):
                if self.mode.started and self.mode.include:
                    self.comments.append(line[2:].rstrip())
                    self.mode.ignoreua = False
                instruction = None
                address_comments.append((None, None))
                continue

            if line.startswith('@'):
                self._parse_asm_directive(line[1:].rstrip())
                continue

            if not self.mode.include:
                continue

            s_line = line.strip()
            if not s_line:
                instruction = None
                address_comments.append((None, None))
                if self.comments:
                    if map_entry:
                        self._add_end_comment(map_entry)
                    else:
                        self.header += self.comments
                self.comments[:] = []
                self.ignores[:] = []
                map_entry = None
                continue

            if s_line[0] == ';' and map_entry and instruction:
                # This is an instruction comment continuation line
                address_comments[-1][1] = '{0} {1}'.format(address_comments[-1][1], s_line[1:].lstrip())
                continue

            # This line contains an instruction
            instruction, address_comment = self._parse_instruction(line)
            address = instruction.address
            addr_str = instruction.addr_str
            ctl = instruction.ctl
            if ctl in DIRECTIVES:
                if address is None:
                    raise SkoolParsingError("Invalid address: '{}'".format(addr_str))
                start_comment, desc, details, registers = parse_comment_block(self.comments, self.ignores, self.mode)
                map_entry = SkoolEntry(address, addr_str, ctl, desc, details, registers)
                instruction.mid_block_comment = start_comment
                map_entry.ignoreua.update(self.mode.entry_ignoreua)
                self.mode.reset_entry_ignoreua()
                self._entries[address] = map_entry
                self.memory_map.append(map_entry)
                self.comments[:] = []
                self.base_address = min((address, self.base_address))
            elif ctl == 'd':
                # This is a data definition entry
                map_entry = None
            elif ctl == 'r':
                # This is a remote entry
                map_entry = RemoteEntry(instruction.operation, address)

            if map_entry:
                address_comments.append([instruction, address_comment])
                if address is not None:
                    self._instructions.setdefault(address, []).append(instruction)
                map_entry.add_instruction(instruction)
                if self.comments:
                    instruction.mid_block_comment = join_comments(self.comments, split=True, html=self.mode.html)
                    self.comments[:] = []
                    self.mode.ignoremrcua = 0 in self.ignores

            self.mode.apply_asm_attributes(instruction)
            self.ignores[:] = []

            # Set bytes in the snapshot if the instruction is DEF{B,M,S,W}
            if address is not None:
                operation = instruction.operation
                if self.mode.assemble or operation.upper().startswith(('DEFB ', 'DEFM ', 'DEFS ', 'DEFW ')):
                    set_bytes(self.snapshot, address, operation)
        if self.comments and map_entry:
            self._add_end_comment(map_entry)

        if min_address > 0 or max_address < 65536:
            self.memory_map = [e for e in self.memory_map if min_address <= e.address < max_address]
            self._entries = {k: v for k, v in self._entries.items() if min_address <= k < max_address}
            if self._entries:
                self.base_address = min(self._entries)
                last_entry = self._entries[max(self._entries)]
                last_entry.instructions = [i for i in last_entry.instructions if i.address is None or i.address < max_address]
            else:
                self.base_address = max_address
            self._instructions = {k: v for k, v in self._instructions.items() if self.base_address <= k < max_address}
            address_comments = [c for c in address_comments if c[0] is None or c[0].address is None or self.base_address <= c[0].address < max_address]

        if self.memory_map:
            end_address = max([i.address for e in self.memory_map for i in e.instructions if i.address is not None])
            last_instruction = self.get_instruction(end_address)
            self.end_address = end_address + (get_size(last_instruction.operation, end_address) or 1)

        # Do some post-processing
        parse_address_comments(address_comments, self.mode.html)
        self.make_replacements(self)
        self._calculate_references()
        if self.mode.asm_labels:
            self._generate_labels()
        if self.mode.html:
            self._calculate_entry_sizes()
            self._escape_instructions()
        else:
            self._substitute_labels()
示例#9
0
 def _test_operation(self, operation, exp_data, address):
     data = assemble(operation, address)
     self.assertEqual(exp_data, data, "assemble('{}', {}) failed".format(operation, address))
     exp_length = len(data)
     length = get_size(operation, address)
     self.assertEqual(exp_length, length, "get_size('{}', {}) failed".format(operation, address))
示例#10
0
    def _parse_skool(self, skoolfile, min_address, max_address):
        address_comments = []
        non_entries = []
        for non_entry, block in read_skool(skoolfile, 1):
            if non_entry:
                non_entries.append(block)
                continue
            map_entry = None
            instruction = None
            comments = []
            ignores = []
            address_comments.append((None, None, None))
            for line in block:
                if line.startswith(';'):
                    comments.append(line[1:])
                    instruction = None
                    address_comments.append((None, None, None))
                    continue

                if line.startswith('@'):
                    self._parse_asm_directive(line[1:], ignores, len(comments))
                    continue

                s_line = line.lstrip()
                if s_line.startswith(';'):
                    if map_entry and instruction:
                        # This is an instruction comment continuation line
                        address_comments[-1][1].append(s_line[1:].lstrip())
                    continue

                # This line contains an instruction
                instruction, address_comment = self._parse_instruction(line)
                address = instruction.address
                if address < min_address:
                    continue
                if address >= max_address:
                    map_entry = None
                    break
                ctl = instruction.ctl
                if ctl in DIRECTIVES:
                    start_comment, desc, details, registers = parse_comment_block(comments, ignores, self.mode)
                    map_entry = Entry(ctl, desc, details, registers, self.mode.entry_ignoreua)
                    instruction.mid_block_comment = start_comment
                    map_entry.asm_directives = extract_entry_asm_directives(instruction.asm_directives)
                    self.memory_map.append(map_entry)
                    comments[:] = []
                    instruction.ignoremrcua = self.mode.ignoremrcua

                if map_entry:
                    address_comments.append((instruction, [address_comment], []))
                    map_entry.add_instruction(instruction)
                    if comments:
                        instruction.mid_block_comment = join_comments(comments, True)
                        comments[:] = []
                        instruction.ignoremrcua = 0 in ignores
                        instruction.ignoreua = any(ignores)
                    elif ignores:
                        instruction.ignoreua = True

                ignores[:] = []

            if map_entry:
                if comments:
                    map_entry.end_comment = join_comments(comments, True)
                    map_entry.ignoreua[END] = len(ignores) > 0
                map_entry.header = non_entries
                non_entries = []

        if self.memory_map:
            self.memory_map[-1].footer = non_entries

        last_entry = None
        last_instruction = None
        for entry in self.memory_map:
            entry.sort_instructions()
            if last_entry is None or last_entry.address < entry.address:
                last_entry = entry
            end_instruction = entry.instructions[-1]
            if last_instruction is None or last_instruction.address < end_instruction.address:
                last_instruction = end_instruction
        if last_entry is not None and last_entry.ctl != 'i':
            address = last_instruction.address
            self.end_address = address + (get_size(last_instruction.operation, address) or 1)

        parse_address_comments(address_comments)
示例#11
0
    def _parse_skool(self, skoolfile, min_address, max_address):
        address_comments = []
        non_entries = []
        done = False
        for non_entry, block in read_skool(skoolfile, 1):
            if non_entry:
                non_entries.append(block)
                continue
            map_entry = None
            instruction = None
            comments = []
            ignores = []
            address_comments.append((None, None, None))
            for line in block:
                if line.startswith(';'):
                    self._parse_comment_line(comments, line)
                    instruction = None
                    address_comments.append((None, None, None))
                    continue

                if line.startswith('@'):
                    self._parse_asm_directive(line[1:], ignores, len(comments))
                    continue

                s_line = line.lstrip()
                if s_line.startswith(';'):
                    if map_entry and instruction:
                        # This is an instruction comment continuation line
                        self._parse_comment_line(address_comments[-1][1], s_line)
                    continue

                # This line contains an instruction
                instruction, address_comment = self._parse_instruction(line)
                address = instruction.address
                if address < min_address:
                    non_entries.clear()
                    break
                if address >= max_address:
                    non_entries.clear()
                    map_entry = None
                    done = True
                    break
                ctl = instruction.ctl
                if ctl in DIRECTIVES:
                    start_comment, title, description, registers = parse_comment_block(comments, ignores, self.mode, self.keep_lines)
                    map_entry = Entry(ctl, title, description, registers, self.mode.entry_ignoreua)
                    instruction.mid_block_comment = start_comment
                    map_entry.asm_directives = extract_entry_asm_directives(instruction.asm_directives)
                    self.memory_map.append(map_entry)
                    comments[:] = []
                    instruction.ignoremrcua = self.mode.ignoremrcua

                if map_entry:
                    address_comments.append((instruction, [address_comment], []))
                    map_entry.add_instruction(instruction)
                    if comments:
                        instruction.mid_block_comment = join_comments(comments, True, self.keep_lines)
                        comments = []
                        instruction.ignoremrcua = 0 in ignores
                        instruction.ignoreua = any(ignores)
                    elif ignores:
                        instruction.ignoreua = True

                ignores[:] = []

            if map_entry:
                if comments:
                    map_entry.end_comment = join_comments(comments, True, self.keep_lines)
                    map_entry.ignoreua[END] = len(ignores) > 0
                map_entry.header = non_entries
                non_entries = []

            if done:
                break

        if self.memory_map:
            self.memory_map[-1].footer = non_entries

        last_entry = None
        last_instruction = None
        for entry in self.memory_map:
            entry.sort_instructions()
            if last_entry is None or last_entry.address < entry.address:
                last_entry = entry
            end_instruction = entry.instructions[-1]
            if last_instruction is None or last_instruction.address < end_instruction.address:
                last_instruction = end_instruction
        if last_entry is not None and last_entry.ctl != 'i':
            address = last_instruction.address
            self.end_address = address + (get_size(last_instruction.operation, address) or 1)

        parse_address_comments(address_comments, self.keep_lines)
示例#12
0
 def _calculate_entry_sizes(self):
     for entry in self.memory_map:
         address = max([i.address for i in entry.instructions if i.address is not None])
         last_instruction = self.get_instruction(address)
         entry.size = address + (get_size(last_instruction.operation, address) or 1) - entry.address
示例#13
0
    def _parse_skool(self, skoolfile, min_address, max_address):
        map_entry = None
        instruction = None
        address_comments = []
        for line in skoolfile:
            if line.startswith(';'):
                if self.mode.started and self.mode.include:
                    self.comments.append(line[2:].rstrip())
                    self.mode.ignoreua = False
                instruction = None
                address_comments.append((None, None))
                continue

            if line.startswith('@'):
                self._parse_asm_directive(line[1:].rstrip())
                continue

            if not self.mode.include:
                continue

            s_line = line.strip()
            if not s_line:
                instruction = None
                address_comments.append((None, None))
                if self.comments:
                    if map_entry:
                        self._add_end_comment(map_entry)
                    else:
                        self.header += self.comments
                self.comments[:] = []
                self.ignores[:] = []
                map_entry = None
                continue

            if s_line[0] == ';' and map_entry and instruction:
                # This is an instruction comment continuation line
                address_comments[-1][1] = '{0} {1}'.format(address_comments[-1][1], s_line[1:].lstrip())
                continue

            # This line contains an instruction
            instruction, address_comment = self._parse_instruction(line)
            address = instruction.address
            addr_str = instruction.addr_str
            ctl = instruction.ctl
            if ctl in DIRECTIVES:
                if address is None:
                    raise SkoolParsingError("Invalid address: '{}'".format(addr_str))
                start_comment, desc, details, registers = parse_comment_block(self.comments, self.ignores, self.mode)
                map_entry = SkoolEntry(address, addr_str, ctl, desc, details, registers)
                instruction.mid_block_comment = start_comment
                map_entry.ignoreua.update(self.mode.entry_ignoreua)
                self.mode.reset_entry_ignoreua()
                self._entries[address] = map_entry
                self.memory_map.append(map_entry)
                self.comments[:] = []
                self.base_address = min((address, self.base_address))
            elif ctl == 'd':
                # This is a data definition entry
                map_entry = None
            elif ctl == 'r':
                # This is a remote entry
                map_entry = RemoteEntry(instruction.operation, address)

            if map_entry:
                address_comments.append([instruction, address_comment])
                if address is not None:
                    self._instructions.setdefault(address, []).append(instruction)
                map_entry.add_instruction(instruction)
                if self.comments:
                    instruction.mid_block_comment = join_comments(self.comments, split=True, html=self.mode.html)
                    self.comments[:] = []
                    self.mode.ignoremrcua = 0 in self.ignores

            self.mode.apply_asm_attributes(instruction)
            self.ignores[:] = []

            # Set bytes in the snapshot if the instruction is DEF{B,M,S,W}
            if address is not None:
                operation = instruction.operation
                if self.mode.assemble or operation.upper().startswith(('DEFB ', 'DEFM ', 'DEFS ', 'DEFW ')):
                    set_bytes(self.snapshot, address, operation)
        if self.comments and map_entry:
            self._add_end_comment(map_entry)

        if min_address > 0 or max_address < 65536:
            self.memory_map = [e for e in self.memory_map if min_address <= e.address < max_address]
            self._entries = {k: v for k, v in self._entries.items() if min_address <= k < max_address}
            if self._entries:
                self.base_address = min(self._entries)
                last_entry = self._entries[max(self._entries)]
                last_entry.instructions = [i for i in last_entry.instructions if i.address is None or i.address < max_address]
            else:
                self.base_address = max_address
            self._instructions = {k: v for k, v in self._instructions.items() if self.base_address <= k < max_address}
            address_comments = [c for c in address_comments if c[0] is None or c[0].address is None or self.base_address <= c[0].address < max_address]

        if self.memory_map:
            end_address = max([i.address for e in self.memory_map for i in e.instructions if i.address is not None])
            last_instruction = self.get_instruction(end_address)
            self.end_address = end_address + (get_size(last_instruction.operation, end_address) or 1)

        # Do some post-processing
        parse_address_comments(address_comments, self.mode.html)
        self.make_replacements(self)
        self._calculate_references()
        if self.mode.asm_labels:
            self._generate_labels()
        if self.mode.html:
            self._calculate_entry_sizes()
            self._escape_instructions()
        else:
            self._substitute_labels()
示例#14
0
    def _parse_skool(self, skoolfile, min_address, max_address):
        map_entry = None
        instruction = None
        comments = []
        ignores = []
        address_comments = []
        for line in skoolfile:
            if line.startswith(';'):
                if self.mode.include:
                    comments.append(line[2:].rstrip())
                instruction = None
                address_comments.append((None, None))
                continue

            if line.startswith('@'):
                self._parse_asm_directive(line[1:].rstrip(), ignores,
                                          len(comments))
                continue

            if not self.mode.include:
                continue

            s_line = line.strip()
            if not s_line:
                instruction = None
                address_comments.append((None, None))
                if comments and map_entry:
                    map_entry.end_comment = join_comments(comments, True)
                comments[:] = []
                map_entry = None
                continue

            if s_line.startswith(';'):
                if map_entry and instruction:
                    # This is an instruction comment continuation line
                    address_comments[-1][1] = '{} {}'.format(
                        address_comments[-1][1], s_line[1:].lstrip())
                continue  # pragma: no cover

            # This line contains an instruction
            instruction, address_comment = self._parse_instruction(line)
            address = instruction.address
            if address < min_address:
                continue
            if address >= max_address:
                map_entry = None
                break
            ctl = instruction.ctl
            if ctl in DIRECTIVES:
                start_comment, desc, details, registers = parse_comment_block(
                    comments, ignores, self.mode)
                map_entry = Entry(ctl, desc, details, registers,
                                  self.mode.entry_ignoreua)
                instruction.mid_block_comment = start_comment
                map_entry.asm_directives = extract_entry_asm_directives(
                    instruction.asm_directives)
                self.memory_map.append(map_entry)
                comments[:] = []
                instruction.ignoremrcua = self.mode.ignoremrcua
            elif ctl in 'dr':
                # This is a data definition entry or a remote entry
                map_entry = None

            if map_entry:
                address_comments.append([instruction, address_comment])
                map_entry.add_instruction(instruction)
                if comments:
                    instruction.mid_block_comment = join_comments(
                        comments, True)
                    comments[:] = []
                    instruction.ignoremrcua = 0 in ignores
                    instruction.ignoreua = any(ignores)
                elif ignores:
                    instruction.ignoreua = True

            ignores[:] = []

        if comments and map_entry:
            map_entry.end_comment = join_comments(comments, True)
            map_entry.ignoreua[END] = len(ignores) > 0

        last_entry = None
        last_instruction = None
        for entry in self.memory_map:
            entry.sort_instructions()
            if last_entry is None or last_entry.address < entry.address:
                last_entry = entry
            end_instruction = entry.instructions[-1]
            if last_instruction is None or last_instruction.address < end_instruction.address:
                last_instruction = end_instruction
        if last_entry is not None and last_entry.ctl != 'i':
            address = last_instruction.address
            self.end_address = address + (get_size(last_instruction.operation,
                                                   address) or 1)

        parse_address_comments(address_comments)