Beispiel #1
0
def get_defs_length(operation, preserve_base):
    if preserve_base:
        fmt = FORMAT_PRESERVE_BASE
    else:
        fmt = FORMAT_NO_BASE
    items = split_operation(operation)[1:3]

    try:
        size = parse_word(items[0])
    except ValueError:
        raise SkoolParsingError("Invalid integer '{}': {}".format(items[0], operation))
    size_base = _get_base(items[0], preserve_base)
    try:
        get_int_param(items[0])
        size_fmt = fmt[size_base].format(items[0])
    except ValueError:
        size_fmt = fmt[size_base].format(size)

    if len(items) == 1:
        return size, size_fmt

    value_base = _get_base(items[1], preserve_base)
    if value_base in 'dh' and not preserve_base:
        value_base = 'n'
    return size, '{}:{}'.format(size_fmt, value_base)
Beispiel #2
0
def poke(snapshot, param_str):
    try:
        addr, val = param_str.split(',', 1)
    except ValueError:
        raise SkoolKitError("Value missing in poke spec: {}".format(param_str))
    try:
        if val.startswith('^'):
            value = get_int_param(val[1:])
            poke_f = lambda b: b ^ value
        elif val.startswith('+'):
            value = get_int_param(val[1:])
            poke_f = lambda b: (b + value) & 255
        else:
            value = get_int_param(val)
            poke_f = lambda b: value
    except ValueError:
        raise SkoolKitError('Invalid value in poke spec: {}'.format(param_str))
    try:
        values = [get_int_param(i) for i in addr.split('-', 2)]
    except ValueError:
        raise SkoolKitError(
            'Invalid address range in poke spec: {}'.format(param_str))
    addr1, addr2, step = values + [values[0], 1][len(values) - 1:]
    for a in range(addr1, addr2 + 1, step):
        snapshot[a] = poke_f(snapshot[a])
Beispiel #3
0
    def _parse_instruction(self, line):
        ctl = line[0]
        lengths = []
        if line[1] == ';':
            inst_ctl = None
            start = None
            i = line.find(' ', 2)
            if i < 0:
                i = len(line.rstrip())
            comment_index = get_int_param(line[2:i])
        else:
            inst_ctl = line[1]
            if inst_ctl == 'I':
                i = find_unquoted(line.rstrip(), ' ', 2)
                address_end = j = find_unquoted(line, ';', 2, i)
            else:
                address_end = line.index(',', 2)
                i = find_unquoted(line.rstrip(), ' ', address_end + 1)
                j = find_unquoted(line, ';', address_end + 1, i)
            start = get_int_param(line[2:address_end])
            if j == i:
                comment_index = -1
            else:
                comment_index = get_int_param(line[j + 1:i])
            if j > address_end + 1:
                params = split_unquoted(line[address_end + 1:j], ',')
                lengths = parse_params(inst_ctl, params, 0)
            elif inst_ctl != 'I':
                raise ValueError

        comment = line[i:].strip()
        return ctl, inst_ctl, start, lengths, comment_index, comment
Beispiel #4
0
    def _parse_instruction(self, line):
        ctl = line[0]
        lengths = []
        if line[1] == ';':
            inst_ctl = None
            start = None
            i = line.find(' ', 2)
            if i < 0:
                i = len(line.rstrip())
            comment_index = get_int_param(line[2:i])
        else:
            inst_ctl = line[1]
            if inst_ctl == 'I':
                i = find_unquoted(line.rstrip(), ' ', 2)
                address_end = j = find_unquoted(line, ';', 2, i)
            else:
                address_end = line.index(',', 2)
                i = find_unquoted(line.rstrip(), ' ', address_end + 1)
                j = find_unquoted(line, ';', address_end + 1, i)
            start = get_int_param(line[2:address_end])
            if j == i:
                comment_index = -1
            else:
                comment_index = get_int_param(line[j + 1:i])
            if j > address_end + 1:
                params = split_unquoted(line[address_end + 1:j], ',')
                lengths = parse_params(inst_ctl, params, 0)
            elif inst_ctl != 'I':
                raise ValueError

        comment = line[i:].strip()
        return ctl, inst_ctl, start, lengths, comment_index, comment
Beispiel #5
0
    def _get_defs_length(self, operation):
        if self.preserve_base:
            fmt = FORMAT_PRESERVE_BASE
        else:
            fmt = FORMAT_NO_BASE
        items = self.op_evaluator.split_operands(operation[5:])[:2]

        try:
            size = self.op_evaluator.eval_int(items[0])
        except ValueError:
            raise SkoolParsingError("Invalid integer '{}': {}".format(
                items[0], operation))
        size_base = _get_base(items[0], self.preserve_base)
        try:
            get_int_param(items[0])
            size_fmt = fmt[size_base].format(items[0])
        except ValueError:
            size_fmt = fmt[size_base].format(size)

        if len(items) == 1:
            return size, size_fmt

        value_base = _get_base(items[1], self.preserve_base)
        if value_base in 'dh' and not self.preserve_base:
            value_base = 'n'
        return size, '{}:{}'.format(size_fmt, value_base)
Beispiel #6
0
def _get_basic_block(spec):
    if spec:
        try:
            if ',' in spec:
                return [get_int_param(i) for i in spec.split(',', 1)]
            return get_int_param(spec), 23755
        except ValueError:
            raise SkoolKitError('Invalid block specification: {}'.format(spec))
