Finish compiler refactoring
This commit is contained in:
@@ -8,163 +8,168 @@ def new_label():
|
|||||||
label_counter += 1
|
label_counter += 1
|
||||||
return Label(text=f"L{label_counter}")
|
return Label(text=f"L{label_counter}")
|
||||||
|
|
||||||
|
# Rules E1, E2
|
||||||
def elab_def(decls, rho, nl):
|
def elab_def(decls, rho, nl):
|
||||||
r = dict(rho)
|
r = dict(rho)
|
||||||
for d in decls:
|
for d in decls:
|
||||||
r = d.elab(r, nl)
|
r = d.elab(r, nl)
|
||||||
return r
|
return r
|
||||||
|
|
||||||
|
# Rule K6
|
||||||
class CONST(syntax.CONST):
|
class CONST(syntax.CONST):
|
||||||
def code(self, rho, nl):
|
def code(self, rho, nl):
|
||||||
return [const(self.value)]
|
return [const(self.value)]
|
||||||
|
|
||||||
|
# Rule K3
|
||||||
class ID(syntax.ID):
|
class ID(syntax.ID):
|
||||||
def code(self, rho, nl):
|
def code(self, rho, nl):
|
||||||
k, nlp = rho[self.name]
|
k, nl_def = rho[self.name]
|
||||||
return [load(k, nl - nlp)]
|
return [load(k, nl - nl_def)]
|
||||||
|
|
||||||
|
# Rule K7
|
||||||
class AOP(syntax.AOP):
|
class AOP(syntax.AOP):
|
||||||
def code(self, rho, nl):
|
def code(self, rho, nl):
|
||||||
c1 = self.arg1.code(rho, nl)
|
c1 = self.arg1.code(rho, nl)
|
||||||
c2 = self.arg2.code(rho, nl)
|
c2 = self.arg2.code(rho, nl)
|
||||||
op = self.operator
|
|
||||||
if op == "+":
|
|
||||||
return c1 + c2 + [add()]
|
|
||||||
if op == "-":
|
|
||||||
return c1 + c2 + [sub()]
|
|
||||||
if op == "*":
|
|
||||||
return c1 + c2 + [mul()]
|
|
||||||
return c1 + c2 + [div()]
|
|
||||||
|
|
||||||
|
match self.operator:
|
||||||
|
case "+":
|
||||||
|
return c1 + c2 + [add()]
|
||||||
|
case "-":
|
||||||
|
return c1 + c2 + [sub()]
|
||||||
|
case "*":
|
||||||
|
return c1 + c2 + [mul()]
|
||||||
|
case "/":
|
||||||
|
return c1 + c2 + [div()]
|
||||||
|
case _:
|
||||||
|
raise Exception(f"Unknown AOP operator.")
|
||||||
|
|
||||||
|
# Rule K5
|
||||||
class COMP(syntax.COMP):
|
class COMP(syntax.COMP):
|
||||||
def code(self, rho, nl):
|
def code(self, rho, nl):
|
||||||
c1 = self.arg1.code(rho, nl)
|
c1 = self.arg1.code(rho, nl)
|
||||||
c2 = self.arg2.code(rho, nl)
|
c2 = self.arg2.code(rho, nl)
|
||||||
if self.operator == "<":
|
|
||||||
return c1 + c2 + [lt()]
|
|
||||||
if self.operator == ">":
|
|
||||||
return c1 + c2 + [gt()]
|
|
||||||
if self.operator == "<=":
|
|
||||||
return c1 + c2 + [gt(), nop()] # NOT IMPLEMENTED IN TRAM
|
|
||||||
if self.operator == ">=":
|
|
||||||
return c1 + c2 + [lt(), nop()] # NOT IMPLEMENTED IN TRAM
|
|
||||||
return c1 + c2
|
|
||||||
|
|
||||||
|
match self.operator:
|
||||||
|
case "<":
|
||||||
|
return c1 + c2 + [lt()]
|
||||||
|
case ">":
|
||||||
|
return c1 + c2 + [gt()]
|
||||||
|
case "<=":
|
||||||
|
# leq is not implemented in vistra.tram
|
||||||
|
return LOP("||", COMP("<", self.arg1, self.arg2), EQOP("==", self.arg1, self.arg2)).code(rho, nl)
|
||||||
|
case ">=":
|
||||||
|
# geq is not implemented in vistra.tram
|
||||||
|
return LOP("||", COMP(">", self.arg1, self.arg2), EQOP("==", self.arg1, self.arg2)).code(rho, nl)
|
||||||
|
case _:
|
||||||
|
raise ValueError(f"Unknown COMP operator.")
|
||||||
|
|
||||||
|
# Rule K5
|
||||||
class EQOP(syntax.EQOP):
|
class EQOP(syntax.EQOP):
|
||||||
def code(self, rho, nl):
|
def code(self, rho, nl):
|
||||||
c1 = self.arg1.code(rho, nl)
|
c1 = self.arg1.code(rho, nl)
|
||||||
c2 = self.arg2.code(rho, nl)
|
c2 = self.arg2.code(rho, nl)
|
||||||
if self.operator == "==":
|
|
||||||
return c1 + c2 + [eq()]
|
|
||||||
return c1 + c2 + [neq()]
|
|
||||||
|
|
||||||
|
match self.operator:
|
||||||
|
case "==":
|
||||||
|
return c1 + c2 + [eq()]
|
||||||
|
case "!=":
|
||||||
|
return c1 + c2 + [neq()]
|
||||||
|
case _:
|
||||||
|
raise ValueError(f"Unknown EQOP operator.")
|
||||||
|
|
||||||
|
# see lecture code generation AND/OR
|
||||||
class LOP(syntax.LOP):
|
class LOP(syntax.LOP):
|
||||||
def code(self, rho, nl):
|
def code(self, rho, nl):
|
||||||
# TRIPLA: logical operators must be done by short-circuiting (not strict)
|
|
||||||
# but your TRAM has no boolean ops, so fallback to == and pop
|
|
||||||
c1 = self.arg1.code(rho, nl)
|
c1 = self.arg1.code(rho, nl)
|
||||||
c2 = self.arg2.code(rho, nl)
|
c2 = self.arg2.code(rho, nl)
|
||||||
if self.operator == "&&":
|
|
||||||
l = new_label()
|
|
||||||
return (
|
|
||||||
c1 +
|
|
||||||
[ifzero(l)] +
|
|
||||||
c2 +
|
|
||||||
[ifzero(l)] +
|
|
||||||
[const(1)] +
|
|
||||||
[nop(assigned_label=l)]
|
|
||||||
)
|
|
||||||
if self.operator == "||":
|
|
||||||
l = new_label()
|
|
||||||
return (
|
|
||||||
c1 +
|
|
||||||
[ifzero(l)] +
|
|
||||||
[const(1)] +
|
|
||||||
[goto(l)] +
|
|
||||||
[nop(assigned_label=l)] +
|
|
||||||
c2
|
|
||||||
)
|
|
||||||
return c1 + c2
|
|
||||||
|
|
||||||
|
l1 = new_label()
|
||||||
|
l2 = new_label()
|
||||||
|
match self.operator:
|
||||||
|
case "&&":
|
||||||
|
return c1 + [ifzero(l1)] + [const(1)] + c2 + [mul()] + [goto(l2)] + [nop(l1)] + [const(0)] + [nop(l2)]
|
||||||
|
case "||":
|
||||||
|
return c1 + [ifzero(l1)] + [const(1)] + [goto(l2)] + [nop(l1)] + c2 + [nop(l2)]
|
||||||
|
case _:
|
||||||
|
raise ValueError("Unknown LOP operator.")
|
||||||
|
|
||||||
|
# Rule K4
|
||||||
class ASSIGN(syntax.ASSIGN):
|
class ASSIGN(syntax.ASSIGN):
|
||||||
def code(self, rho, nl):
|
def code(self, rho, nl):
|
||||||
c = self.expr.code(rho, nl)
|
c = self.expr.code(rho, nl)
|
||||||
k, nlp = rho[self.var.name]
|
k, nl_def = rho[self.var.name]
|
||||||
d = nl - nlp
|
dif = nl - nl_def
|
||||||
return c + [store(k, d), load(k, d)]
|
return c + [store(k, dif), load(k, dif)]
|
||||||
|
|
||||||
|
# Rule K9
|
||||||
class SEQ(syntax.SEQ):
|
class SEQ(syntax.SEQ):
|
||||||
def code(self, rho, nl):
|
def code(self, rho, nl):
|
||||||
c1 = self.exp1.code(rho, nl)
|
c1 = self.exp1.code(rho, nl)
|
||||||
c2 = self.exp2.code(rho, nl)
|
c2 = self.exp2.code(rho, nl)
|
||||||
return c1 + [pop()] + c2
|
return c1 + [pop()] + c2
|
||||||
|
|
||||||
|
# Rule K10
|
||||||
class IF(syntax.IF):
|
class IF(syntax.IF):
|
||||||
def code(self, rho, nl):
|
def code(self, rho, nl):
|
||||||
l1 = new_label()
|
l1 = new_label()
|
||||||
l2 = new_label()
|
l2 = new_label()
|
||||||
|
|
||||||
c1 = self.cond.code(rho, nl)
|
c1 = self.cond.code(rho, nl)
|
||||||
c2 = self.exp1.code(rho, nl)
|
c2 = self.exp1.code(rho, nl)
|
||||||
c3 = self.exp2.code(rho, nl)
|
c3 = self.exp2.code(rho, nl)
|
||||||
return (
|
|
||||||
c1 +
|
|
||||||
[ifzero(l1)] +
|
|
||||||
c2 +
|
|
||||||
[goto(l2)] +
|
|
||||||
[nop(assigned_label=l1)] +
|
|
||||||
c3 +
|
|
||||||
[nop(assigned_label=l2)]
|
|
||||||
)
|
|
||||||
|
|
||||||
|
return c1 + [ifzero(l1)] + c2 + [goto(l2)] + [nop(assigned_label=l1)] + c3 + [nop(assigned_label=l2)]
|
||||||
|
|
||||||
|
# Rule K11
|
||||||
class WHILE(syntax.WHILE):
|
class WHILE(syntax.WHILE):
|
||||||
def code(self, rho, nl):
|
def code(self, rho, nl):
|
||||||
l1 = new_label() # loop header
|
l1 = new_label()
|
||||||
l2 = new_label() # exit
|
l2 = new_label()
|
||||||
l3 = new_label() # repeat
|
l3 = new_label()
|
||||||
l4 = new_label() # evaluate body
|
l4 = new_label()
|
||||||
return (
|
|
||||||
self.cond.code(rho, nl)
|
|
||||||
+ [ifzero(l2), goto(l4)]
|
|
||||||
+ [nop(assigned_label=l1)]
|
|
||||||
+ self.cond.code(rho, nl)
|
|
||||||
+ [ifzero(l3), pop()]
|
|
||||||
+ [nop(assigned_label=l4)]
|
|
||||||
+ self.body.code(rho, nl)
|
|
||||||
+ [goto(l1)]
|
|
||||||
+ [nop(assigned_label=l2), const(None), nop(assigned_label=l3)]
|
|
||||||
)
|
|
||||||
|
|
||||||
|
c1 = self.cond.code(rho, nl)
|
||||||
|
c2 = self.body.code(rho, nl)
|
||||||
|
|
||||||
|
return c1 + [ifzero(l3), goto(l4)] + [nop(l1)] + c1 + [ifzero(l2), pop()] + [nop(l4)] + c2 + [goto(l1)] + [nop(l3), const(None), nop(l2)]
|
||||||
|
|
||||||
|
# Rule K2
|
||||||
class LET(syntax.LET):
|
class LET(syntax.LET):
|
||||||
def code(self, rho, nl):
|
def code(self, rho, nl):
|
||||||
l = new_label()
|
l = new_label()
|
||||||
rho2 = elab_def(self.decl, rho, nl)
|
|
||||||
cd = []
|
|
||||||
for d in self.decl:
|
|
||||||
cd += d.code(rho2, nl)
|
|
||||||
ce = self.body.code(rho2, nl)
|
|
||||||
return [goto(l)] + cd + [nop(assigned_label=l)] + ce
|
|
||||||
|
|
||||||
|
# Normalize to list
|
||||||
|
decls = self.decl if isinstance(self.decl, list) else [self.decl]
|
||||||
|
|
||||||
|
shared_rho = elab_def(decls, rho, nl)
|
||||||
|
ds = []
|
||||||
|
for d in decls:
|
||||||
|
ds += d.code(shared_rho, nl)
|
||||||
|
|
||||||
|
es = self.body.code(shared_rho, nl)
|
||||||
|
return [goto(l)] + ds + [nop(assigned_label=l)] + es
|
||||||
|
|
||||||
|
# Rule K13
|
||||||
class DECL(syntax.DECL):
|
class DECL(syntax.DECL):
|
||||||
def elab(self, rho, nl):
|
def elab(self, rho, nl):
|
||||||
r = dict(rho)
|
nested_rho = dict(rho)
|
||||||
r[self.f_name] = (new_label(), nl)
|
nested_rho[self.f_name] = (new_label(), nl)
|
||||||
return r
|
return nested_rho
|
||||||
|
|
||||||
def code(self, rho, nl):
|
def code(self, rho, nl):
|
||||||
l, _ = rho[self.f_name]
|
l, _ = rho[self.f_name]
|
||||||
rho2 = dict(rho)
|
nested_rho = dict(rho)
|
||||||
for i, p in enumerate(self.params):
|
for i, p in enumerate(self.params):
|
||||||
rho2[p] = (i, nl + 1)
|
nested_rho[p] = (i, nl + 1)
|
||||||
return (
|
c = self.body.code(nested_rho, nl + 1)
|
||||||
[nop(assigned_label=l)]
|
return [nop(assigned_label=l)] + c + [ireturn()]
|
||||||
+ self.body.code(rho2, nl + 1)
|
|
||||||
+ [ireturn()]
|
|
||||||
)
|
|
||||||
|
|
||||||
|
# Rule K12
|
||||||
class CALL(syntax.CALL):
|
class CALL(syntax.CALL):
|
||||||
def code(self, rho, nl):
|
def code(self, rho, nl):
|
||||||
c = []
|
c = []
|
||||||
for a in self.arg:
|
for a in self.arg:
|
||||||
c += a.code(rho, nl)
|
c += a.code(rho, nl)
|
||||||
l, nlp = rho[self.f_name]
|
l, nl_def = rho[self.f_name]
|
||||||
return c + [invoke(len(self.arg), l, nl - nlp)]
|
return c + [invoke(len(self.arg), l, nl - nl_def)]
|
||||||
|
|||||||
18
Project-02-03/tramcodes/geq.tram
Normal file
18
Project-02-03/tramcodes/geq.tram
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
CONST 1
|
||||||
|
CONST 0
|
||||||
|
GT
|
||||||
|
IFZERO L3
|
||||||
|
CONST 1
|
||||||
|
GOTO L4
|
||||||
|
L3: NOP
|
||||||
|
CONST 1
|
||||||
|
CONST 0
|
||||||
|
EQ
|
||||||
|
L4: NOP
|
||||||
|
IFZERO L1
|
||||||
|
CONST 1
|
||||||
|
GOTO L2
|
||||||
|
L1: NOP
|
||||||
|
CONST 0
|
||||||
|
L2: NOP
|
||||||
|
HALT
|
||||||
@@ -1,47 +1,47 @@
|
|||||||
GOTO L1
|
GOTO L13
|
||||||
L2: NOP
|
L14: NOP
|
||||||
LOAD 0 0
|
LOAD 0 0
|
||||||
CONST 0
|
CONST 0
|
||||||
EQ
|
EQ
|
||||||
IFZERO L4
|
IFZERO L16
|
||||||
GOTO L6
|
GOTO L18
|
||||||
L7: NOP
|
L19: NOP
|
||||||
LOAD 0 0
|
LOAD 0 0
|
||||||
LOAD 1 1
|
LOAD 1 1
|
||||||
MUL
|
MUL
|
||||||
LOAD 1 0
|
LOAD 1 0
|
||||||
ADD
|
ADD
|
||||||
RETURN
|
RETURN
|
||||||
L6: NOP
|
L18: NOP
|
||||||
CONST 2
|
CONST 2
|
||||||
LOAD 1 0
|
LOAD 1 0
|
||||||
MUL
|
MUL
|
||||||
LOAD 0 0
|
LOAD 0 0
|
||||||
INVOKE 2 L7 0
|
INVOKE 2 L19 0
|
||||||
GOTO L5
|
GOTO L17
|
||||||
L4: NOP
|
L16: NOP
|
||||||
LOAD 0 0
|
LOAD 0 0
|
||||||
CONST 1
|
CONST 1
|
||||||
ADD
|
ADD
|
||||||
L5: NOP
|
L17: NOP
|
||||||
RETURN
|
RETURN
|
||||||
L3: NOP
|
L15: NOP
|
||||||
LOAD 1 0
|
LOAD 1 0
|
||||||
CONST 0
|
CONST 0
|
||||||
GT
|
GT
|
||||||
IFZERO L9
|
IFZERO L22
|
||||||
GOTO L11
|
GOTO L23
|
||||||
L8: NOP
|
L20: NOP
|
||||||
LOAD 1 0
|
LOAD 1 0
|
||||||
CONST 0
|
CONST 0
|
||||||
GT
|
GT
|
||||||
IFZERO L10
|
IFZERO L21
|
||||||
POP
|
POP
|
||||||
L11: NOP
|
L23: NOP
|
||||||
LOAD 0 0
|
LOAD 0 0
|
||||||
LOAD 0 0
|
LOAD 0 0
|
||||||
LOAD 1 0
|
LOAD 1 0
|
||||||
INVOKE 2 L2 1
|
INVOKE 2 L14 1
|
||||||
MUL
|
MUL
|
||||||
STORE 0 0
|
STORE 0 0
|
||||||
LOAD 0 0
|
LOAD 0 0
|
||||||
@@ -51,21 +51,21 @@ L11: NOP
|
|||||||
SUB
|
SUB
|
||||||
STORE 1 0
|
STORE 1 0
|
||||||
LOAD 1 0
|
LOAD 1 0
|
||||||
GOTO L8
|
GOTO L20
|
||||||
L9: NOP
|
L22: NOP
|
||||||
CONST None
|
CONST None
|
||||||
L10: NOP
|
L21: NOP
|
||||||
POP
|
POP
|
||||||
LOAD 0 0
|
LOAD 0 0
|
||||||
CONST 42
|
CONST 42
|
||||||
ADD
|
ADD
|
||||||
RETURN
|
RETURN
|
||||||
L1: NOP
|
L13: NOP
|
||||||
CONST 1
|
CONST 1
|
||||||
CONST 2
|
CONST 2
|
||||||
INVOKE 2 L2 0
|
INVOKE 2 L14 0
|
||||||
POP
|
POP
|
||||||
CONST 3
|
CONST 3
|
||||||
CONST 3
|
CONST 3
|
||||||
INVOKE 2 L3 0
|
INVOKE 2 L15 0
|
||||||
HALT
|
HALT
|
||||||
|
|||||||
1
Project-02-03/triplaprograms/geq.tripla
Normal file
1
Project-02-03/triplaprograms/geq.tripla
Normal file
@@ -0,0 +1 @@
|
|||||||
|
if 1 >= 0 then 1 else 0
|
||||||
Reference in New Issue
Block a user