示例#1
0
 def _parse_skool(self, skoolfile):
     entry_ctl = None
     f = open_file(skoolfile)
     for line in f:
         if line.startswith(';'):
             continue
         if line.startswith('@'):
             self._parse_asm_directive(line[1:].rstrip())
             continue
         if not self.include:
             continue
         s_line = line.strip()
         if not s_line:
             # This line is blank
             entry_ctl = None
             continue
         # Check whether we're in a block that can be skipped
         if entry_ctl is None and line.startswith(SKIP_BLOCKS):
             entry_ctl = line[0]
         if entry_ctl in SKIP_BLOCKS:
             continue
         if s_line.startswith(';'):
             # This line is a continuation of an instruction comment
             continue
         if line[0] in VALID_CTLS:
             # This line contains an instruction
             self._parse_instruction(line)
     f.close()
示例#2
0
 def _parse_skool(self, skoolfile):
     entry_ctl = None
     f = open_file(skoolfile)
     for line in f:
         if line.startswith(';'):
             continue
         if line.startswith('@'):
             self._parse_asm_directive(line[1:].rstrip())
             continue
         if not self.include:
             continue
         s_line = line.strip()
         if not s_line:
             # This line is blank
             entry_ctl = None
             continue
         # Check whether we're in a block that can be skipped
         if entry_ctl is None and line.startswith(SKIP_BLOCKS):
             entry_ctl = line[0]
         if entry_ctl in SKIP_BLOCKS:
             continue
         if s_line.startswith(';'):
             # This line is a continuation of an instruction comment
             continue
         if line[0] in VALID_CTLS:
             # This line contains an instruction
             self._parse_instruction(line)
     f.close()
示例#3
0
    def __init__(self, skoolfile, case=None, base=None, asm_mode=0, warnings=False, fix_mode=0, html=False,
                 create_labels=False, asm_labels=True, min_address=0, max_address=65536):
        self.skoolfile = skoolfile
        self.mode = Mode(case, base, asm_mode, warnings, fix_mode, html, create_labels, asm_labels)
        self.case = case
        self.base = base

        self.snapshot = [0] * 65536  # 64K of Spectrum memory
        self._instructions = {}      # address -> [Instructions]
        self._entries = {}           # address -> SkoolEntry
        self.memory_map = []         # SkoolEntry instances
        self.base_address = 65536
        self.end_address = 0
        self.header = []
        self.stack = []
        self.comments = []
        self.ignores = []
        self.asm_writer_class = None
        self.properties = {}
        self._replacements = []
        self.equs = []
        self._equ_values = {}

        with open_file(skoolfile) as f:
            self._parse_skool(f, min_address, max_address)
示例#4
0
def _get_tape(urlstring, member=None):
    url = urlparse(urlstring)
    if url.scheme:
        write_line('Downloading {0}'.format(urlstring))
        u = urlopen(urlstring, timeout=30)
        f = tempfile.NamedTemporaryFile(prefix='tap2sna-')
        while 1:
            data = bytearray(u.read(4096))
            if data:
                f.write(data)
            else:
                break
    elif url.path:
        f = open_file(url.path, 'rb')

    if urlstring.lower().endswith('.zip'):
        z = zipfile.ZipFile(f)
        if member is None:
            for name in z.namelist():
                if name.lower().endswith(('.tap', '.tzx')):
                    member = name
                    break
            else:
                raise TapeError('No TAP or TZX file found')
        write_line('Extracting {0}'.format(member))
        tape = z.open(member)
        data = bytearray(tape.read())
        tape_type = member[-3:]
    else:
        tape_type = urlstring[-3:]
        f.seek(0)
        data = bytearray(f.read())

    f.close()
    return tape_type, data
示例#5
0
    def __init__(self, skoolfile, preserve_base, min_address, max_address):
        self.skoolfile = skoolfile
        self.preserve_base = preserve_base
        self.mode = Mode()
        self.memory_map = []
        self.end_address = 65536

        with open_file(skoolfile) as f:
            self._parse_skool(f, min_address, max_address)
示例#6
0
    def __init__(self, skoolfile, preserve_base, min_address, max_address):
        self.skoolfile = skoolfile
        self.preserve_base = preserve_base
        self.mode = Mode()
        self.memory_map = []
        self.stack = []
        self.end_address = 65536

        with open_file(skoolfile) as f:
            self._parse_skool(f, min_address, max_address)