Beispiel #7
0
def _get_basic_block(spec):
    if spec:
        try:
            if ',' in spec:
                params = spec.split(',', 1)
                return get_int_param(params[0]), get_int_param(params[1], True)
            return get_int_param(spec), 23755
        except ValueError:
            raise SkoolKitError('Invalid block specification: {}'.format(spec))
Beispiel #8
0
def _get_basic_block(spec):
    if spec:
        try:
            if ',' in spec:
                params = spec.split(',', 1)
                return get_int_param(params[0]), get_int_param(params[1], True)
            return get_int_param(spec), 23755
        except ValueError:
            raise SkoolKitError('Invalid block specification: {}'.format(spec))
Beispiel #9
0
def find(infile, byte_seq):
    step = 1
    if '-' in byte_seq:
        byte_seq, step = byte_seq.split('-', 1)
        step = get_int_param(step)
    byte_values = [get_int_param(i) for i in byte_seq.split(',')]
    offset = step * len(byte_values)
    snapshot = get_snapshot(infile)
    for a in range(16384, 65537 - offset):
        if snapshot[a:a + offset:step] == byte_values:
            print("{}-{}-{}: {}".format(a, a + offset - step, step, byte_seq))
Beispiel #10
0
def _parse_length(length, default_base, required):
    if length.startswith(BASES):
        base = length[0]
        if length[1:].startswith(BASES):
            base += length[1]
        if required or len(length) > len(base):
            return (get_int_param(length[len(base):]), base)
        return (0, base)
    if required or length:
        return (get_int_param(length), default_base)
    return (0, default_base)
Beispiel #11
0
def _parse_length(length, subctl=None, default_prefix=None, required=True):
    if length.startswith(BASES):
        prefix = length[0]
        if length[1:].startswith(BASES):
            prefix += length[1]
        if required or len(length) > len(prefix):
            return (get_int_param(length[len(prefix):]), prefix)
        return (None, prefix)
    if subctl in ('B', 'T') and length.startswith(('B', 'T')):
        return (get_int_param(length[1:]), length[0])
    if required or length:
        return (get_int_param(length), default_prefix)
    return (None, default_prefix)
Beispiel #12
0
def _parse_length(length, subctl=None, default_prefix=None, required=True):
    if length.startswith(BASES):
        prefix = length[0]
        if length[1:].startswith(BASES):
            prefix += length[1]
        if required or len(length) > len(prefix):
            return (get_int_param(length[len(prefix):]), prefix)
        return (None, prefix)
    if subctl in ('B', 'T') and length.startswith(('B', 'T')):
        return (get_int_param(length[1:]), length[0])
    if required or length:
        return (get_int_param(length), default_prefix)
    return (None, default_prefix)
Beispiel #13
0
def peek(infile, addr_range):
    step = 1
    if '-' in addr_range:
        addr1, addr2 = addr_range.split('-', 1)
        addr1 = get_int_param(addr1)
        if '-' in addr2:
            addr2, step = [get_int_param(i) for i in addr2.split('-', 1)]
        else:
            addr2 = get_int_param(addr2)
    else:
        addr1 = addr2 = get_int_param(addr_range)
    snapshot = get_snapshot(infile)
    for a in range(addr1, addr2 + 1, step):
        print('{}: {}'.format(a, snapshot[a]))
Beispiel #14
0
def _find(infile, byte_seq):
    step = 1
    if '-' in byte_seq:
        byte_seq, step = byte_seq.split('-', 1)
        step = get_int_param(step)
    try:
        byte_values = [get_int_param(i) for i in byte_seq.split(',')]
    except ValueError:
        raise SkoolKitError('Invalid byte sequence: {}'.format(byte_seq))
    offset = step * len(byte_values)
    snapshot = get_snapshot(infile)
    for a in range(16384, 65537 - offset):
        if snapshot[a:a + offset:step] == byte_values:
            print("{0}-{1}-{2} {0:04X}-{1:04X}-{2:X}: {3}".format(a, a + offset - step, step, byte_seq))
Beispiel #15
0
def set_z80_registers(z80, *specs):
    for spec in specs:
        reg, sep, val = spec.lower().partition('=')
        if sep:
            if reg.startswith('^'):
                size = len(reg) - 1
            else:
                size = len(reg)
            if reg == 'pc' and z80[6:8] != [0, 0]:
                offset = 6
            else:
                offset = Z80_REGISTERS.get(reg, -1)
            if offset >= 0:
                try:
                    value = get_int_param(val, True)
                except ValueError:
                    raise SkoolKitError("Cannot parse register value: {}".format(spec))
                lsb, msb = value % 256, (value & 65535) // 256
                if size == 1:
                    z80[offset] = lsb
                elif size == 2:
                    z80[offset:offset + 2] = [lsb, msb]
                if reg == 'r' and lsb & 128:
                    z80[12] |= 1
            else:
                raise SkoolKitError('Invalid register: {}'.format(spec))
Beispiel #16
0
 def _parse_instruction(self, address, line, removed):
     try:
         skool_address = get_int_param(line[1:6])
     except ValueError:
         raise SkoolParsingError("Invalid address ({}):\n{}".format(
             line[1:6], line.rstrip()))
     if address is None:
         address = skool_address
     original_op = partition_unquoted(line[6:], ';')[0].strip()
     subbed = max(self.subs)
     if subbed:
         operations = self.subs[subbed]
     else:
         operations = [original_op]
     self.subs = defaultdict(list, {0: []})
     parsed = [parse_asm_sub_fix_directive(v)[::2] for v in operations]
     before = [i[1] for i in parsed if i[0].prepend and i[1]]
     for operation in before:
         address = self._assemble(operation, address)
     after = [(i[0].overwrite, i[1], i[0].append) for i in parsed
              if not i[0].prepend]
     if not after or after[0][2]:
         after.insert(0, (False, original_op, False))
     overwrite, operation = after.pop(0)[:2]
     operation = operation or original_op
     if operation and skool_address not in removed:
         address = self._assemble(operation, address, overwrite, removed)
     for overwrite, operation, append in after:
         if operation:
             address = self._assemble(operation, address, overwrite,
                                      removed)
     return address
