Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Newer
Older
100644 484 lines (398 sloc) 15.839 kb
ae5ad92 Stephen Roller Rudimentary code generator.
authored
1 #!/usr/bin/env python
2
d2e01fb Stephen Roller Global variables.
authored
3 from semantic import first_definition
4
ae5ad92 Stephen Roller Rudimentary code generator.
authored
5 # REGISTERS
6 ZERO = 0 # always zero
7 AC1 = 1 # Accumulator 1
8 AC2 = 2 # Accumulator 2
9 AC3 = 3 # Accumulator 3
426bf87 Stephen Roller Add support for comments. Kinda makes things a little grosser.
authored
10 ST = 4 # Temporary storage
ae5ad92 Stephen Roller Rudimentary code generator.
authored
11 FP = 5 # points to the start of the frame
12 SP = 6 # points to the top of the stack
13 PC = 7 # points to the next instruction
14
d2e01fb Stephen Roller Global variables.
authored
15 # variable locations, done the same as in type checking
16 # a global stack of dictionaries.
17 variables = [{}]
f5fac0e Stephen Roller Yay, got procs with no return values or addresses.
authored
18 # global dictionary of proc locations
19 procs = {}
d2e01fb Stephen Roller Global variables.
authored
20
7b1b19d Stephen Roller Move code around for organization.
authored
21 # Code generation utilities -------------------------------------------------
ae5ad92 Stephen Roller Rudimentary code generator.
authored
22
366d642 Stephen Roller Seemed to get procs with parameters, but not return values.
authored
23 def type9_size(ice9_type):
24 """Returns the full size of the ice9 type in words."""
25 return 1
26
64f58b1 Stephen Roller Use a code_length method that ignores comments for easier jump calculati...
authored
27 def is_comment(inst5):
28 "Returns whether this 'instruction' is just a comment."
29 return type(inst5) is tuple and inst5[0] == 'comment'
30
31 def code_length(code5):
32 """Returns the length of the code with comments removed."""
33 return len([1 for inst5 in code5 if not is_comment(inst5)])
34
366d642 Stephen Roller Seemed to get procs with parameters, but not return values.
authored
35 def push_register(reg, comment=None):
5581f25 Stephen Roller Handle add/sub/mul/div properly.
authored
36 """Creates code for pushing a register onto the stack."""
366d642 Stephen Roller Seemed to get procs with parameters, but not return values.
authored
37 if not comment:
38 comment = 'Store reg %s on the stack' % reg
f5fac0e Stephen Roller Yay, got procs with no return values or addresses.
authored
39 return [('LDA', SP, -1, SP, 'Move (push) the stack pointer'),
366d642 Stephen Roller Seemed to get procs with parameters, but not return values.
authored
40 ('ST', reg, 0, SP, comment)]
5581f25 Stephen Roller Handle add/sub/mul/div properly.
authored
41
366d642 Stephen Roller Seemed to get procs with parameters, but not return values.
authored
42 def pop_register(reg, comment=None):
5581f25 Stephen Roller Handle add/sub/mul/div properly.
authored
43 """Creates code for popping a register off the stack."""
366d642 Stephen Roller Seemed to get procs with parameters, but not return values.
authored
44 if not comment:
45 comment = 'Get reg %d off the stack' % reg
46 return [('LD', reg, 0, SP, comment),
f5fac0e Stephen Roller Yay, got procs with no return values or addresses.
authored
47 ('LDA', SP, 1, SP, 'Move (pop) the stack pointer')]
48
49 def push_var(varname, vartype):
50 """Allocates room for a variable on the stack."""
366d642 Stephen Roller Seemed to get procs with parameters, but not return values.
authored
51 return [('LDA', SP, - type9_size(vartype), SP, "Make room for %s on the stack" % varname)]
5581f25 Stephen Roller Handle add/sub/mul/div properly.
authored
52
426bf87 Stephen Roller Add support for comments. Kinda makes things a little grosser.
authored
53 def comment(comment):
f62430d Stephen Roller Comments and docstrings.
authored
54 """Makes a comment line."""
426bf87 Stephen Roller Add support for comments. Kinda makes things a little grosser.
authored
55 return [('comment', 0, 0, 0, comment)]
bb16c1a Stephen Roller Move stuff around.
authored
56
7b1b19d Stephen Roller Move code around for organization.
authored
57 def passthru(ast):
58 """
59 Code generated by this item is the sequential concatenation of its
60 children. Useful for statements, etc.
61 """
62 from operator import add
63 return reduce(add, [generate_code(c) for c in ast.children], [])
64
65 # NODE_TYPE RULES ---------------------------------------------------------
66
bb16c1a Stephen Roller Move stuff around.
authored
67 def literal(ast):
f62430d Stephen Roller Comments and docstrings.
authored
68 """Generates code for literal constants."""
bb16c1a Stephen Roller Move stuff around.
authored
69 if ast.ice9_type == 'int' or ast.ice9_type == 'bool':
426bf87 Stephen Roller Add support for comments. Kinda makes things a little grosser.
authored
70 return [('LDC', AC1, int(ast.value), 0, 'load constant: %s' % ast.value)]
f62430d Stephen Roller Comments and docstrings.
authored
71 elif ast.ice9_type == 'str':
72 # TODO: implement strings
73 pass
bb16c1a Stephen Roller Move stuff around.
authored
74
8ff6191 Stephen Roller Yay, write/writes work!
authored
75 def writes(ast):
f62430d Stephen Roller Comments and docstrings.
authored
76 """Handles writing to output."""
8ff6191 Stephen Roller Yay, write/writes work!
authored
77 value = ast.children[0]
a1fa834 Stephen Roller Support adding two values.
authored
78 childcode = generate_code(ast.children[0])
8ff6191 Stephen Roller Yay, write/writes work!
authored
79 if value.ice9_type == 'int':
a1fa834 Stephen Roller Support adding two values.
authored
80 return childcode + [('OUT', AC1, 0, 0, 'writing int')]
426bf87 Stephen Roller Add support for comments. Kinda makes things a little grosser.
authored
81 elif value.ice9_type == 'bool':
a1fa834 Stephen Roller Support adding two values.
authored
82 return childcode + [('OUTB', AC1, 0, 0, 'writing bool')]
426bf87 Stephen Roller Add support for comments. Kinda makes things a little grosser.
authored
83 else:
84 raise ValueError("unimplmented")
8ff6191 Stephen Roller Yay, write/writes work!
authored
85
86 def write(ast):
f62430d Stephen Roller Comments and docstrings.
authored
87 """Handles write command (contains a newline)."""
426bf87 Stephen Roller Add support for comments. Kinda makes things a little grosser.
authored
88 return writes(ast) + [('OUTNL', 0, 0, 0, 'newline for write')]
89
d2e01fb Stephen Roller Global variables.
authored
90 def ident(ast):
91 varname = ast.value
92 memloc, relreg = first_definition(variables, varname)
93 return [('LD', AC1, memloc, relreg, 'Load %s to register 1' % varname)]
94
95 def assignment(ast):
96 var, val = ast.children
97 varname = var.value
98 code5 = comment('ASSIGN to %s:' % varname) + generate_code(val)
99 memloc, relreg = first_definition(variables, varname)
100 code5 += [('ST', AC1, memloc, relreg, 'STORE variable %s' % varname)]
101 code5 += comment('END ASSIGN TO %s' % varname)
102 return code5
103
426bf87 Stephen Roller Add support for comments. Kinda makes things a little grosser.
authored
104 def program(ast):
7b1b19d Stephen Roller Move code around for organization.
authored
105 """Generates code for a whole program."""
f5fac0e Stephen Roller Yay, got procs with no return values or addresses.
authored
106 # make sure variable and proc locations are reset
107 global variables, procs
d2e01fb Stephen Roller Global variables.
authored
108 variables = [{}]
f5fac0e Stephen Roller Yay, got procs with no return values or addresses.
authored
109 procs = {}
d2e01fb Stephen Roller Global variables.
authored
110
111 code5 = comment("PREAMBLE")
112 # variable declarations:
113 i = 1
114 for var, type9 in ast.vars:
366d642 Stephen Roller Seemed to get procs with parameters, but not return values.
authored
115 code5 += [('alloc', type9_size(type9), 0, 0, var)]
d2e01fb Stephen Roller Global variables.
authored
116 code5 += comment('DECLARE "%s"' % var)
117 variables[0][var] = i, ZERO
118 i += 1
f5fac0e Stephen Roller Yay, got procs with no return values or addresses.
authored
119
120 children = ast.children
121 # general program code.
122 while len(children) > 0 and children[0].node_type == 'proc':
123 procnode = children.pop(0)
124 procname = procnode.value
125 proclocation = code_length(code5) + 1
126 procs[procname] = proclocation
127 code5 += generate_code(procnode)
128
129
130 code5.insert(1, ('JEQ', ZERO, code_length(code5), PC,
131 'skip variable and proc declarations'))
8522067 Stephen Roller Poorly handle binary operators. Add stack pointer preamble.
authored
132
133 # set the stack pointer
134 code5 += [('LD', SP, ZERO, ZERO, 'Set the stack pointer')]
135
136 code5 += comment("END PREAMBLE")
137 code5 += comment("START OF PROGRAM")
f5fac0e Stephen Roller Yay, got procs with no return values or addresses.
authored
138
8522067 Stephen Roller Poorly handle binary operators. Add stack pointer preamble.
authored
139 code5 += passthru(ast)
f5fac0e Stephen Roller Yay, got procs with no return values or addresses.
authored
140
8522067 Stephen Roller Poorly handle binary operators. Add stack pointer preamble.
authored
141 code5 += comment('END OF PROGRAM')
f5fac0e Stephen Roller Yay, got procs with no return values or addresses.
authored
142
143 # we need to go back and add all our proc call jumps
144 realcode5 = []
145 for inst5 in code5:
146 inst, r, s, t, com = inst5
147 if inst == 'call':
148 procname = r
149 memloc = procs[procname]
150 realcode5.append(('LDC', PC, memloc, ZERO, com))
151 else:
152 realcode5.append(inst5)
153
154 code5 = realcode5
8522067 Stephen Roller Poorly handle binary operators. Add stack pointer preamble.
authored
155 return code5
a1fa834 Stephen Roller Support adding two values.
authored
156
8522067 Stephen Roller Poorly handle binary operators. Add stack pointer preamble.
authored
157 # Binary operators ---------------------------------------------------------
158 def binary_operator(opinst, ast):
159 """
160 Generic binary operator handler. opinst should one of ADD, SUB, DIV or
161 MUL. ast is the AST including the operator node.
162 """
a1fa834 Stephen Roller Support adding two values.
authored
163 left, right = ast.children
5581f25 Stephen Roller Handle add/sub/mul/div properly.
authored
164
165 # Store the result of the left operand on the stack.
a1fa834 Stephen Roller Support adding two values.
authored
166 code5 = generate_code(left)
5581f25 Stephen Roller Handle add/sub/mul/div properly.
authored
167 code5 += push_register(AC1)
168
169 # store value of right operand is in AC1
a1fa834 Stephen Roller Support adding two values.
authored
170 code5 += generate_code(right)
5581f25 Stephen Roller Handle add/sub/mul/div properly.
authored
171
172 # Get the left value off the stack and put it in AC2
173 code5 += pop_register(AC2)
174
175 # And add the two and store in AC1
176 code5 += [(opinst, AC1, AC2, AC1, '%s left and right.' % opinst)]
a1fa834 Stephen Roller Support adding two values.
authored
177 return code5
178
8522067 Stephen Roller Poorly handle binary operators. Add stack pointer preamble.
authored
179 def add(ast):
799c049 Stephen Roller Add support for boolean OR.
authored
180 """Handles integer addition and boolean OR."""
181 if ast.ice9_type == 'int':
182 # integer addition
183 return binary_operator('ADD', ast)
184 else:
185 assert ast.ice9_type == 'bool'
186 # boolean OR
187 left, right = ast.children
188 leftcode = generate_code(left)
189 rightcode = generate_code(right)
190
191 code5 = comment('boolean OR')
192 code5 += leftcode
64f58b1 Stephen Roller Use a code_length method that ignores comments for easier jump calculati...
authored
193 code5 += [('JNE', AC1, code_length(rightcode), PC, 'short circuit boolean OR')]
799c049 Stephen Roller Add support for boolean OR.
authored
194 code5 += rightcode
195 code5 += comment('end boolean OR')
196 return code5
8522067 Stephen Roller Poorly handle binary operators. Add stack pointer preamble.
authored
197
198 def mul(ast):
f6f76ee Stephen Roller Boolean AND.
authored
199 """Handles integer multiplication and boolean AND."""
200 if ast.ice9_type == 'int':
201 # integer multiplication
202 return binary_operator('MUL', ast)
203 else:
204 # boolean AND
205 assert ast.ice9_type == 'bool'
206 left, right = ast.children
207 leftcode = generate_code(left)
208 rightcode = generate_code(right)
209
210 code5 = comment('boolean AND')
211 code5 += leftcode
212 code5 += [('JEQ', AC1, code_length(rightcode), PC, 'short circuit boolean AND')]
213 code5 += rightcode
214 code5 += comment('end boolean AND')
215 return code5
8522067 Stephen Roller Poorly handle binary operators. Add stack pointer preamble.
authored
216
217 def div(ast):
218 """Handles division."""
219 return binary_operator('DIV', ast)
220
221 def sub(ast):
222 """Handles both binary and unary subtraction."""
223 if len(ast.children) == 1:
6ec94fa Stephen Roller Boolean negation.
authored
224 if ast.ice9_type == 'int':
225 # unary subtract, we really should just multiply by -1
226 return generate_code(ast.children[0]) + comment('integer negation:') + [
227 ('LDC', AC2, -1, ZERO, 'Prepare to invert sign.'),
228 ('MUL', AC1, AC1, AC2, 'Invert sign.')
229 ]
230 else:
231 # boolean negation
232 assert ast.ice9_type == 'bool'
233 return generate_code(ast.children[0]) + comment('boolean negation:') + [
234 ('LDC', AC2, -1, ZERO, 'Prepare invert sign.'),
235 ('MUL', AC1, AC1, AC2, 'Invert sign.'),
236 ('LDA', AC1, 1, AC1, 'Convert back to boolean.')
237 ]
8522067 Stephen Roller Poorly handle binary operators. Add stack pointer preamble.
authored
238 else:
6ec94fa Stephen Roller Boolean negation.
authored
239 # integer subtraction
5581f25 Stephen Roller Handle add/sub/mul/div properly.
authored
240 assert len(ast.children) == 2, "Subtract should only have two nodes"
6ec94fa Stephen Roller Boolean negation.
authored
241 assert ast.ice9_type == 'int', "Must be integer subtraction"
8522067 Stephen Roller Poorly handle binary operators. Add stack pointer preamble.
authored
242 return binary_operator('SUB', ast)
243
259fd16 Stephen Roller Comparison operators.
authored
244 def comparison(comparenode):
245 jumpinstrs = {'=': 'JEQ', '!=': 'JNE',
246 '>': 'JGT', '>=': 'JGE',
247 '<': 'JLT', '<=': 'JLE'}
248
249 op = comparenode.value
250 inst = jumpinstrs[op]
251
252 code5 = comment("BEGIN COMPARISON %s" % op)
253 code5 += binary_operator('SUB', comparenode)
254 code5 += [
255 (inst, AC1, 1, PC, 'skip set to false'),
256 ('LDC', AC1, 0, 0, 'comparison is bad, set reg 1 to false'),
257 ('JEQ', ZERO, 1, PC, 'skip set to true'),
258 ('LDC', AC1, 1, 0, 'compairson is good, set reg 1 to true'),
259 ]
260 code5 += comment("END COMPARISON %s" % op)
261 return code5
262
8522067 Stephen Roller Poorly handle binary operators. Add stack pointer preamble.
authored
263 # end binary operators ------------------------------------------------------
264
1ecb18e Stephen Roller Seem to have basic do loops!
authored
265 # condition code ----------------------------------------------------------
fc449d2 Stephen Roller Seemed to get if-then-else statements.
authored
266 def cond(ast):
267 children = ast.children
268
269 code5 = []
270
271 while len(children) > 1:
272 cond = children.pop(0)
273 dothen = children.pop(0)
274
275 stmtcode = generate_code(dothen)
276 condcode = generate_code(cond)
277
278 code5 += comment('IF condition:')
279 code5 += condcode
64f58b1 Stephen Roller Use a code_length method that ignores comments for easier jump calculati...
authored
280 code5 += [('JEQ', AC1, code_length(stmtcode) + 1, PC, 'if false, jump to next cond')]
fc449d2 Stephen Roller Seemed to get if-then-else statements.
authored
281 code5 += comment('IF was true, THEN:')
282 code5 += stmtcode
283 code5 += ['jumpend']
284
285 if len(children) == 1:
286 stmtcode = generate_code(children.pop(0))
287 code5 += comment("ELSE:") + stmtcode
288
289 # total number of instructions with comments excluded
64f58b1 Stephen Roller Use a code_length method that ignores comments for easier jump calculati...
authored
290 codecount = code_length(code5)
fc449d2 Stephen Roller Seemed to get if-then-else statements.
authored
291
292 # need to go back and replace our jump labels with the real instruction offsets
293 realcode5 = []
294 i = 0
295 for inst5 in code5:
296 if inst5 == 'jumpend':
297 # label telling us to jump to the end of the statement
298 numleft = codecount - i - 1
299 realcode5.append(('JEQ', ZERO, numleft, PC, 'jump to end of if-then-else'))
300 else:
301 realcode5.append(inst5)
302
64f58b1 Stephen Roller Use a code_length method that ignores comments for easier jump calculati...
authored
303 if not is_comment(code5):
fc449d2 Stephen Roller Seemed to get if-then-else statements.
authored
304 i += 1
305
306 code5 = realcode5
307
308 return code5
309
1ecb18e Stephen Roller Seem to have basic do loops!
authored
310 def do_loop(ast):
311 cond, stmt = ast.children
312 condcode = generate_code(cond)
313 stmtcode = generate_code(stmt)
314
315 code5 = comment('BEGIN DO COND')
316 code5 += condcode
64f58b1 Stephen Roller Use a code_length method that ignores comments for easier jump calculati...
authored
317 code5 += [('JEQ', AC1, code_length(stmtcode) + 1, PC, 'jump if do cond is false')]
1ecb18e Stephen Roller Seem to have basic do loops!
authored
318 code5 += comment('cond true, DO:')
319 code5 += stmtcode
64f58b1 Stephen Roller Use a code_length method that ignores comments for easier jump calculati...
authored
320 code5 += [('JEQ', ZERO, -code_length(condcode + stmtcode) - 2, PC,
321 'End of DO, go back to beginning')]
1ecb18e Stephen Roller Seem to have basic do loops!
authored
322
323 return code5
324
f5fac0e Stephen Roller Yay, got procs with no return values or addresses.
authored
325 # proc stuff ---------------------------------------------------------------
326
366d642 Stephen Roller Seemed to get procs with parameters, but not return values.
authored
327 # memory representation
7c4bf96 Stephen Roller Handle return values!
authored
328 # +-------------------------------------------------------------------------------+
329 # | program... | ... | var2 | var1| retval | retaddr | param1 | p2 | lastfp | ... |
330 # +-------------------------------------------------------------------------------+
331 # ^ ^ ^ ^
332 # sp fp fp + fpoffset dmem
366d642 Stephen Roller Seemed to get procs with parameters, but not return values.
authored
333
f5fac0e Stephen Roller Yay, got procs with no return values or addresses.
authored
334 def proc(procnode):
366d642 Stephen Roller Seemed to get procs with parameters, but not return values.
authored
335 global variables
336 variables.insert(0, {})
337
338 children = procnode.children
f5fac0e Stephen Roller Yay, got procs with no return values or addresses.
authored
339 procname = procnode.value
366d642 Stephen Roller Seemed to get procs with parameters, but not return values.
authored
340 body = children.pop(-1)
341
f5fac0e Stephen Roller Yay, got procs with no return values or addresses.
authored
342 code5 = comment('BEGIN PROC %s' % procname)
366d642 Stephen Roller Seemed to get procs with parameters, but not return values.
authored
343 code5 += [('LDA', FP, 0, SP, 'Set frame pointer')]
f5fac0e Stephen Roller Yay, got procs with no return values or addresses.
authored
344
366d642 Stephen Roller Seemed to get procs with parameters, but not return values.
authored
345 # set memory locations of params
346 fpoffset = 1
347 for p in children:
348 paramname = p.value
349 paramloc = fpoffset
350 variables[0][paramname] = (fpoffset, FP)
351 fpoffset += type9_size(fpoffset)
352
353 # set memory locations of local variables
7c4bf96 Stephen Roller Handle return values!
authored
354 vars = procnode.vars
355 if procnode.ice9_type != 'nil':
356 vars.insert(0, (procname, procnode.ice9_type))
357
366d642 Stephen Roller Seemed to get procs with parameters, but not return values.
authored
358 i = 0
359 for var, type9 in procnode.vars:
360 code5 += push_var(var, type9)
361 i += type9_size(type9)
362 variables[0][var] = (- i, FP)
363
364 # generate code of proc
365 code5 += generate_code(body)
7c4bf96 Stephen Roller Handle return values!
authored
366
367 if procnode.ice9_type != 'nil':
368 # handle return value
369 code5 += [('LD', AC1, -1, FP, 'Store the return value in AC1')]
370
366d642 Stephen Roller Seemed to get procs with parameters, but not return values.
authored
371 code5 += pop_register(AC2, 'pop return address')
7c4bf96 Stephen Roller Handle return values!
authored
372
366d642 Stephen Roller Seemed to get procs with parameters, but not return values.
authored
373 code5 += [('LDA', SP, fpoffset, FP, 'Pop off local values from the stack')]
374 code5 += [('LD', PC, 0, FP, 'Moving return address into PC')]
f5fac0e Stephen Roller Yay, got procs with no return values or addresses.
authored
375 code5 += comment('END PROC %s' % procname)
366d642 Stephen Roller Seemed to get procs with parameters, but not return values.
authored
376
377 variables.pop(0)
f5fac0e Stephen Roller Yay, got procs with no return values or addresses.
authored
378 return code5
379
380 def proc_call(pcnode):
381 # push the return address
382 procname = pcnode.value
383 code5 = comment('BEGIN PROC CALL %s' % procname)
366d642 Stephen Roller Seemed to get procs with parameters, but not return values.
authored
384 code5 += push_register(FP, 'store the frame pointer before the call')
385
386 params = pcnode.children # calling parameters
387 params.reverse() # we want to push on in reverse so they'll be in order in mem
388 for p in params:
389 code5 += generate_code(p)
390 code5 += push_register(AC1, 'push parameter')
391
f5fac0e Stephen Roller Yay, got procs with no return values or addresses.
authored
392 code5 += [('LDA', AC2, 3, PC, 'Store return address in AC2')]
366d642 Stephen Roller Seemed to get procs with parameters, but not return values.
authored
393 code5 += push_register(AC2, 'store the return address')
f5fac0e Stephen Roller Yay, got procs with no return values or addresses.
authored
394 code5 += [('call', procname, 0, 0, 'CALL %s' % procname)]
366d642 Stephen Roller Seemed to get procs with parameters, but not return values.
authored
395 code5 += pop_register(FP, 'pop the frame pointer after call')
f5fac0e Stephen Roller Yay, got procs with no return values or addresses.
authored
396 code5 += comment('END PROC CALL %s' % procname)
397 return code5
398
8522067 Stephen Roller Poorly handle binary operators. Add stack pointer preamble.
authored
399 # core algorithm ---------------------------------------------------------
400
bb16c1a Stephen Roller Move stuff around.
authored
401 # the repeated callback paradigm
402 callbacks = {
403 'literal': literal,
8ff6191 Stephen Roller Yay, write/writes work!
authored
404 'write': write,
405 'writes': writes,
426bf87 Stephen Roller Add support for comments. Kinda makes things a little grosser.
authored
406 'program': program,
a1fa834 Stephen Roller Support adding two values.
authored
407 'statements': passthru,
408 '+': add,
8522067 Stephen Roller Poorly handle binary operators. Add stack pointer preamble.
authored
409 '*': mul,
410 '/': div,
411 '-': sub,
ce948e8 Stephen Roller ? support.
authored
412 '?': passthru,
fc449d2 Stephen Roller Seemed to get if-then-else statements.
authored
413 'cond': cond,
1ecb18e Stephen Roller Seem to have basic do loops!
authored
414 'do_loop': do_loop,
d2e01fb Stephen Roller Global variables.
authored
415 'ident': ident,
416 'assignment': assignment,
259fd16 Stephen Roller Comparison operators.
authored
417 '=': comparison,
418 '!=': comparison,
419 '<': comparison,
420 '<=': comparison,
421 '>': comparison,
422 '>=': comparison,
f5fac0e Stephen Roller Yay, got procs with no return values or addresses.
authored
423 'proc': proc,
424 'proc_call': proc_call,
bb16c1a Stephen Roller Move stuff around.
authored
425 }
426
ae5ad92 Stephen Roller Rudimentary code generator.
authored
427 def generate_code(ast):
428 """
426bf87 Stephen Roller Add support for comments. Kinda makes things a little grosser.
authored
429 Generates a list of 5-tuples describing instructions for TM code of the form
430 (inst, r, s, t, comment)
ae5ad92 Stephen Roller Rudimentary code generator.
authored
431 """
bb16c1a Stephen Roller Move stuff around.
authored
432 def noop(ast):
433 # returns empty code
d2e01fb Stephen Roller Global variables.
authored
434 return comment('NOOP')
bb16c1a Stephen Roller Move stuff around.
authored
435
426bf87 Stephen Roller Add support for comments. Kinda makes things a little grosser.
authored
436 code5 = []
a1fa834 Stephen Roller Support adding two values.
authored
437 if ast.node_type == 'operator':
438 cb = callbacks.get(ast.value, noop)
439 else:
440 cb = callbacks.get(ast.node_type, noop)
7b1b19d Stephen Roller Move code around for organization.
authored
441
a1fa834 Stephen Roller Support adding two values.
authored
442 # code 5 because callbacks return 5-tuples.
443 setattr(ast, 'code5', cb(ast))
444 return ast.code5
445
7b1b19d Stephen Roller Move code around for organization.
authored
446 # STRING OUTPUT ------------------------------------------------------------
447
448 def code5str(code5):
449 """Converts from code5 to something actually usuable by TM."""
450 from itertools import count
451 output = []
452 linecounter = count()
453 for inst5 in code5:
454 inst, r, s, t, com = inst5
455 if inst in ('LDC', 'LDA', 'LD', 'ST', 'JLT', 'JLE', 'JEQ',
456 'JNE', 'JGE', 'JGT'):
457 ln = linecounter.next() # line number
fd35b5b Stephen Roller Make sure formatting lines up.
authored
458 output.append("%5d: %-9s %d,%2d(%d)\t\t%s" % (ln, inst, r, s, t, com))
7b1b19d Stephen Roller Move code around for organization.
authored
459 elif inst in ('HALT', 'IN', 'OUT', 'INB', 'OUTB', 'OUTC',
460 'ADD', 'SUB', 'MUL', 'DIV', 'OUTNL'):
461 ln = linecounter.next()
fd35b5b Stephen Roller Make sure formatting lines up.
authored
462 output.append("%5d: %-9s %d,%2d,%2d\t\t%s" % (ln, inst, r, s, t, com))
d2e01fb Stephen Roller Global variables.
authored
463 elif inst == 'alloc':
464 size = r
465 for i in xrange(0, size):
466 ln = linecounter.next()
7b1b19d Stephen Roller Move code around for organization.
authored
467 elif inst == 'comment':
468 output.append("* %s" % com)
469 else:
470 raise ValueError("Can't print this instruction: %s" % inst)
471
472 return "\n".join(output)
473
a1fa834 Stephen Roller Support adding two values.
authored
474 def generate_code_str(ast):
8522067 Stephen Roller Poorly handle binary operators. Add stack pointer preamble.
authored
475 """Shorthand for creating the TM string code for the ast."""
a1fa834 Stephen Roller Support adding two values.
authored
476 return code5str(generate_code(ast))
ae5ad92 Stephen Roller Rudimentary code generator.
authored
477
7b1b19d Stephen Roller Move code around for organization.
authored
478 # ---------------------------------------------------------------------------
479
ae5ad92 Stephen Roller Rudimentary code generator.
authored
480 if __name__ == '__main__':
481 from ice9 import compile
482 source = file('test.9').read()
483 print compile(source)
Something went wrong with that request. Please try again.