-
Notifications
You must be signed in to change notification settings - Fork 6
/
transasm.py
77 lines (73 loc) · 4.17 KB
/
transasm.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
from syntree import *
from analyzer import LabelFactory
from transasm_recipe import templates
def transasm(n):
strings = ''.join([templates['ascii'].format(**locals()) for label,string in n.deco['strings']])
display_size = n.deco['scope_cnt']*4
offset = n.deco['scope']*4
main = n.deco['label']
varsize = len(n.var)*4
functions = fun(n)
return templates['program'].format(**locals())
def fun(n):
label = n.deco['label']
nested = ''.join([ fun(f) for f in n.fun ])
body = ''.join([stat(s) for s in n.body])
return f'{label}:\n{body}\n\tret\n{nested}\n'
def stat(n):
match n:
case Print():
newline = templates['print_linebreak'] if n.newline else ''
match n.expr.deco['type']:
case Type.INT:
return templates['print_int'].format(expr = expr(n.expr), newline = newline)
case Type.BOOL:
return templates['print_bool'].format(expr = expr(n.expr), newline = newline)
case Type.STRING:
return templates['print_string'].format(label = n.expr.deco['label'], newline = newline)
case other: raise Exception('Unknown expression type', n.expr)
case Return():
return (expr(n.expr) if n.expr is not None and n.expr.deco['type'] != Type.VOID else '') + '\tret\n'
case Assign():
return templates['assign'].format(expression = expr(n.expr),
scope = n.deco['scope']*4,
variable = n.deco['offset']*4)
case FunCall(): return expr(n)
case While():
return templates['while'].format(condition = expr(n.expr),
label1 = LabelFactory.new_label(),
label2 = LabelFactory.new_label(),
body = ''.join([stat(s) for s in n.body]))
case IfThenElse():
return templates['ifthenelse'].format(condition = expr(n.expr),
label1 = LabelFactory.new_label(),
label2 = LabelFactory.new_label(),
ibody = ''.join([stat(s) for s in n.ibody]),
ebody = ''.join([stat(s) for s in n.ebody]))
case other: raise Exception('Unknown statement type', n)
def expr(n): # convention: all expressions save their results to eax
match n:
case ArithOp() | LogicOp():
args = expr(n.left) + '\tpushl %eax\n' + expr(n.right) + '\tmovl %eax, %ebx\n\tpopl %eax\n'
pyeq1 = {'+':'addl', '-':'subl', '*':'imull', '||':'orl', '&&':'andl'}
pyeq2 = {'<=':'jle', '<':'jl', '>=':'jge', '>':'jg', '==':'je', '!=':'jne'}
if n.op in pyeq1:
return args + f'\t{pyeq1[n.op]} %ebx, %eax\n'
elif n.op in pyeq2:
return args + f'\tcmp %ebx, %eax\n\tmovl $1, %eax\n\t{pyeq2[n.op]} 1f\n\txorl %eax, %eax\n1:\n'
elif n.op=='/':
return args + '\tcdq\n\tidivl %ebx, %eax\n'
elif n.op=='%':
return args + '\tcdq\n\tidivl %ebx, %eax\n\tmovl %edx, %eax\n'
raise Exception('Unknown binary operation')
case Integer() | Boolean():
return f'\tmovl ${int(n.value)}, %eax\n'
case Var():
return templates['var'].format(scope = n.deco['scope']*4, variable = n.deco['offset']*4)
case FunCall():
return templates['funcall'].format(allocargs = ''.join(['%s\tpushl %%eax\n' % expr(a) for a in n.args]),
varsize = len(n.deco['fundeco']['local'])*4,
disphead = len(n.deco['fundeco']['local'])*4 + len(n.args)*4 - 4,
scope = n.deco['fundeco']['scope']*4,
funlabel = n.deco['fundeco']['label'])
case other: raise Exception('Unknown expression type', n)