Beispiel #17
0
 def _label_operand(self, instruction):
     label_warn = instruction.sub is None and instruction.warn
     operation = instruction.operation
     operation_u = operation.upper()
     if operation_u.startswith(('RST', 'DEFS')):
         return
     operand = get_address(operation)
     if operand is None:
         return
     operand_int = get_int_param(operand)
     if operand_int < 256 and (not operation_u.startswith(('CALL', 'DEFW', 'DJNZ', 'JP', 'JR', 'LD '))
                               or self._is_8_bit_ld_instruction(operation_u)):
         return
     reference = self.get_instruction(operand_int)
     if reference:
         if reference.asm_label:
             rep = operation.replace(operand, reference.asm_label)
             if reference.is_in_routine() and label_warn and operation_u.startswith('LD '):
                 # Warn if a LD operand is replaced with a routine label in
                 # an unsubbed operation (will need @keep to retain operand,
                 # or @nowarn if the replacement is OK)
                 self.warn('LD operand replaced with routine label in unsubbed operation:\n  {} {} -> {}'.format(instruction.addr_str, operation, rep))
             instruction.operation = rep
         elif instruction.warn and instruction.is_in_routine():
             # Warn if we cannot find a label to replace the operand of this
             # routine instruction (will need @nowarn if this is OK)
             self.warn('Found no label for operand: {} {}'.format(instruction.addr_str, operation))
     else:
         references = self._instructions.get(operand_int)
         is_local = not (references and references[0].container.is_remote())
         if is_local and label_warn and self.mode.do_ssubs and self.base_address <= operand_int < self.end_address:
             # Warn if the operand is inside the address range of the
             # disassembly (where code might be) but doesn't refer to the
             # address of an instruction (will need @nowarn if this is OK)
             self.warn('Unreplaced operand: {} {}'.format(instruction.addr_str, operation))
Beispiel #18
0
def set_z80_state(z80, *specs):
    for spec in specs:
        name, sep, val = spec.lower().partition('=')
        try:
            if name == 'iff':
                z80[27] = z80[28] = get_int_param(val) & 255
            elif name == 'im':
                z80[29] &= 252 # Clear bits 0 and 1
                z80[29] |= get_int_param(val) & 3
            elif name == 'border':
                z80[12] &= 241 # Clear bits 1-3
                z80[12] |= (get_int_param(val) & 7) * 2 # Border colour
            else:
                raise SkoolKitError("Invalid parameter: {}".format(spec))
        except ValueError:
            raise SkoolKitError("Cannot parse integer: {}".format(spec))
Beispiel #19
0
def set_z80_registers(z80, *specs):
    for spec in specs:
        reg, sep, val = spec.lower().partition('=')
        if sep:
            if reg.startswith('^'):
                size = len(reg) - 1
            else:
                size = len(reg)
            if reg == 'pc' and z80[6:8] != [0, 0]:
                offset = 6
            else:
                offset = Z80_REGISTERS.get(reg, -1)
            if offset >= 0:
                try:
                    value = get_int_param(val, True)
                except ValueError:
                    raise SkoolKitError("Cannot parse register value: {}".format(spec))
                lsb, msb = value % 256, (value & 65535) // 256
                if size == 1:
                    z80[offset] = lsb
                elif size == 2:
                    z80[offset:offset + 2] = [lsb, msb]
                if reg == 'r' and lsb & 128:
                    z80[12] |= 1
            else:
                raise SkoolKitError('Invalid register: {}'.format(spec))
Beispiel #20
0
def _load(snapshot, counters, blocks, param_str):
    try:
        block_num, start, length, step, offset, inc = _get_load_params(
            param_str)
    except ValueError:
        raise SkoolKitError(
            'Invalid integer in load spec: {}'.format(param_str))
    default_index = 1
    load_last = False
    if block_num.startswith('+'):
        block_num = block_num[1:]
        default_index = 0
    if block_num.endswith('+'):
        block_num = block_num[:-1]
        load_last = True
    block_num = get_int_param(block_num)
    index = counters.setdefault(block_num, default_index)
    try:
        block = blocks[block_num - 1]
    except IndexError:
        raise TapeError("Block {} not found".format(block_num))
    if length is None and load_last:
        length = len(block) - index
    length = _load_block(snapshot, block, start, length, step, offset, inc,
                         index)
    counters[block_num] += length
Beispiel #21
0
 def _parse_instruction(self, line, removed):
     try:
         address = get_int_param(line[1:6])
     except ValueError:
         raise SkoolParsingError("Invalid address ({}):\n{}".format(
             line[1:6], line.rstrip()))
     original_op = partition_unquoted(line[6:], ';')[0].strip()
     subbed = max(self.subs)
     if subbed:
         operations = [
             partition_unquoted(s, ';') for s in self.subs[subbed]
         ]
     else:
         operations = [(original_op, '', '')]
     self.subs = defaultdict(list, {0: []})
     for op, sep, comment in operations:
         operation = op.strip() or original_op
         if operation:
             data = assemble(operation, address)
             if data:
                 end_address = address + len(data)
                 if address not in removed:
                     self.snapshot[address:end_address] = data
                     self.base_address = min(self.base_address, address)
                     self.end_address = max(self.end_address, end_address)
                 if subbed:
                     removed.update(range(address, end_address))
                 address = end_address
             else:
                 warn("Failed to assemble:\n {} {}".format(
                     address, operation))
                 break
         original_op = None
