Fix bug found in project 04
This commit is contained in:
175
Project-02-03-04/compiler.py
Normal file
175
Project-02-03-04/compiler.py
Normal file
@@ -0,0 +1,175 @@
|
||||
import syntax
|
||||
from vistram.tram import *
|
||||
|
||||
label_counter = 0
|
||||
|
||||
def new_label():
|
||||
global label_counter
|
||||
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, 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)
|
||||
|
||||
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)
|
||||
|
||||
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)
|
||||
|
||||
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):
|
||||
c1 = self.arg1.code(rho, nl)
|
||||
c2 = self.arg2.code(rho, nl)
|
||||
|
||||
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, 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)]
|
||||
|
||||
# Rule K11
|
||||
class WHILE(syntax.WHILE):
|
||||
def code(self, rho, nl):
|
||||
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()
|
||||
|
||||
# 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):
|
||||
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]
|
||||
nested_rho = dict(rho)
|
||||
for i, p in enumerate(self.params):
|
||||
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, nl_def = rho[self.f_name]
|
||||
return c + [invoke(len(self.arg), l, nl - nl_def)]
|
||||
Reference in New Issue
Block a user