diff options
| author | s-ol <s+removethis@s-ol.nu> | 2021-05-22 16:23:57 +0000 |
|---|---|---|
| committer | s-ol <s+removethis@s-ol.nu> | 2021-05-22 16:24:36 +0000 |
| commit | 0658187afb830fbcf082950b30f0be6cea4455a0 (patch) | |
| tree | bc174c1d648951157ff7957f1bdf8f34e9e2ae72 | |
| parent | support non-byte aligned data lines (diff) | |
| download | subv-0658187afb830fbcf082950b30f0be6cea4455a0.tar.gz subv-0658187afb830fbcf082950b30f0be6cea4455a0.zip | |
log offending line when errors occur, across all stages
| -rwxr-xr-x | elf.py | 15 | ||||
| -rwxr-xr-x | format.py | 57 | ||||
| -rwxr-xr-x | pack.py | 2 | ||||
| -rw-r--r-- | subv.py | 42 | ||||
| -rwxr-xr-x | survey.py | 5 |
5 files changed, 74 insertions, 47 deletions
@@ -80,12 +80,11 @@ def write_program_header(segment, c, start): c += wi(align, 4) # p_align return c -if __name__ == "__main__": +@subv.with_parsed_lines +def elf(iter): segments = [] segment = None - for line in sys.stdin: - line = subv.parse(line) - + for line in iter: if line['type'] == 'segment': (name, addr) = line['segment'] segment = { 'name': name, 'addr': addr, 'content': [] } @@ -98,8 +97,6 @@ if __name__ == "__main__": else: raise ValueError("elf input should contain only segments and data!") - cursor = 0 - c = write_elf_header(segments) segment_start = 0x1000 for seg in segments: @@ -110,3 +107,9 @@ if __name__ == "__main__": c = padto(seg['offset'], c) for part in seg['content']: c += wi(part[0], 1) + + yield + +if __name__ == '__main__': + for line in elf(sys.stdin): + pass @@ -282,44 +282,27 @@ instr_map = { 'jal': (pack_j, 0x6f), } +@subv.with_parsed_lines def format(iter): - for line_no, raw_line in enumerate(iter, start=1): - try: - line = subv.parse(raw_line) - except AssertionError as e: - message = ''' -failed to format line: -<input>:{} {} -parsed as {} - '''.strip().format(line_no, raw_line.strip()) - raise Exception(message) from e - - try: - if line['type'] == 'instr': - op = line['instr'][0] - assert len(op) == 2, 'instruction without op label: {}'.format(op) - - (op, label) = op - if label not in instr_map: - raise ValueError("unknown instruction label: {}".format(label)) - (formatter, expected) = instr_map[label] - if op != expected: - raise ValueError("opcode {} doesn't match label {} (expected {})" - .format(op, label, expected)) - - formatted = formatter(line['instr']) - formatted[0] = (*formatted[0], label) - line['instr'] = formatted - yield subv.format(line) - else: - yield line['raw'] - except AssertionError as e: - message = ''' -failed to format line: -<input>:{} {} -parsed as {} - '''.strip().format(line_no, raw_line.strip(), subv.dump(line)) - raise Exception(message) from e + for line in iter: + if line['type'] == 'instr': + op = line['instr'][0] + assert len(op) == 2, 'instruction without op label: {}'.format(op) + + (op, label) = op + if label not in instr_map: + raise ValueError("unknown instruction label: {}".format(label)) + (formatter, expected) = instr_map[label] + if op != expected: + raise ValueError("opcode {} doesn't match label {} (expected {})" + .format(op, label, expected)) + + formatted = formatter(line['instr']) + formatted[0] = (*formatted[0], label) + line['instr'] = formatted + line = yield subv.format(line) + else: + line = yield line['raw'] if __name__ == '__main__': import sys @@ -62,6 +62,7 @@ def byteify(word): out.append(byte[:1]) return out +@subv.with_parsed_lines def pack(iter): segment = None @@ -78,7 +79,6 @@ def pack(iter): } for line in iter: - line = subv.parse(line) if line['type'] == 'data': for part in line['data']: buf = bits.concat(buf, bits.from_part(part)) @@ -288,3 +288,45 @@ def dump(line): def join_all(gen): res = '\n'.join(gen) return res + + +class SubVException(Exception): + pass + +class LineIterator(object): + def __init__(self, stream): + self.stream = stream + self.iter = enumerate(self.stream, start=1) + self.i, self.raw_line, self.line = 0, None, None + + def __iter__(self): + return self + + def __next__(self): + self.i, self.raw_line = next(self.iter) + self.line = None + try: + self.line = parse(self.raw_line) + except Exception as e: + raise self.exception("failed to parse line") from e + return self.line + + def exception(self, msg): + if self.line: + msg = msg + "\n{}:{}: {}".format(self.stream.name, self.i, format(self.line)) + msg = msg + "\nparsed as {}".format(dump(self.line)) + elif self.raw_line: + msg = msg + "\n{}:{}: {}".format(self.stream.name, self.i, self.raw_line.strip()) + return SubVException(msg) + +def with_parsed_lines(process_fn): + def _wrapped(iter): + iterator = LineIterator(iter) + try: + yield from process_fn(iterator) + except SubVException: + raise + except Exception as e: + raise iterator.exception("failed to {} line".format(process_fn.__name__)) from e + + return _wrapped @@ -90,13 +90,12 @@ def observe(part, rel_addr, map): return bits.slice(addr, ref['hi'], ref['lo']) +@subv.with_parsed_lines def survey(iter): queue = [] map = {} - addr = -1 - bits = 0 + addr, bits = -1, 0 for line in iter: - line = subv.parse(line) line['addr'] = addr queue.append(line) |