Beispiel #22
0
def set_z80_state(z80, *specs):
    for spec in specs:
        name, sep, val = spec.lower().partition('=')
        try:
            if name == 'iff':
                z80[27] = z80[28] = get_int_param(val) & 255
            elif name == 'im':
                z80[29] &= 252 # Clear bits 0 and 1
                z80[29] |= get_int_param(val) & 3
            elif name == 'border':
                z80[12] &= 241 # Clear bits 1-3
                z80[12] |= (get_int_param(val) & 7) * 2 # Border colour
            else:
                raise SkoolKitError("Invalid parameter: {}".format(spec))
        except ValueError:
            raise SkoolKitError("Cannot parse integer: {}".format(spec))
Beispiel #23
0
 def _parse_instruction(self, line):
     ctl, addr_str, operation, comment = parse_instruction(line)
     try:
         address = get_int_param(addr_str)
     except ValueError:
         raise SkoolParsingError("Invalid address ({}):\n{}".format(addr_str, line.rstrip()))
     instruction = Instruction(ctl, address, operation, self.preserve_base)
     self.mode.apply_asm_directives(instruction)
     return instruction, comment
Beispiel #24
0
def move(snapshot, param_str):
    params = param_str.split(',', 2)
    if len(params) < 3:
        raise SkoolKitError("Not enough arguments in move spec (expected 3): {}".format(param_str))
    try:
        src, length, dest = [get_int_param(p, True) for p in params]
    except ValueError:
        raise SkoolKitError('Invalid integer in move spec: {}'.format(param_str))
    snapshot[dest:dest + length] = snapshot[src:src + length]
Beispiel #25
0
def _get_address_ranges(specs, step=1):
    addr_ranges = []
    for addr_range in specs:
        try:
            values = [get_int_param(i, True) for i in addr_range.split('-', 2)]
        except ValueError:
            raise SkoolKitError('Invalid address range: {}'.format(addr_range))
        addr_ranges.append(values + [values[0], step][len(values) - 1:])
    return addr_ranges
Beispiel #26
0
def move(snapshot, param_str):
    params = param_str.split(',', 2)
    if len(params) < 3:
        raise SkoolKitError("Not enough arguments in move spec (expected 3): {}".format(param_str))
    try:
        src, length, dest = [get_int_param(p) for p in params]
    except ValueError:
        raise SkoolKitError('Invalid integer in move spec: {}'.format(param_str))
    snapshot[dest:dest + length] = snapshot[src:src + length]
Beispiel #27
0
 def _parse_instruction(self, line):
     ctl, addr_str, operation, comment = parse_instruction(line)
     try:
         address = get_int_param(addr_str)
     except ValueError:
         raise SkoolParsingError("Invalid address ({}):\n{}".format(addr_str, line.rstrip()))
     instruction = Instruction(ctl, address, operation, self.preserve_base)
     self.mode.apply_asm_directives(instruction)
     return instruction, comment
Beispiel #28
0
def _get_address_ranges(specs, step=1):
    addr_ranges = []
    for addr_range in specs:
        try:
            values = [get_int_param(i, True) for i in addr_range.split('-', 2)]
        except ValueError:
            raise SkoolKitError('Invalid address range: {}'.format(addr_range))
        addr_ranges.append(values + [values[0], step][len(values) - 1:])
    return addr_ranges
Beispiel #29
0
def _get_load_params(param_str):
    params = []
    for index, n in enumerate(param_str.split(',')):
        if index == 0:
            params.append(n)
        elif n:
            params.append(get_int_param(n, True))
        else:
            params.append(None)
    params += [None] * (6 - len(params))
    return params[:6]
Beispiel #30
0
def _get_int_params(param_str, num, leave):
    params = []
    for index, n in enumerate(param_str.split(',')):
        if index in leave:
            params.append(n)
        elif n:
            params.append(get_int_param(n))
        else:
            params.append(None)
    params += [None] * (num - len(params))
    return params[:num]
Beispiel #31
0
def _get_load_params(param_str):
    params = []
    for index, n in enumerate(param_str.split(',')):
        if index == 0:
            params.append(n)
        elif n:
            params.append(get_int_param(n, True))
        else:
            params.append(None)
    params += [None] * (6 - len(params))
    return params[:6]
Beispiel #32
0
def _get_int_params(param_str, num, leave):
    params = []
    for index, n in enumerate(param_str.split(',')):
        if index in leave:
            params.append(n)
        elif n:
            params.append(get_int_param(n))
        else:
            params.append(None)
    params += [None] * (num - len(params))
    return params[:num]
Beispiel #33
0
def _find(snapshot, byte_seq, base_addr=16384):
    steps = '1'
    if '-' in byte_seq:
        byte_seq, steps = byte_seq.split('-', 1)
    try:
        byte_values = [get_int_param(i, True) for i in byte_seq.split(',')]
    except ValueError:
        raise SkoolKitError('Invalid byte sequence: {}'.format(byte_seq))
    try:
        if '-' in steps:
            limits = [get_int_param(n, True) for n in steps.split('-', 1)]
            steps = range(limits[0], limits[1] + 1)
        else:
            steps = [get_int_param(steps, True)]
    except ValueError:
        raise SkoolKitError('Invalid distance: {}'.format(steps))
    for step in steps:
        offset = step * len(byte_values)
        for a in range(base_addr, 65537 - offset):
            if snapshot[a:a + offset:step] == byte_values:
                print("{0}-{1}-{2} {0:04X}-{1:04X}-{2:X}: {3}".format(a, a + offset - step, step, byte_seq))