示例#7
0
文件: ctlparser.py 项目: dpt/skoolkit
 def _parse_ctl_file(self, ctlfile, ctl_lines, min_address, max_address):
     with open_file(ctlfile) as f:
         for line in f:
             s_line = line.rstrip()
             if s_line:
                 ctl_lines.append(s_line)
                 if s_line.startswith(('b', 'c', 'g', 'i', 's', 't', 'u', 'w')):
                     try:
                         address = get_int_param(s_line[1:].lstrip().split(' ', 1)[0])
                         if min_address <= address < max_address:
                             self._ctls[address] = s_line[0]
                     except ValueError:
                         pass
示例#8
0
 def _parse_ctl_file(self, ctlfile, ctl_lines, min_address, max_address):
     with open_file(ctlfile) as f:
         for line in f:
             s_line = line.rstrip()
             if s_line:
                 ctl_lines.append(s_line)
                 if s_line.startswith(('b', 'c', 'g', 'i', 's', 't', 'u', 'w')):
                     try:
                         address = get_int_param(s_line[1:].lstrip().split(' ', 1)[0])
                         if min_address <= address < max_address:
                             self._ctls[address] = s_line[0]
                     except ValueError:
                         pass
示例#9
0
文件: skoolctl.py 项目: dpt/skoolkit
    def __init__(self, skoolfile, preserve_base, assembler, min_address,
                 max_address, keep_lines):
        self.skoolfile = skoolfile
        self.mode = Mode()
        self.memory_map = []
        self.end_address = 65536
        self.keep_lines = keep_lines
        self.assembler = assembler
        self.composer = get_component('ControlDirectiveComposer',
                                      preserve_base)

        with open_file(skoolfile) as f:
            self._parse_skool(f, min_address, max_address)
示例#10
0
 def _parse_skool(self, skoolfile):
     f = open_file(skoolfile)
     removed = set()
     for non_entry, block in read_skool(f, 2, self.asm_mode, self.fix_mode):
         if non_entry:
             continue
         for line in block:
             if line.startswith('@'):
                 self._parse_asm_directive(line[1:])
             elif not line.lstrip().startswith(
                     ';') and line[0] in VALID_CTLS:
                 self._parse_instruction(line, removed)
     f.close()
