|
4 | 4 |
|
5 | 5 | from . import opcodes
|
6 | 6 |
|
| 7 | +class Assembler: |
| 8 | + def __init__(self): |
| 9 | + self.symbols = {} |
| 10 | + self.code = [] |
| 11 | + self.addr = 0 |
7 | 12 |
|
8 |
| -def parse_line(line): |
9 |
| - """ |
10 |
| - parse one line of assembler into label, opcode, args |
11 |
| -
|
12 |
| - a line looks like (label, opcode, args, comment are all optional): |
13 |
| -
|
14 |
| - label: opcode arg1, arg2, ... # rest-of-line comment |
15 |
| - """ |
16 |
| - line = line.split('#', 1)[0].rstrip() |
17 |
| - if not line: |
18 |
| - return |
19 |
| - has_label = line[0] not in '\t ' |
20 |
| - if has_label: |
21 |
| - label_line = line.split(None, 1) |
22 |
| - if len(label_line) == 2: |
23 |
| - label, line = label_line |
24 |
| - else: # 1 |
25 |
| - label, line = label_line[0], None |
26 |
| - label = label.rstrip(':') |
27 |
| - else: |
28 |
| - label, line = None, line.lstrip() |
29 |
| - if line is None: |
30 |
| - opcode, args = None, () |
31 |
| - else: |
32 |
| - opcode_args = line.split(None, 1) |
33 |
| - if len(opcode_args) == 2: |
34 |
| - opcode, args = opcode_args |
35 |
| - args = tuple(arg.strip() for arg in args.split(',')) |
36 |
| - else: # 1 |
37 |
| - opcode, args = opcode_args[0], () |
38 |
| - return label, opcode, args |
39 |
| - |
40 |
| - |
41 |
| -def parse(lines): |
42 |
| - parsed = [parse_line(line) for line in lines] |
43 |
| - return [p for p in parsed if p is not None] |
44 |
| - |
45 |
| - |
46 |
| -def assemble(lines): |
47 |
| - symbols = {} |
48 |
| - code = [] |
49 |
| - addr = 0 |
50 |
| - for label, opcode, args in parse(lines): |
51 |
| - if label is not None: |
52 |
| - if label in symbols: |
53 |
| - raise Exception('label %s is already defined.' % label) |
54 |
| - symbols[label] = addr |
55 |
| - if opcode is not None: |
56 |
| - func = getattr(opcodes, 'i_' + opcode, None) |
57 |
| - if func is None: |
58 |
| - raise Exception('Unknown opcode: %s' % opcode) |
59 |
| - instruction = func(*args) |
60 |
| - code.append(instruction) |
61 |
| - addr += 1 |
62 |
| - return symbols, code |
| 13 | + def parse_line(self, line): |
| 14 | + """ |
| 15 | + parse one line of assembler into label, opcode, args |
| 16 | +
|
| 17 | + a line looks like (label, opcode, args, comment are all optional): |
| 18 | +
|
| 19 | + label: opcode arg1, arg2, ... # rest-of-line comment |
| 20 | + """ |
| 21 | + line = line.split('#', 1)[0].rstrip() |
| 22 | + if not line: |
| 23 | + return |
| 24 | + has_label = line[0] not in '\t ' |
| 25 | + if has_label: |
| 26 | + label_line = line.split(None, 1) |
| 27 | + if len(label_line) == 2: |
| 28 | + label, line = label_line |
| 29 | + else: # 1 |
| 30 | + label, line = label_line[0], None |
| 31 | + label = label.rstrip(':') |
| 32 | + else: |
| 33 | + label, line = None, line.lstrip() |
| 34 | + if line is None: |
| 35 | + opcode, args = None, () |
| 36 | + else: |
| 37 | + opcode_args = line.split(None, 1) |
| 38 | + if len(opcode_args) == 2: |
| 39 | + opcode, args = opcode_args |
| 40 | + args = tuple(arg.strip() for arg in args.split(',')) |
| 41 | + else: # 1 |
| 42 | + opcode, args = opcode_args[0], () |
| 43 | + return label, opcode, args |
| 44 | + |
| 45 | + |
| 46 | + def parse(self, lines): |
| 47 | + parsed = [self.parse_line(line) for line in lines] |
| 48 | + return [p for p in parsed if p is not None] |
| 49 | + |
| 50 | + |
| 51 | + def assemble(self, lines): |
| 52 | + for label, opcode, args in self.parse(lines): |
| 53 | + if label is not None: |
| 54 | + if label in self.symbols: |
| 55 | + raise Exception('label %s is already defined.' % label) |
| 56 | + self.symbols[label] = self.addr |
| 57 | + if opcode is not None: |
| 58 | + func = getattr(opcodes, 'i_' + opcode, None) |
| 59 | + if func is None: |
| 60 | + raise Exception('Unknown opcode: %s' % opcode) |
| 61 | + instruction = func(*args) |
| 62 | + self.code.append(instruction) |
| 63 | + self.addr += 1 |
| 64 | + return self.symbols, self.code |
63 | 65 |
|
0 commit comments