Beispiel #34
0
def _find(snapshot, byte_seq, base_addr=16384):
    steps = '1'
    if '-' in byte_seq:
        byte_seq, steps = byte_seq.split('-', 1)
    try:
        byte_values = [get_int_param(i, True) for i in byte_seq.split(',')]
    except ValueError:
        raise SkoolKitError('Invalid byte sequence: {}'.format(byte_seq))
    try:
        if '-' in steps:
            limits = [get_int_param(n, True) for n in steps.split('-', 1)]
            steps = range(limits[0], limits[1] + 1)
        else:
            steps = [get_int_param(steps, True)]
    except ValueError:
        raise SkoolKitError('Invalid distance: {}'.format(steps))
    for step in steps:
        offset = step * len(byte_values)
        for a in range(base_addr, 65537 - offset):
            if snapshot[a:a + offset:step] == byte_values:
                print("{0}-{1}-{2} {0:04X}-{1:04X}-{2:X}: {3}".format(a, a + offset - step, step, byte_seq))
Beispiel #35
0
def parse_params(ctl, params):
    int_params = []
    for i, param in enumerate(params):
        if i == 0:
            length, base = _parse_length(param, BASE_MAP[ctl], False)
            int_params.append(length)
        else:
            n, sep, m = partition_unquoted(param, '*', '1')
            int_params += (_parse_sublengths(n, ctl, base),) * get_int_param(m)
    if len(int_params) == 1:
        int_params.append((0, ((0, base),)))
    return tuple(int_params)
Beispiel #36
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
Beispiel #37
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
Beispiel #38
0
def get_defs_length(operation, preserve_base):
    if preserve_base:
        fmt = FORMAT_PRESERVE_BASE
    else:
        fmt = FORMAT_NO_BASE
    size = None
    lengths = []
    for item in split_operation(operation)[1:3]:
        if size is None:
            size = get_int_param(item)
        base = _get_base(item, preserve_base)
        lengths.append(fmt[base].format(item))
    return size, ':'.join(lengths)
Beispiel #39
0
def parse_params(ctl, params, lengths_index=1):
    int_params = []
    prefix = None
    for i, param in enumerate(params):
        if i < lengths_index:
            length, prefix = _parse_length(param, required=False)
            int_params.append(length)
        else:
            n, sep, m = partition_unquoted(param, '*', '1')
            int_params += (_parse_sublengths(n, ctl, prefix),) * get_int_param(m)
    if prefix and len(int_params) == lengths_index:
        int_params.append((None, ((None, prefix),)))
    return tuple(int_params)
Beispiel #40
0
 def _parse_ctl_line(self, line, entry_addresses):
     ctl = start = end = text = asm_directive = None
     lengths = ()
     first_char = line[0]
     content = line[1:].lstrip()
     if first_char in '.:':
         ctl = first_char
         text = line[2:].rstrip()
     elif content:
         if first_char in ' >bBcCDEgiLMNRsStTuwW':
             fields = split_unquoted(content, ' ', 1)
             params = split_unquoted(fields[0], ',')
             try:
                 start = get_int_param(params[0])
             except ValueError:
                 raise CtlParserError("invalid address")
             ctl = first_char
             if ctl == ' ':
                 index = bisect.bisect_right(entry_addresses, start) - 1
                 if index < 0:
                     raise CtlParserError(
                         "blank directive with no containing block")
                 entry_ctl = self._ctls[entry_addresses[index]]
                 if entry_ctl in 'cstw':
                     ctl = entry_ctl.upper()
                 else:
                     ctl = 'B'
             try:
                 int_params = parse_params(ctl, params[1:])
             except ValueError:
                 raise CtlParserError("invalid integer")
             if int_params:
                 if ctl not in '>BCLMSTW':
                     raise CtlParserError("extra parameters after address")
                 length = int_params[0]
                 if length:
                     end = start + length
             lengths = int_params[1:]
             if ctl == 'L':
                 if end is None:
                     raise CtlParserError("loop length not specified")
                 if not lengths[0][0]:
                     raise CtlParserError("loop count not specified")
             if len(fields) > 1:
                 text = fields[1]
         elif first_char == '@':
             asm_directive = self._parse_asm_directive(content)
         elif first_char not in '#%;':
             raise CtlParserError("invalid directive")
     return ctl, start, end, text, lengths, asm_directive
Beispiel #41
0
def parse_params(ctl, params, lengths_index=1):
    int_params = []
    prefix = None
    for i, param in enumerate(params):
        if i < lengths_index:
            length, prefix = _parse_length(param, required=False)
            int_params.append(length)
        else:
            n, sep, m = partition_unquoted(param, '*', '1')
            int_params += (_parse_sublengths(n, ctl,
                                             prefix), ) * get_int_param(m)
    if prefix and len(int_params) == lengths_index:
        int_params.append((None, ((None, prefix), )))
    return tuple(int_params)