示例#11
0
def _get_code_blocks(snapshot, start, end, fname):
    if os.path.isdir(fname):
        raise SkoolKitError('{0} is a directory'.format(fname))
    try:
        size = os.path.getsize(fname)
    except OSError as e:
        if e.errno == 2:
            raise SkoolKitError('{0}: file not found'.format(fname))
        raise SkoolKitError('Failed to get size of {}: {}'.format(
            fname, e.strerror))

    if size == 8192:
        # Assume this is a Z80 map file
        sys.stderr.write('Reading {0}'.format(fname))
        sys.stderr.flush()
        addresses = []
        data = read_bin_file(fname)
        address = start & 65528
        for b in data[start // 8:end // 8 + 1]:
            for i in range(8):
                if b & 1 and start <= address < end:
                    addresses.append(address)
                b >>= 1
                address += 1
    elif size == 65536:
        # Assume this is a SpecEmu map file
        sys.stderr.write('Reading {}'.format(fname))
        sys.stderr.flush()
        addresses = []
        data = read_bin_file(fname)
        for address in range(start, end):
            if data[address] & 1:
                addresses.append(address)
    else:
        sys.stderr.write('Reading {0}: '.format(fname))
        sys.stderr.flush()
        with open_file(fname) as f:
            addresses = _get_addresses(f, fname, size, start, end)
    sys.stderr.write('\n')

    code_blocks = []
    disassembler = Disassembler(snapshot)
    for address in addresses:
        size = disassembler.disassemble(address, address + 1)[0].size()
        if code_blocks and address <= sum(code_blocks[-1]):
            if address == sum(code_blocks[-1]):
                code_blocks[-1][1] += size
        else:
            code_blocks.append([address, size])

    return code_blocks
示例#12
0
def _get_code_blocks(snapshot, start, end, fname):
    if os.path.isdir(fname):
        raise SkoolKitError('{0} is a directory'.format(fname))
    try:
        size = os.path.getsize(fname)
    except OSError as e:
        if e.errno == 2:
            raise SkoolKitError('{0}: file not found'.format(fname))
        raise # pragma: no cover

    if size == 8192:
        # Assume this is a Z80 map file
        sys.stderr.write('Reading {0}'.format(fname))
        sys.stderr.flush()
        addresses = []
        data = read_bin_file(fname)
        address = start & 65528
        for b in data[start // 8:end // 8 + 1]:
            for i in range(8):
                if b & 1 and start <= address < end:
                    addresses.append(address)
                b >>= 1
                address += 1
    elif size == 65536:
        # Assume this is a SpecEmu map file
        sys.stderr.write('Reading {}'.format(fname))
        sys.stderr.flush()
        addresses = []
        data = read_bin_file(fname)
        for address in range(start, end):
            if data[address] & 1:
                addresses.append(address)
    else:
        sys.stderr.write('Reading {0}: '.format(fname))
        sys.stderr.flush()
        with open_file(fname) as f:
            addresses = _get_addresses(f, fname, size, start, end)
    sys.stderr.write('\n')

    code_blocks = []
    disassembler = Disassembler(snapshot)
    for address in addresses:
        size = disassembler.disassemble(address, address + 1)[0].size()
        if code_blocks and address <= sum(code_blocks[-1]):
            if address == sum(code_blocks[-1]):
                code_blocks[-1][1] += size
        else:
            code_blocks.append([address, size])

    return code_blocks
示例#13
0
    def _parse_skool(self, min_address, max_address):
        sft = []
        f = open_file(self.skoolfile)
        for non_entry, block in read_skool(f):
            lines = []
            for line in block:
                if line.startswith(';'):
                    lines.append(VerbatimLine(line))
                    continue
                if line.startswith('@'):
                    lines.append(VerbatimLine(line))
                    self._parse_asm_directive(line[1:])
                    continue
                if self.verbatim:
                    # This line is inside a '+' block, so include it as is
                    lines.append(VerbatimLine(line))
                    continue
                s_line = line.lstrip()
                if not s_line:
                    # This line is blank
                    lines.append(VerbatimLine(line))
                    continue
                if s_line.startswith(';'):
                    # This line is a continuation of an instruction comment
                    comment_index = line.index(';')
                    lines.append(
                        VerbatimLine(" ;{} {}".format(
                            comment_index, line[comment_index + 1:].lstrip())))
                elif line[0] in VALID_CTLS:
                    # This line contains an instruction
                    ctl_line = self._parse_instruction(line)
                    if ctl_line.address >= max_address:
                        while lines and lines[-1].is_trimmable():
                            lines.pop()
                        if lines:
                            lines.append(VerbatimLine(''))
                        break
                    if ctl_line.address < min_address:
                        lines[:] = []
                        break
                    lines.append(ctl_line)
                else:
                    lines.append(VerbatimLine(line))
            sft.extend(lines)
        f.close()

        while sft and sft[-1].is_blank():
            sft.pop()
        return self._compress_blocks(sft)
示例#14
0
 def write(self, binfile, start, end):
     if start is None:
         base_address = self.base_address
     else:
         base_address = start
     if end is None:
         end_address = self.end_address
     else:
         end_address = end
     data = self.snapshot[base_address:end_address]
     with open_file(binfile, 'wb') as f:
         f.write(bytearray(data))
     if binfile == '-':
         binfile = 'stdout'
     info("Wrote {}: start={}, end={}, size={}".format(binfile, base_address, end_address, len(data)))
示例#15
0
 def write(self, binfile, start, end):
     if start is None:
         base_address = self.base_address
     else:
         base_address = start
     if end is None:
         end_address = self.end_address
     else:
         end_address = end
     data = self.snapshot[base_address:end_address]
     with open_file(binfile, 'wb') as f:
         f.write(bytearray(data))
     if binfile == '-':
         binfile = 'stdout'
     info("Wrote {}: start={}, end={}, size={}".format(binfile, base_address, end_address, len(data)))
示例#16
0
 def write(self, binfile):
     if self.start < 0:
         base_address = self.base_address
     else:
         base_address = max(self.start, self.base_address)
     if self.end > 65536:
         end_address = self.end_address
     else:
         end_address = min(self.end, self.end_address)
     base_address = min(base_address, end_address)
     data = self.snapshot[base_address:end_address]
     with open_file(binfile, 'wb') as f:
         f.write(bytearray(data))
     if binfile == '-':
         binfile = 'stdout'
     info("Wrote {}: start={}, end={}, size={}".format(
         binfile, base_address, end_address, len(data)))
示例#17
0
def run(snafile, options, config):
    words = set()
    dict_fname = config['Dictionary']
    if dict_fname:
        if find_file(dict_fname):
            info("Using dictionary file: {}".format(dict_fname))
            with open_file(config['Dictionary']) as f:
                for line in f:
                    word = line.strip().lower()
                    if word:
                        words.add(word)
        else:
            info("Dictionary file '{}' not found".format(dict_fname))
    ctl_config = Config(config['TextChars'], config['TextMinLengthCode'], config['TextMinLengthData'], words)
    snapshot, start, end = make_snapshot(snafile, options.org, options.start, options.end, options.page)
    ctls = get_component('ControlFileGenerator').generate_ctls(snapshot, start, end, options.code_map, ctl_config)
    write_ctl(ctls, options.ctl_hex)
示例#18
0
 def _parse_skool(self, skoolfile):
     f = open_file(skoolfile)
     address = None
     for non_entry, block in read_skool(f, 2, self.asm_mode, self.fix_mode):
         if non_entry:
             continue
         removed = set()
         for line in block:
             if line.startswith('@'):
                 address = self._parse_asm_directive(
                     address, line[1:], removed)
             elif not line.lstrip().startswith(
                     ';') and line[0] in VALID_CTLS:
                 address = self._parse_instruction(address, line, removed)
         self.entries.append(Entry(self.entry_ctl, self.instructions))
         self.entry_ctl = None
         self.instructions = []
     f.close()
示例#19
0
    def parse(self, reffile):
        """Parse a ref file. This method may be called as many times as
        required to collect sections from multiple ref files.

        :param reffile: The name of the ref file to parse.
        """
        section_name = None
        section_lines = []
        infile = open_file(reffile)
        for line in infile:
            s_line = line.rstrip()
            if s_line.startswith(('[[', ';;')):
                section_lines.append(s_line[1:])
            elif s_line.startswith('[') and s_line.endswith(']'):
                self._add_section(section_name, section_lines)
                section_name = s_line[1:-1]
                section_lines = []
            elif not s_line.startswith(';'):
                section_lines.append(s_line)
        infile.close()
        self._add_section(section_name, section_lines)
示例#20
0
    def parse(self, reffile):
        """Parse a ref file. This method may be called as many times as
        required to collect sections from multiple ref files.

        :param reffile: The name of the ref file to parse.
        """
        section_name = None
        section_lines = []
        infile = open_file(reffile)
        for line in infile:
            s_line = line.rstrip()
            if s_line.startswith(('[[', ';;')):
                section_lines.append(s_line[1:])
            elif s_line.startswith('[') and s_line.endswith(']'):
                self._add_section(section_name, section_lines)
                section_name = s_line[1:-1]
                section_lines = []
            elif not s_line.startswith(';'):
                section_lines.append(s_line)
        infile.close()
        self._add_section(section_name, section_lines)
示例#21
0
def _get_tape(urlstring, member=None):
    url = urlparse(urlstring)
    if url.scheme:
        write_line('Downloading {0}'.format(urlstring))
        r = Request(urlstring, headers={'User-Agent': ''})
        u = urlopen(r, timeout=30)
        f = tempfile.NamedTemporaryFile(prefix='tap2sna-')
        while 1:
            data = bytearray(u.read(4096))
            if data:
                f.write(data)
            else:
                break
    elif url.path:
        f = open_file(url.path, 'rb')

    if urlstring.lower().endswith('.zip'):
        z = zipfile.ZipFile(f)
        if member is None:
            for name in z.namelist():
                if name.lower().endswith(('.tap', '.tzx')):
                    member = name
                    break
            else:
                f.close()
                raise TapeError('No TAP or TZX file found')
        write_line('Extracting {0}'.format(member))
        tape = z.open(member)
        data = bytearray(tape.read())
        tape_type = member[-3:]
    else:
        tape_type = urlstring[-3:]
        f.seek(0)
        data = bytearray(f.read())

    f.close()
    return tape_type, data
示例#22
0
    def parse_ctl(self, ctlfile, min_address=0, max_address=65536):
        entry_ctl = None
        f = open_file(ctlfile)
        for line_no, line in enumerate(f, 1):
            s_line = line.rstrip()
            if not s_line:
                continue
            try:
                ctl, start, end, text, lengths, asm_directive = self._parse_ctl_line(s_line, entry_ctl)
            except CtlParserError as e:
                warn('Ignoring line {} in {} ({}):\n{}'.format(line_no, ctlfile, e.args[0], s_line))
                continue
            if ctl:
                ctl = ctl.strip()
                if ctl.islower():
                    entry_ctl = ctl
                if not min_address <= start < max_address:
                    continue
                if ctl.islower():
                    self._ctls[start] = ctl
                    self._titles[start] = text
                elif ctl in 'D':
                    self._descriptions.setdefault(start, []).append(text)
                    self._subctls.setdefault(start, None)
                elif ctl in 'N':
                    self._mid_block_comments.setdefault(start, []).append(text)
                    self._subctls.setdefault(start, None)
                elif ctl == 'E':
                    self._end_comments.setdefault(start, []).append(text)
                elif ctl == 'R':
                    if text:
                        fields = text.split(' ', 1)
                        if len(fields) == 1:
                            fields.append('')
                        self._registers.setdefault(start, []).append(fields)
                elif ctl == 'M':
                    self._multiline_comments[start] = (end, text)
                    self._subctls.setdefault(start, None)
                elif ctl == 'L':
                    count = lengths[0][0]
                    if count > 1:
                        if len(lengths) > 1:
                            repeat_entries = lengths[1][0]
                        else:
                            repeat_entries = 0
                        loop_end = start + count * (end - start)
                        if loop_end > 65536:
                            warn('Loop crosses 64K boundary:\n{}'.format(s_line))
                        self._loops.append((start, end, count, repeat_entries))
                        self._subctls[loop_end] = None
                else:
                    self._subctls[start] = ctl.lower()
                    self._instruction_comments[start] = text
                    if end:
                        self._subctls[end] = None
                if ctl != 'L' and lengths:
                    self._lengths[start] = lengths[0][1]
                    if len(lengths) > 1:
                        address = start + lengths[0][0]
                        subctl = self._subctls[start]
                        for length, sublengths in lengths[1:]:
                            self._lengths[address] = sublengths
                            self._subctls[address] = subctl
                            address += length
                        if text:
                            self._multiline_comments[start] = (address, text)
            elif asm_directive:
                directive, address = asm_directive
                self._asm_directives.setdefault(address, []).append(directive)
        f.close()

        self._terminate_multiline_comments()
        self._unroll_loops(max_address)
        self._ctls[max_address] = 'i'
示例#23
0
    def parse_ctl(self, ctlfile, min_address=0, max_address=65536):
        ctl_lines = []
        with open_file(ctlfile) as f:
            for line in f:
                s_line = line.rstrip()
                if s_line:
                    ctl_lines.append(s_line)
                    if s_line.startswith(
                        ('b', 'c', 'g', 'i', 's', 't', 'u', 'w')):
                        try:
                            address = get_int_param(s_line[1:].lstrip().split(
                                ' ', 1)[0])
                            if min_address <= address < max_address:
                                self._ctls[address] = s_line[0]
                        except ValueError:
                            pass
        entry_addresses = sorted(self._ctls)

        for line_no, s_line in enumerate(ctl_lines, 1):
            try:
                ctl, start, end, text, lengths, asm_directive = self._parse_ctl_line(
                    s_line, entry_addresses)
            except CtlParserError as e:
                warn('Ignoring line {} in {} ({}):\n{}'.format(
                    line_no, ctlfile, e.args[0], s_line))
                continue
            if ctl:
                if not min_address <= start < max_address:
                    continue
                if ctl == '>':
                    if end:
                        self._footers[start].append(text or '')
                    else:
                        self._headers[start].append(text or '')
                elif ctl.islower():
                    self._titles[start] = text
                elif ctl == 'D':
                    self._descriptions.setdefault(start, []).append(text)
                    self._subctls.setdefault(start, None)
                elif ctl == 'N':
                    self._mid_block_comments.setdefault(start, []).append(text)
                    self._subctls.setdefault(start, None)
                elif ctl == 'E':
                    self._end_comments.setdefault(start, []).append(text)
                elif ctl == 'R':
                    if text:
                        fields = text.split(' ', 1)
                        if len(fields) == 1:
                            fields.append('')
                        self._registers.setdefault(start, []).append(fields)
                elif ctl == 'M':
                    self._multiline_comments[start] = (end, text)
                    self._subctls.setdefault(start, None)
                elif ctl == 'L':
                    count = lengths[0][0]
                    if count > 1:
                        if len(lengths) > 1:
                            repeat_entries = lengths[1][0]
                        else:
                            repeat_entries = 0
                        loop_end = start + count * (end - start)
                        if loop_end > 65536:
                            warn('Loop crosses 64K boundary:\n{}'.format(
                                s_line))
                        self._loops.append((start, end, count, repeat_entries))
                        self._subctls[loop_end] = None
                else:
                    self._subctls[start] = ctl.lower()
                    self._instruction_comments[start] = text
                    if end:
                        self._subctls[end] = None
                if ctl != 'L' and lengths:
                    self._lengths[start] = lengths[0][1]
                    if len(lengths) > 1:
                        address = start + lengths[0][0]
                        subctl = self._subctls[start]
                        for length, sublengths in lengths[1:]:
                            self._lengths[address] = sublengths
                            self._subctls[address] = subctl
                            address += length
                        if text:
                            self._multiline_comments[start] = (address, text)
            elif asm_directive:
                directive, address = asm_directive
                self._asm_directives.setdefault(address, []).append(directive)

        self._terminate_multiline_comments()
        self._unroll_loops(max_address)
        self._ctls[max_address] = 'i'
示例#24
0
    def _parse_skool(self, min_address, max_address):
        start_index = -1
        lines = []
        ctl_lines = []
        entry_ctl = None
        f = open_file(self.skoolfile)
        for line in f:
            if line.startswith(';'):
                lines.append(VerbatimLine(line))
                continue
            if line.startswith('@'):
                lines.append(VerbatimLine(line))
                self._parse_asm_directive(line[1:].rstrip())
                continue
            if self.verbatim:
                # This line is inside a '+' block, so include it as is
                lines.append(VerbatimLine(line))
                continue
            s_line = line.strip()
            if not s_line:
                # This line is blank
                lines.append(VerbatimLine(line))
                entry_ctl = None
                continue
            # Check whether we're in a block that should be preserved verbatim
            if entry_ctl is None and line.startswith(VERBATIM_BLOCKS):
                entry_ctl = line[0]
            if entry_ctl in VERBATIM_BLOCKS:
                lines.append(VerbatimLine(line))
            elif s_line.startswith(';'):
                # This line is a continuation of an instruction comment
                comment_index = line.index(';')
                lines.append(VerbatimLine(" ;{} {}".format(comment_index, line[comment_index + 1:].lstrip())))
            elif line[0] in VALID_CTLS:
                # This line contains an instruction
                ctl_line = self._parse_instruction(line)
                if ctl_line.address >= max_address:
                    while lines and lines[-1].is_trimmable():
                        lines.pop()
                    while lines and lines[-1].is_blank():
                        lines.pop()
                    break
                if ctl_line.address >= min_address > 0 and start_index < 0:
                    start_index = len(lines)
                lines.append(ctl_line)
                ctl_lines.append(ctl_line)
            else:
                lines.append(VerbatimLine(line))
        f.close()

        if min_address > 0:
            if start_index < 0:
                return []
            if start_index < len(lines):
                if str(lines[start_index])[0] in DIRECTIVES:
                    while start_index > 0 and not lines[start_index].is_blank():
                        start_index -= 1
                else:
                    while start_index < len(lines) and not lines[start_index].is_blank():
                        start_index += 1
                return self._compress_blocks(lines[start_index + 1:])
        return self._compress_blocks(lines)
示例#25
0
    def _parse_sft(self, min_address, max_address):
        start_index = -1
        lines = []
        v_block_ctl = None
        f = open_file(self.sftfile)
        for line in f:
            if line.startswith('#'):
                # This line is a skool file template comment
                continue

            if not line.strip():
                # This line is blank
                lines.append(VerbatimLine(line))
                v_block_ctl = None
                continue

            if line.startswith(';'):
                # This line is an entry-level comment
                lines.append(VerbatimLine(line))
                continue

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

            if not self.disassemble:
                # This line is inside a '+' block, so include it as is
                lines.append(VerbatimLine(line))
                continue

            # Check whether we're in a block that should be restored verbatim
            if v_block_ctl is None and line.startswith(VERBATIM_BLOCKS):
                v_block_ctl = line[0]
            if v_block_ctl:
                if v_block_ctl == 'd':
                    self._set_bytes(line)
                lines.append(VerbatimLine(line))
                continue

            # Check whether the line starts with a valid character
            if line[0] not in VALID_CTLS:
                lines.append(VerbatimLine(line))
                continue

            try:
                ctl, inst_ctl, start, lengths, comment_index, comment = self._parse_instruction(
                    line)
            except (IndexError, ValueError):
                raise SftParsingError("Invalid line: {0}".format(
                    line.split()[0]))
            if start is not None:
                # This line contains a control directive
                if start >= min_address > 0 and start_index < 0:
                    start_index = len(lines)
                instructions = []
                for length, sublengths in lengths:
                    end = start + length
                    if inst_ctl == 'C':
                        base = sublengths[0][1]
                        instructions += self.disassembler.disassemble(
                            start, end, base)
                    elif inst_ctl == 'W':
                        instructions += self.disassembler.defw_range(
                            start, end, sublengths)
                    elif inst_ctl == 'T':
                        instructions += self.disassembler.defm_range(
                            start, end, sublengths)
                    elif inst_ctl == 'S':
                        instructions.append(
                            self.disassembler.defs(start, end, sublengths))
                    else:
                        instructions += self.disassembler.defb_range(
                            start, end, sublengths)
                    start += length
                if instructions:
                    done = False
                    for instruction in instructions:
                        if instruction.address >= max_address:
                            while lines and lines[-1].is_trimmable():
                                lines.pop()
                            done = True
                            break
                        address = self.address_fmt.format(instruction.address)
                        lines.append(
                            InstructionLine(ctl, address,
                                            instruction.operation,
                                            comment_index, comment))
                        ctl = ' '
                    if done:
                        break
                else:
                    lines.append(
                        InstructionLine(ctl, start, '', comment_index,
                                        comment))
            else:
                # This line is an instruction-level comment continuation line
                lines.append(
                    InstructionLine(comment_index=comment_index,
                                    comment=comment))
        f.close()

        if start_index < 0:
            return lines
        if start_index < len(lines):
            if str(lines[start_index])[0] in DIRECTIVES:
                while start_index > 0 and not lines[start_index].is_blank():
                    start_index -= 1
            else:
                while start_index < len(
                        lines) and not lines[start_index].is_blank():
                    start_index += 1
            return lines[start_index + 1:]
        return []
示例#26
0
        self._instructions = {}                  # address -> [Instructions]
        self._entries = {}                       # address -> SkoolEntry
        self.memory_map = []                     # SkoolEntry instances
        self.base_address = 65536
        self.end_address = 0
        self.header = []
        self.stack = []
        self.comments = []
        self.ignores = []
        self.asm_writer_class = None
        self.properties = {}
        self._replacements = []
        self.equs = []
        self._equ_values = {}

        with open_file(skoolfile) as f:
            self._parse_skool(f, min_address, max_address)

    def clone(self, skoolfile):
        return SkoolParser(
            skoolfile,
            self.case,
            self.base,
            self.mode.asm_mode,
            self.mode.warn,
            self.mode.fix_mode,
            self.mode.html,
            self.mode.create_labels,
            self.mode.asm_labels,
            snapshot=self.snapshot[:]
        )
 def test_open_file(self):
     tempdir = self.make_directory()
     with self.assertRaises(IOError) as cm:
         open_file(tempdir)
     self.assertEqual(cm.exception.errno, ERRNO)
示例#28
0
 def test_open_file(self):
     tempdir = self.make_directory()
     with self.assertRaises(IOError) as cm:
         open_file(tempdir)
     self.assertEqual(cm.exception.errno, ERRNO)
示例#29
0
    def _parse_sft(self, min_address, max_address):
        start_index = -1
        lines = []
        v_block_ctl = None
        f = open_file(self.sftfile)
        for line in f:
            if line.startswith('#'):
                # This line is a skool file template comment
                continue

            if not line.strip():
                # This line is blank
                lines.append(VerbatimLine(line))
                v_block_ctl = None
                continue

            if line.startswith(';'):
                # This line is an entry-level comment
                lines.append(VerbatimLine(line))
                continue

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

            if not self.disassemble:
                # This line is inside a '+' block, so include it as is
                lines.append(VerbatimLine(line))
                continue

            # Check whether we're in a block that should be restored verbatim
            if v_block_ctl is None and line[0] in 'dr' or (line[0] == 'i' and line[1] in '$0123456789'):
                v_block_ctl = line[0]
            if v_block_ctl:
                if v_block_ctl == 'd':
                    self._set_bytes(line)
                lines.append(VerbatimLine(line))
                continue

            # Check whether the line starts with a valid character
            if line[0] not in VALID_CTLS:
                lines.append(VerbatimLine(line))
                continue

            try:
                ctl, inst_ctl, start, lengths, comment_index, comment = self._parse_instruction(line)
            except (IndexError, ValueError):
                raise SftParsingError("Invalid line: {0}".format(line.split()[0]))
            if start is not None:
                # This line contains a control directive
                if start >= min_address > 0 and start_index < 0:
                    start_index = len(lines)
                instructions = []
                for length, sublengths in lengths:
                    end = start + length
                    if inst_ctl == 'C':
                        base = sublengths[0][1]
                        instructions += self.disassembler.disassemble(start, end, base)
                    elif inst_ctl == 'W':
                        instructions += self.disassembler.defw_range(start, end, sublengths)
                    elif inst_ctl == 'T':
                        instructions += self.disassembler.defm_range(start, end, sublengths)
                    elif inst_ctl == 'S':
                        instructions.append(self.disassembler.defs(start, end, sublengths))
                    else:
                        instructions += self.disassembler.defb_range(start, end, sublengths)
                    start += length
                if instructions:
                    done = False
                    for instruction in instructions:
                        if instruction.address >= max_address:
                            while lines and lines[-1].is_trimmable():
                                lines.pop()
                            done = True
                            break
                        address = self.address_fmt.format(instruction.address)
                        lines.append(InstructionLine(ctl, address, instruction.operation, comment_index, comment))
                        ctl = ' '
                    if done:
                        break
                else:
                    lines.append(InstructionLine(ctl, start, '', comment_index, comment))
            else:
                # This line is an instruction-level comment continuation line
                lines.append(InstructionLine(comment_index=comment_index, comment=comment))
        f.close()

        if start_index < 0:
            return lines
        if start_index < len(lines):
            if str(lines[start_index])[0] in DIRECTIVES:
                while start_index > 0 and not lines[start_index].is_blank():
                    start_index -= 1
            else:
                while start_index < len(lines) and not lines[start_index].is_blank():
                    start_index += 1
            return lines[start_index + 1:]
        return []
示例#30
0
    def _parse_skool(self, min_address, max_address):
        start_index = -1
        lines = []
        ctl_lines = []
        entry_ctl = None
        f = open_file(self.skoolfile)
        for line in f:
            if line.startswith(';'):
                lines.append(VerbatimLine(line))
                continue
            if line.startswith('@'):
                lines.append(VerbatimLine(line))
                self._parse_asm_directive(line[1:].rstrip())
                continue
            if self.verbatim:
                # This line is inside a '+' block, so include it as is
                lines.append(VerbatimLine(line))
                continue
            s_line = line.strip()
            if not s_line:
                # This line is blank
                lines.append(VerbatimLine(line))
                entry_ctl = None
                continue
            # Check whether we're in a block that should be preserved verbatim
            if entry_ctl is None and line.startswith(VERBATIM_BLOCKS):
                entry_ctl = line[0]
            if entry_ctl in VERBATIM_BLOCKS:
                lines.append(VerbatimLine(line))
            elif s_line.startswith(';'):
                # This line is a continuation of an instruction comment
                comment_index = line.index(';')
                lines.append(
                    VerbatimLine(" ;{} {}".format(
                        comment_index, line[comment_index + 1:].lstrip())))
            elif line[0] in VALID_CTLS:
                # This line contains an instruction
                ctl_line = self._parse_instruction(line)
                if ctl_line.address >= max_address:
                    while lines and lines[-1].is_trimmable():
                        lines.pop()
                    while lines and lines[-1].is_blank():
                        lines.pop()
                    break
                if ctl_line.address >= min_address > 0 and start_index < 0:
                    start_index = len(lines)
                lines.append(ctl_line)
                ctl_lines.append(ctl_line)
            else:
                lines.append(VerbatimLine(line))
        f.close()

        if min_address > 0:
            if start_index < 0:
                return []
            if start_index < len(lines):
                if str(lines[start_index])[0] in DIRECTIVES:
                    while start_index > 0 and not lines[start_index].is_blank(
                    ):
                        start_index -= 1
                else:
                    while start_index < len(
                            lines) and not lines[start_index].is_blank():
                        start_index += 1
                return self._compress_blocks(lines[start_index + 1:])
        return self._compress_blocks(lines)