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)
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])
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
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)
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))
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))
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))
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)
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)
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]))
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))
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))
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
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))
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))
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
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
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
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]
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
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]
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]
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]
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))
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)
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
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)
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)
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
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)
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
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])
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)
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
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)
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)
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))
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)
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
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
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
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])
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)
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))
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
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()
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)