Beispiel #42
0
 def _parse_ctl_line(self, line, entry_addresses):
     ctl = start = end = text = asm_directive = None
     lengths = ()
     first_char = line[0]
     content = line[1:].lstrip()
     if first_char in '.:':
         ctl = first_char
         text = line[2:].rstrip()
     elif content:
         if first_char in ' >bBcCDEgiLMNRsStTuwW':
             fields = split_unquoted(content, ' ', 1)
             params = split_unquoted(fields[0], ',')
             try:
                 start = get_int_param(params[0])
             except ValueError:
                 raise CtlParserError("invalid address")
             ctl = first_char
             if ctl == ' ':
                 index = bisect.bisect_right(entry_addresses, start) - 1
                 if index < 0:
                     raise CtlParserError("blank directive with no containing block")
                 entry_ctl = self._ctls[entry_addresses[index]]
                 if entry_ctl in 'cstw':
                     ctl = entry_ctl.upper()
                 else:
                     ctl = 'B'
             try:
                 int_params = parse_params(ctl, params[1:])
             except ValueError:
                 raise CtlParserError("invalid integer")
             if int_params:
                 if ctl not in '>BCLMSTW':
                     raise CtlParserError("extra parameters after address")
                 length = int_params[0]
                 if length is not None:
                     end = start + length
             lengths = int_params[1:]
             if ctl == 'L':
                 if end is None:
                     raise CtlParserError("loop length not specified")
                 if not lengths:
                     raise CtlParserError("loop count not specified")
             if len(fields) > 1:
                 text = fields[1]
         elif first_char == '@':
             asm_directive = self._parse_asm_directive(content)
         elif first_char not in '#%;':
             raise CtlParserError("invalid directive")
     return ctl, start, end, text, lengths, asm_directive
Beispiel #43
0
def poke(snapshot, param_str):
    try:
        addr, val = param_str.split(',', 1)
    except ValueError:
        raise SkoolKitError("Value missing in poke spec: {}".format(param_str))
    try:
        if val.startswith('^'):
            value = get_int_param(val[1:])
            poke_f = lambda b: b ^ value
        elif val.startswith('+'):
            value = get_int_param(val[1:])
            poke_f = lambda b: (b + value) & 255
        else:
            value = get_int_param(val)
            poke_f = lambda b: value
    except ValueError:
        raise SkoolKitError('Invalid value in poke spec: {}'.format(param_str))
    try:
        values = [get_int_param(i) for i in addr.split('-', 2)]
    except ValueError:
        raise SkoolKitError('Invalid address range in poke spec: {}'.format(param_str))
    addr1, addr2, step = values + [values[0], 1][len(values) - 1:]
    for a in range(addr1, addr2 + 1, step):
        snapshot[a] = poke_f(snapshot[a])
Beispiel #44
0
 def _parse_instruction(self, line):
     ctl = line[0]
     try:
         address = get_int_param(line[1:6])
     except ValueError:
         raise SkoolParsingError("Invalid address ({}):\n{}".format(line[1:6], line.rstrip()))
     addr_str = self.address_fmt.format(address)
     comment_index = find_unquoted(line, ';', 6, neg=True)
     if comment_index > 0:
         end = comment_index
     else:
         end = len(line)
     operation = line[7:end].strip()
     comment = line[end + 1:].strip()
     return ControlLine(ctl, address, addr_str, operation, comment_index, comment, self.preserve_base)
Beispiel #45
0
def evaluate(param, safe=False):
    try:
        return get_int_param(param)
    except ValueError:
        pass
    param = html.unescape(param)
    if safe or set(param) <= AE_CHARS:
        try:
            return int(
                eval(
                    param.replace('$', '0x').replace('/', '//').replace(
                        '&&', ' and ').replace('||', ' or ')))
        except:
            pass
    raise ValueError
