Skip to content

Commit c58eed5

Browse files
committed
Refactor code generation and some misc changes
1 parent b648e8e commit c58eed5

File tree

8 files changed

+369
-183
lines changed

8 files changed

+369
-183
lines changed

asm_reader.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ class AsmReader:
1919
def __init__(self, text='', filename=''):
2020
self.text = text
2121
self.lineno = 1
22-
self.filename = filename or '<a.asm>'
22+
self.filename = filename
2323

2424
def feed(self, text):
2525
self.text += text

assembler.py

Lines changed: 38 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ def __init__(self):
2323
self.constants = {}
2424
self.function_subsequences = {}
2525
self.command_block_lines = []
26+
self.event_handlers = []
2627
self.included_subroutines = set()
2728
self.enter_subroutine('__main__')
2829
self.jump_later = None
@@ -33,15 +34,20 @@ def __init__(self):
3334
self.predef()
3435
self.init_instructions()
3536
self.enable_sync = False
36-
self.reader = None
37+
self.lineno = None
38+
self.filename = None
3739

3840
def predef(self):
3941
self.constants['sp'] = Var('stack_pointer')
4042
self.constants['sr'] = Var('stack_register')
4143

4244
def parse(self, text, filename=''):
43-
reader = self.reader = AsmReader(text, filename)
45+
self.filename = filename or '<a.asm>'
46+
self.consume_reader(AsmReader(text, self.filename))
47+
48+
def consume_reader(self, reader):
4449
for (token, arg) in reader:
50+
self.lineno = reader.lineno
4551
if token == 'const':
4652
name, ref = arg
4753
self.define_const(name, self.resolve_ref(*ref))
@@ -60,12 +66,10 @@ def parse(self, text, filename=''):
6066
self.handle_directive(*arg)
6167
elif token == 'eof':
6268
break
63-
self.reader = None
6469

6570
def warn(self, message):
6671
import warnings
67-
r = self.reader
68-
warnings.showwarning(message, UserWarning, r.filename, r.lineno)
72+
warnings.showwarning(message, UserWarning, self.filename, self.lineno)
6973

7074
def define_const(self, name, value):
7175
if name in self.constants:
@@ -195,28 +199,42 @@ def add_cast(self, type, cmd, dest):
195199
def handle_directive(self, directive, value):
196200
if directive == 'include':
197201
import os
198-
dir = os.path.dirname(self.reader.filename)
202+
our_file = self.filename
203+
dir = os.path.dirname(our_file)
199204
path = os.path.join(dir, value)
200205
with open(path, 'r') as f:
201206
data = f.read()
202-
old_reader = self.reader
203-
self.parse(data, path)
204-
self.reader = old_reader
207+
self.parse(data, path)
208+
self.filename = our_file
205209
elif directive == 'include_h':
206210
import os
207-
dir = os.path.dirname(self.reader.filename)
211+
our_file = self.filename
212+
dir = os.path.dirname(our_file)
208213
path = os.path.join(dir, value)
209214
with open(path, 'r') as f:
210215
data = f.read()
211-
assembler = Assembler()
212-
assembler.enable_sync = self.enable_sync
213-
assembler.parse(data, path)
214-
for sub in assembler.subroutines.keys():
215-
if sub.startswith('__'):
216-
continue
217-
self.included_subroutines.add(self.sub_to_func_name(sub))
218-
self.constants.update(assembler.constants)
219-
self.sync_func_ids.update(assembler.sync_func_ids)
216+
assembler = Assembler()
217+
assembler.enable_sync = self.enable_sync
218+
assembler.parse(data, path)
219+
for sub in assembler.subroutines.keys():
220+
if sub.startswith('__'):
221+
continue
222+
self.included_subroutines.add(self.sub_to_func_name(sub))
223+
self.constants.update(assembler.constants)
224+
self.sync_func_ids.update(assembler.sync_func_ids)
225+
elif directive == 'event_handler':
226+
handler, event, conditions = value.split(' ', 2)
227+
conds = {}
228+
if conditions:
229+
for cond in conditions.split(';'):
230+
key, value = cond.split('=', 1)
231+
path = tuple(key.split('.'))
232+
conds[path] = value
233+
self.event_handlers.append({
234+
'event': event,
235+
'conditions': conds,
236+
'handler': self.sub_to_func_name(handler)
237+
})
220238

