Finish compiler refactoring

This commit is contained in:
Jan-Niclas Loosen
2025-12-11 01:09:28 +01:00
parent b3e20a52eb
commit 5ce2c5a281
4 changed files with 137 additions and 113 deletions

View File

@@ -8,163 +8,168 @@ def new_label():
label_counter += 1
return Label(text=f"L{label_counter}")
# Rules E1, E2
def elab_def(decls, rho, nl):
r = dict(rho)
for d in decls:
r = d.elab(r, nl)
return r
# Rule K6
class CONST(syntax.CONST):
def code(self, rho, nl):
return [const(self.value)]
# Rule K3
class ID(syntax.ID):
def code(self, rho, nl):
k, nlp = rho[self.name]
return [load(k, nl - nlp)]
k, nl_def = rho[self.name]
return [load(k, nl - nl_def)]
# Rule K7
class AOP(syntax.AOP):
def code(self, rho, nl):
c1 = self.arg1.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):
def code(self, rho, nl):
c1 = self.arg1.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):
def code(self, rho, nl):
c1 = self.arg1.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):
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)
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):
def code(self, rho, nl):
c = self.expr.code(rho, nl)
k, nlp = rho[self.var.name]
d = nl - nlp
return c + [store(k, d), load(k, d)]
k, nl_def = rho[self.var.name]
dif = nl - nl_def
return c + [store(k, dif), load(k, dif)]
# Rule K9
class SEQ(syntax.SEQ):
def code(self, rho, nl):
c1 = self.exp1.code(rho, nl)
c2 = self.exp2.code(rho, nl)
return c1 + [pop()] + c2
# Rule K10
class IF(syntax.IF):
def code(self, rho, nl):
l1 = new_label()
l2 = new_label()
c1 = self.cond.code(rho, nl)
c2 = self.exp1.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):
def code(self, rho, nl):
l1 = new_label() # loop header
l2 = new_label() # exit
l3 = new_label() # repeat
l4 = new_label() # evaluate body
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)]
)
l1 = new_label()
l2 = new_label()
l3 = new_label()
l4 = new_label()
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):
def code(self, rho, nl):
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):
def elab(self, rho, nl):
r = dict(rho)
r[self.f_name] = (new_label(), nl)
return r
nested_rho = dict(rho)
nested_rho[self.f_name] = (new_label(), nl)
return nested_rho
def code(self, rho, nl):
l, _ = rho[self.f_name]
rho2 = dict(rho)
nested_rho = dict(rho)
for i, p in enumerate(self.params):
rho2[p] = (i, nl + 1)
return (
[nop(assigned_label=l)]
+ self.body.code(rho2, nl + 1)
+ [ireturn()]
)
nested_rho[p] = (i, nl + 1)
c = self.body.code(nested_rho, nl + 1)
return [nop(assigned_label=l)] + c + [ireturn()]
# Rule K12
class CALL(syntax.CALL):
def code(self, rho, nl):
c = []
for a in self.arg:
c += a.code(rho, nl)
l, nlp = rho[self.f_name]
return c + [invoke(len(self.arg), l, nl - nlp)]
l, nl_def = rho[self.f_name]
return c + [invoke(len(self.arg), l, nl - nl_def)]

View 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

View File

@@ -1,47 +1,47 @@
GOTO L1
L2: NOP
GOTO L13
L14: NOP
LOAD 0 0
CONST 0
EQ
IFZERO L4
GOTO L6
L7: NOP
IFZERO L16
GOTO L18
L19: NOP
LOAD 0 0
LOAD 1 1
MUL
LOAD 1 0
ADD
RETURN
L6: NOP
L18: NOP
CONST 2
LOAD 1 0
MUL
LOAD 0 0
INVOKE 2 L7 0
GOTO L5
L4: NOP
INVOKE 2 L19 0
GOTO L17
L16: NOP
LOAD 0 0
CONST 1
ADD
L5: NOP
L17: NOP
RETURN
L3: NOP
L15: NOP
LOAD 1 0
CONST 0
GT
IFZERO L9
GOTO L11
L8: NOP
IFZERO L22
GOTO L23
L20: NOP
LOAD 1 0
CONST 0
GT
IFZERO L10
IFZERO L21
POP
L11: NOP
L23: NOP
LOAD 0 0
LOAD 0 0
LOAD 1 0
INVOKE 2 L2 1
INVOKE 2 L14 1
MUL
STORE 0 0
LOAD 0 0
@@ -51,21 +51,21 @@ L11: NOP
SUB
STORE 1 0
LOAD 1 0
GOTO L8
L9: NOP
GOTO L20
L22: NOP
CONST None
L10: NOP
L21: NOP
POP
LOAD 0 0
CONST 42
ADD
RETURN
L1: NOP
L13: NOP
CONST 1
CONST 2
INVOKE 2 L2 0
INVOKE 2 L14 0
POP
CONST 3
CONST 3
INVOKE 2 L3 0
INVOKE 2 L15 0
HALT

View File

@@ -0,0 +1 @@
if 1 >= 0 then 1 else 0