Beispiel #46
0
def _find_tile(snapshot, coords):
    steps = '1'
    if '-' in coords:
        coords, steps = coords.split('-', 1)
    try:
        x, y = [get_int_param(i) for i in coords.split(',', 1)]
        if not 0 <= x < 32 or not 0 <= y < 24:
            raise ValueError
    except ValueError:
        raise SkoolKitError('Invalid tile coordinates: {}'.format(coords))
    df_addr = 16384 + 2048 * (y // 8) + 32 * (y & 7) + x
    byte_seq = snapshot[df_addr:df_addr + 2048:256]
    for b in byte_seq:
        print('|{:08b}|'.format(b).replace('0', ' ').replace('1', '*'))
    _find(snapshot, '{}-{}'.format(','.join([str(b) for b in byte_seq]), steps), 23296)
Beispiel #47
0
def _find_tile(snapshot, coords):
    steps = '1'
    if '-' in coords:
        coords, steps = coords.split('-', 1)
    try:
        x, y = [get_int_param(i) for i in coords.split(',', 1)]
        if not 0 <= x < 32 or not 0 <= y < 24:
            raise ValueError
    except ValueError:
        raise SkoolKitError('Invalid tile coordinates: {}'.format(coords))
    df_addr = 16384 + 2048 * (y // 8) + 32 * (y & 7) + x
    byte_seq = snapshot[df_addr:df_addr + 2048:256]
    for b in byte_seq:
        print('|{:08b}|'.format(b).replace('0', ' ').replace('1', '*'))
    _find(snapshot, '{}-{}'.format(','.join([str(b) for b in byte_seq]), steps), 23296)
Beispiel #48
0
 def _parse_instruction(self, line):
     ctl = line[0]
     try:
         address = get_int_param(line[1:6])
     except ValueError:
         raise SkoolParsingError("Invalid address ({}):\n{}".format(
             line[1:6], line.rstrip()))
     addr_str = self.address_fmt.format(address)
     comment_index = find_unquoted(line, ';', 6, neg=True)
     if comment_index > 0:
         end = comment_index
     else:
         end = len(line)
     operation = line[7:end].strip()
     comment = line[end + 1:].strip()
     return ControlLine(ctl, address, addr_str, operation, comment_index,
                        comment, self.preserve_base)
Beispiel #49
0
def _peek(infile, specs):
    addr_ranges = []
    for addr_range in specs:
        try:
            values = [get_int_param(i) for i in addr_range.split('-', 2)]
        except ValueError:
            raise SkoolKitError('Invalid address range: {}'.format(addr_range))
        addr_ranges.append(values + [values[0], 1][len(values) - 1:])
    snapshot = get_snapshot(infile)
    for addr1, addr2, step in addr_ranges:
        for a in range(addr1, addr2 + 1, step):
            value = snapshot[a]
            if 32 <= value <= 126:
                char = chr(value)
            else:
                char = ''
            print('{0:>5} {0:04X}: {1:>3}  {1:02X}  {1:08b}  {2}'.format(a, value, char))
Beispiel #50
0
 def _parse_asm_directive(self, content):
     fields = [f.lstrip() for f in content.split(' ', 1)]
     if len(fields) < 2:
         raise CtlParserError("invalid ASM directive declaration")
     try:
         address = get_int_param(fields[0])
     except ValueError:
         raise CtlParserError("invalid ASM directive address")
     directive = fields[1]
     comment_type = 'i'
     if directive.startswith(AD_IGNOREUA + ':'):
         directive, comment_type = directive.split(':', 1)
     if directive != AD_IGNOREUA:
         return directive, address
     if comment_type not in COMMENT_TYPES:
         raise CtlParserError("invalid @ignoreua directive suffix: '{}'".format(comment_type))
     self._ignoreua_directives.setdefault(address, set()).add(comment_type)
Beispiel #51
0
def eval_int(text):
    """Evaluate an integer operand.

    :param text: The operand.
    :return: The integer value.
    :raises: `ValueError` if the operand is not a valid integer.
    """
    try:
        return get_int_param(text)
    except ValueError:
        pass
    try:
        s = _convert_nums(_convert_chars(text))
        if set(s) <= OPERAND_AE_CHARS:
            return int(eval(s.replace('/', '//')))
    except (ValueError, TypeError):
        pass
    raise ValueError
Beispiel #52
0
 def _parse_asm_directive(self, address, directive, removed):
     if directive.startswith(
         ('isub=', 'ssub=', 'rsub=', 'ofix=', 'bfix=', 'rfix=')):
         weight = self.weights[directive[:4]]
         if weight > (0, 0):
             value = directive[5:].rstrip()
             if value.startswith('!'):
                 removed.update(parse_address_range(value[1:]))
             else:
                 self.subs[weight].append(value)
     elif directive.startswith('if('):
         try:
             address = self._parse_asm_directive(
                 address,
                 parse_if(self.fields, directive, 2)[1], removed)
         except MacroParsingError:
             pass
     elif directive.startswith('org'):
         org = directive.rstrip().partition('=')[2]
         if org:
             try:
                 address = get_int_param(org)
             except ValueError:
                 raise SkoolParsingError(
                     "Invalid org address: {}".format(org))
         else:
             address = None
     elif directive.startswith('keep'):
         self.keep = parse_asm_keep_directive(directive)
     elif directive.startswith('nowarn'):
         self.nowarn = parse_asm_nowarn_directive(directive)
     elif self.data is not None and directive.startswith(
         ('defb=', 'defs=', 'defw=')):
         self.data.append(directive)
     elif directive.startswith('remote='):
         addrs = [
             parse_int(a)
             for a in directive[7:].partition(':')[-1].split(',')
         ]
         if addrs[0] is not None:
             self.remote_entries.append(
                 Entry(None,
                       [Instruction(a) for a in addrs if a is not None]))
     return address
Beispiel #53
0
def _parse_expr(text, limit, brackets, non_neg, default):
    try:
        in_brackets = text.startswith("(") and text.endswith(")")
        if not brackets or in_brackets:
            if in_brackets:
                text = text[1:-1]
            try:
                value = get_int_param(text)
            except ValueError:
                s = _convert_nums(_convert_chars(text))
                if set(s) <= OPERAND_AE_CHARS:
                    value = int(eval(s.replace('/', '//')))
            if not (abs(value) >= limit or (non_neg and value < 0)):
                return value % limit
        raise ValueError
    except (ValueError, TypeError, UnboundLocalError):
        if default is None:
            raise ValueError
        return default
Beispiel #54
0
def _parse_expr(text, limit, brackets, non_neg, default):
    try:
        in_brackets = text.startswith("(") and text.endswith(")")
        if not brackets or in_brackets:
            if in_brackets:
                text = text[1:-1]
            try:
                value = get_int_param(text)
            except ValueError:
                s = _convert_nums(_convert_chars(text))
                if set(s) <= OPERAND_AE_CHARS:
                    value = int(eval(s.replace('/', '//')))
            if not (abs(value) >= limit or (non_neg and value < 0)):
                return value % limit
        raise ValueError
    except (ValueError, TypeError, UnboundLocalError):
        if default is None:
            raise ValueError
        return default
Beispiel #55
0
def get_defs_length(operation, preserve_base):
    if preserve_base:
        fmt = FORMAT_PRESERVE_BASE
    else:
        fmt = FORMAT_NO_BASE
    values = []
    for item in split_operation(operation)[1:3]:
        base = _get_base(item, preserve_base)
        try:
            value = get_int_param(item)
        except ValueError:
            try:
                item = value = parse_word(item)
            except ValueError:
                raise SkoolParsingError("Invalid integer '{}': {}".format(item, operation))
            if base == 'c':
                base = 'd'
        values.append((value, fmt[base].format(item)))
    return values[0][0], ':'.join([v[1] for v in values])
Beispiel #56
0
 def _parse_asm_directive(self, content):
     fields = [f.lstrip() for f in content.split(' ', 1)]
     if len(fields) < 2:
         raise CtlParserError("invalid ASM directive declaration")
     try:
         address = get_int_param(fields[0])
     except ValueError:
         raise CtlParserError("invalid ASM directive address")
     directive = fields[1]
     comment_type = 'i'
     if directive.startswith(AD_IGNOREUA + ':'):
         directive, comment_type = directive.split(':', 1)
     if directive != AD_IGNOREUA:
         return directive, address
     if comment_type not in COMMENT_TYPES:
         raise CtlParserError(
             "invalid @ignoreua directive suffix: '{}'".format(
                 comment_type))
     self._ignoreua_directives.setdefault(address, set()).add(comment_type)
Beispiel #57
0
 def _parse_instruction(self, line):
     try:
         address = get_int_param(line[1:6])
     except ValueError:
         raise SkoolParsingError("Invalid address ({}):\n{}".format(line[1:6], line.rstrip()))
     for sub in self.subs:
         if sub is not None:
             operation = sub
             self.subs = [None] * 4
             break
     else:
         comment_index = find_unquoted(line, ';', 6)
         operation = line[7:comment_index].strip()
     data = assemble(operation, address)
     if data:
         end_address = address + len(data)
         self.snapshot[address:end_address] = data
         self.base_address = min(self.base_address, address)
         self.end_address = max(self.end_address, end_address)
     else:
         warn("Failed to assemble:\n {} {}".format(address, operation))
Beispiel #58
0
def _load(snapshot, counters, blocks, param_str):
    try:
        block_num, start, length, step, offset, inc = _get_int_params(param_str, 6, (0,))
    except ValueError:
        raise SkoolKitError('Invalid integer in load spec: {}'.format(param_str))
    default_index = 1
    load_last = False
    if block_num.startswith('+'):
        block_num = block_num[1:]
        default_index = 0
    if block_num.endswith('+'):
        block_num = block_num[:-1]
        load_last = True
    block_num = get_int_param(block_num)
    index = counters.setdefault(block_num, default_index)
    try:
        block = blocks[block_num - 1]
    except IndexError:
        raise TapeError("Block {} not found".format(block_num))
    if length is None and load_last:
        length = len(block) - index
    length = _load_block(snapshot, block, start, length, step, offset, inc, index)
    counters[block_num] += length
Beispiel #59
0
    def _parse_asm_directive(self, directive):
        if self.mode.started:
            if directive.startswith('end'):
                self.mode.end()
                return

            if parse_asm_block_directive(directive, self.stack):
                include = True
                for p, i in self.stack:
                    if p == 'ofix':
                        do_op = self.mode.do_ofixes
                    elif p == 'bfix':
                        do_op = self.mode.do_bfixes
                    elif p == 'rfix':
                        do_op = self.mode.do_rfixes
                    elif p == 'isub':
                        do_op = self.mode.asm
                    elif p == 'ssub':
                        do_op = self.mode.do_ssubs
                    elif p == 'rsub':
                        do_op = self.mode.do_rsubs
                    if do_op:
                        include = i == '+'
                    else:
                        include = i == '-'
                    if not include:
                        break
                self.mode.include = include
                return

            if not self.mode.include:
                return

            if directive.startswith('label='):
                self.mode.label = directive[6:].rstrip()
            elif directive.startswith('keep'):
                self.mode.keep = True
            elif directive.startswith('replace='):
                self._add_replacement(directive[8:])
            elif directive.startswith('assemble='):
                try:
                    self.mode.assemble = int(directive[9:])
                except ValueError:
                    pass

            if self.mode.asm:
                if directive.startswith('rsub='):
                    self.mode.rsub = directive[5:].rstrip()
                elif directive.startswith('ssub='):
                    self.mode.ssub = directive[5:].rstrip()
                elif directive.startswith('isub='):
                    self.mode.isub = directive[5:].rstrip()
                elif directive.startswith('bfix='):
                    self.mode.bfix = directive[5:].rstrip()
                elif directive.startswith('ofix='):
                    self.mode.ofix = directive[5:].rstrip()
                elif directive.startswith('rfix='):
                    self.mode.rfix = directive[5:].rstrip()
                elif directive.startswith('nolabel'):
                    self.mode.nolabel = True
                elif directive.startswith('nowarn'):
                    self.mode.nowarn = True
                elif directive.startswith('ignoreua'):
                    self.mode.ignoreua = True
                    self.ignores.append(len(self.comments))
                elif directive.startswith('org='):
                    self.mode.org = directive[4:].rstrip()
                elif directive.startswith('writer='):
                    self.asm_writer_class = directive[7:].rstrip()
                elif directive.startswith('set-'):
                    name, sep, value = directive[4:].partition('=')
                    if sep:
                        self.properties[name.lower()] = value
                elif directive.startswith('equ='):
                    name, sep, value = directive[4:].rstrip().partition('=')
                    if sep:
                        self.equs.append((name, value))
                        try:
                            self._equ_values[get_int_param(value)] = name
                        except ValueError:
                            pass
        elif directive.startswith('start'):
            self.mode.start()
Beispiel #60
0
def _parse_num(num, brackets):
    if brackets:
        if num.startswith("(") and num.endswith(")"):
            return get_int_param(num[1:-1])
        raise ValueError
    return get_int_param(num)