221239
def init_instructions(self):
222240
self.instructions = {
@@ -857,6 +875,7 @@ def write_to_session(self, session):
857875
for name, sequence in self.function_subsequences.items():
858876
session.add_subsequence(name, sequence)
859877
session.add_command_blocks(self.command_block_lines)
878+
session.add_event_handlers(self.event_handlers)
860879

861880
def get_sub_jump_command(self, sub_name):
862881
return Function(self.sub_to_func_name(sub_name))

compiler/asm_extensions.py

Lines changed: 0 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -113,24 +113,6 @@ def __init__(self):
113113
'MOVINDD': self.handle_mov_ind_d,
114114
'MOVINDS': self.handle_mov_ind_s
115115
})
116-
self.event_handlers = []
117-
118-
def handle_directive(self, directive, value):
119-
if directive == 'event_handler':
120-
handler, event, conditions = value.split(' ', 2)
121-
conds = {}
122-
if conditions:
123-
for cond in conditions.split(';'):
124-
key, value = cond.split('=', 1)
125-
path = tuple(key.split('.'))
126-
conds[path] = value
127-
self.event_handlers.append({
128-
'event': event,
129-
'conditions': conds,
130-
'handler': self.sub_to_func_name(handler)
131-
})
132-
return
133-
super().handle_directive(directive, value)
134116

135117
def handle_ret(self):
136118
if not self.enable_sync:
@@ -180,9 +162,3 @@ def handle_mov_ind_s(self, src, s_off, dest):
180162
self.add_command(Function('mem_get'))
181163
self.add_command(OpAssign(dest, Var('memory_buffer')))
182164

183-
def write_to_session(self, session):
184-
super().write_to_session(session)
185-
for event_handler in self.event_handlers:
186-
session.add_event_handler(event_handler['event'],
187-
event_handler['conditions'],
188-
event_handler['handler'])

compiler/asm_writer.py

Lines changed: 149 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -1,25 +1,13 @@
1-
class AsmWriter:
1+
from asm_reader import AsmReader
2+
3+
class AsmStringBackend:
24

35
def __init__(self):
46
self.output = ''
57
self.indent = 0
6-
self.sub = False
7-
self._setup = []
8-
self.after_sub = []
98

10-
# TODO unused
11-
def write_statement(self, stmt):
12-
type, *args = stmt
13-
if type == 'constant':
14-
self.write_constant(*args)
15-
elif type == 'subroutine':
16-
self.write_subroutine(*args)
17-
elif type == 'instruction':
18-
self.write_instruction(*args)
19-
elif type == 'local_subroutine':
20-
self.write_local_sub(*args)
21-
elif type == 'directive':
22-
self.write_directive(*args)
9+
def get_output(self):
10+
return self.output
2311

2412
def write_constant(self, name, value):
2513
self.write_line('.%s %s' % (name, value))
@@ -30,48 +18,168 @@ def write_directive(self, name, value):
3018
def write_entity_local(self, name):
3119
self.write_line('@%s' % name)
3220

21+
def write_local_label(self, label):
22+
self.write_line('_%s:' % label)
23+
24+
def write_label(self, label):
25+
self.indent = 0
26+
self.write_line('%s:' % label)
27+
self.indent = 4
28+
29+
def write_instruction(self, insn, operands, comment=None):
30+
line = '%s%s' % (insn, (' ' + ', '.join(operands)) if operands else '')
31+
line = line.replace('\n', '\\n')
32+
if comment:
33+
line += ' ; ' + comment
34+
self.write_line(line)
35+
36+
def write_raw_asm(self, asm):
37+
self.write_line(asm)
38+
39+
def inject(self, block):
40+
self.output += block
41+
42+
def write_line(self, line):
43+
self.output += (' ' * self.indent) + line + '\n'
44+
45+
def ref_literal(self, number):
46+
return '#%d' % number
47+
48+
def ref_address(self, number):
49+
return '%d' % number
50+
51+
def ref_string(self, string):
52+
return '"%s"' % string.replace('\\', '\\\\').replace('"', '\\"')
53+
54+
def ref_symbol(self, symbol):
55+
return str(symbol)
56+
57+
def ref_raw(self, text):
58+
return str(text)
59+
60+
class AsmTokenBackend:
61+
62+
def __init__(self):
63+
self.tokens = []
64+
self.asm_reader = AsmReader()
65+
66+
def get_output(self):
67+
return self.tokens
68+
69+
def add(self, key, value):
70+
self.tokens.append((key, value))
71+
72+
def write_constant(self, name, value):
73+
self.add('const', (name, value))
74+
75+
def write_directive(self, name, value):
76+
self.add('directive', (name, value))
77+
78+
def write_entity_local(self, name):
79+
self.add('entity_local', name)
80+
81+
def write_local_label(self, label):
82+
self.add('local_label', label)
83+
84+
def write_label(self, label):
85+
self.add('label', label)
86+
87+
def write_instruction(self, insn, operands, comment=None):
88+
self.add('instruction', (insn, operands))
89+
90+
def write_raw_asm(self, asm):
91+
self.asm_reader.feed(asm)
92+
for token in self.asm_reader:
93+
self.tokens.append(token)
94+
95+
def inject(self, block):
96+
self.tokens.extend(block)
97+
98+
def ref_literal(self, number):
99+
return ('literal', number)
100+
101+
def ref_address(self, number):
102+
return ('address', number)
103+
104+
def ref_string(self, string):
105+
return ('string', string)
106+
107+
def ref_symbol(self, symbol):
108+
return ('symbol', symbol)
109+
110+
def ref_raw(self, text):
111+
return str(text)
112+
113+
class AsmWriter:
114+
115+
def __init__(self, backend='string'):
116+
self.backend = {
117+
'string': AsmStringBackend,
118+
'token': AsmTokenBackend
119+
}[backend]()
120+
self.backend_type = backend
121+
self.sub = False
122+
self._setup = []
123+
self.after_sub = []
124+
125+
def fork(self):
126+
return AsmWriter(self.backend_type)
127+
128+
def ref_literal(self, number):
129+
return self.backend.ref_literal(number)
130+
131+
def ref_address(self, number):
132+
return self.backend.ref_address(number)
133+
134+
def ref_string(self, string):
135+
return self.backend.ref_string(string)
136+
137+
def ref_symbol(self, symbol):
138+
return self.backend.ref_symbol(symbol)
139+
140+
def ref_raw(self, text):
141+
return self.backend.ref_raw(text)
142+
143+
def write_constant(self, name, value):
144+
self.backend.write_constant(name, value)
145+
146+
def write_directive(self, name, value):
147+
self.backend.write_directive(name, value)
148+
149+
def write_entity_local(self, name):
150+
self.backend.write_entity_local(name)
151+
33152
def write_subroutine(self, name):
34153
if name == '__setup__':
35154
return
36-
self.write_line('%s:' % name)
37-
self.indent = 4
38155
self.sub = True
156+
self.backend.write_label(name)
39157

40158
def end_subroutine(self):
41-
self.indent = 0
42-
self.write_line('')
43159
self.sub = False
44160
for after in self.after_sub:
45-
self.output += after
161+
self.backend.inject(after)
46162
self.after_sub = []
47163

48164
def write_after_subroutine(self, block):
49165
self.after_sub.append(block)
50166

51-
def write_instruction(self, insn, *args, comment=None, raw=False):
52-
if raw:
53-
line = '%s%s' % (insn, ''.join(args))
167+
def write_instruction(self, insn, *args, comment=None):
168+
if self.sub:
169+
self.backend.write_instruction(insn, args, comment)
54170
else:
55-
line = '%s%s' % (insn, (' ' + ', '.join(args)) if args else '')
56-
line = line.replace('\n', '\\n')
57-
if comment:
58-
line += ' ; ' + comment
59-
if not self.sub:
60-
self._setup.append(line)
61-
else:
62-
self.write_line(line)
171+
self._setup.append((insn, args, comment))
63172

64173
def write_local_sub(self, label):
65-
self.write_line('_%s:' % label)
174+
self.backend.write_local_label(label)
66175

67-
def write_line(self, line):
68-
self.output += (' ' * self.indent) + line + '\n'
176+
def write_raw_asm(self, asm):
177+
self.backend.write_raw_asm(asm)
69178

70179
def get_output(self):
71180
assert not self.sub
72-
setup = ''
73181
if self._setup:
74-
setup = '__setup__:\n '
75-
setup += '\n '.join(self._setup)
76-
setup += '\n\n'
77-
return self.output + setup
182+
self.backend.write_label('__setup__')
183+
for (insn, args, comment) in self._setup:
184+
self.backend.write_instruction(insn, args, comment)
185+
return self.backend.get_output()

0 commit comments

Comments
 (0)