182 lines
4.0 KiB
Python
182 lines
4.0 KiB
Python
from cfg.CFG_Node import (
|
|
CFG_Node,
|
|
CFG_CALL,
|
|
CFG_RETURN,
|
|
CFG_DIAMOND,
|
|
)
|
|
|
|
import compiler
|
|
import syntax
|
|
|
|
|
|
# -------------------------------------------------
|
|
# Global function environment
|
|
# -------------------------------------------------
|
|
|
|
FUNCTIONS = {} # name -> (func_start, func_end)
|
|
|
|
|
|
# -------------------------------------------------
|
|
# Expressions — NO CFG NODES
|
|
# -------------------------------------------------
|
|
|
|
class CONST(compiler.CONST):
|
|
def cfa(self, pred, end):
|
|
return pred
|
|
|
|
|
|
class ID(compiler.ID):
|
|
def cfa(self, pred, end):
|
|
return pred
|
|
|
|
|
|
class AOP(compiler.AOP):
|
|
def cfa(self, pred, end):
|
|
return pred
|
|
|
|
|
|
class COMP(compiler.COMP):
|
|
def cfa(self, pred, end):
|
|
return pred
|
|
|
|
|
|
class EQOP(compiler.EQOP):
|
|
def cfa(self, pred, end):
|
|
return pred
|
|
|
|
|
|
class LOP(compiler.LOP):
|
|
def cfa(self, pred, end):
|
|
return pred
|
|
|
|
|
|
# -------------------------------------------------
|
|
# Statements
|
|
# -------------------------------------------------
|
|
|
|
class ASSIGN(compiler.ASSIGN):
|
|
def cfa(self, pred, end):
|
|
n = CFG_Node(self)
|
|
pred.add_child(n)
|
|
return n
|
|
|
|
|
|
class SEQ(compiler.SEQ):
|
|
def cfa(self, pred, end):
|
|
mid = self.exp1.cfa(pred, end)
|
|
if mid is None:
|
|
return None
|
|
return self.exp2.cfa(mid, end)
|
|
|
|
|
|
class IF(compiler.IF):
|
|
def cfa(self, pred, end):
|
|
# decision node (condition only)
|
|
cond = CFG_DIAMOND(self.cond)
|
|
pred.add_child(cond)
|
|
|
|
# explicit branch entries
|
|
then_entry = CFG_Node()
|
|
else_entry = CFG_Node()
|
|
cond.add_child(then_entry)
|
|
cond.add_child(else_entry)
|
|
|
|
# join node
|
|
join = CFG_Node()
|
|
|
|
then_end = self.exp1.cfa(then_entry, end)
|
|
else_end = self.exp2.cfa(else_entry, end)
|
|
|
|
if then_end is not None:
|
|
then_end.add_child(join)
|
|
if else_end is not None:
|
|
else_end.add_child(join)
|
|
|
|
return join
|
|
|
|
|
|
class WHILE(compiler.WHILE):
|
|
def cfa(self, pred, end):
|
|
# loop condition
|
|
cond = CFG_DIAMOND(self.cond)
|
|
pred.add_child(cond)
|
|
|
|
# body entry
|
|
body_entry = CFG_Node()
|
|
cond.add_child(body_entry)
|
|
|
|
body_end = self.body.cfa(body_entry, end)
|
|
if body_end is not None:
|
|
body_end.add_child(cond) # back-edge
|
|
|
|
# loop exit
|
|
after = CFG_Node()
|
|
cond.add_child(after)
|
|
|
|
return after
|
|
|
|
|
|
# -------------------------------------------------
|
|
# Functions / calls (interprocedural CFG)
|
|
# -------------------------------------------------
|
|
|
|
class CALL(compiler.CALL):
|
|
def cfa(self, pred, end):
|
|
call = CFG_CALL(self)
|
|
pred.add_child(call)
|
|
|
|
# continuation after return
|
|
cont = CFG_Node()
|
|
|
|
if self.f_name not in FUNCTIONS:
|
|
raise RuntimeError(f"Call to undefined function '{self.f_name}'")
|
|
|
|
f_start, f_end = FUNCTIONS[self.f_name]
|
|
|
|
# call → function entry
|
|
call.add_child(f_start)
|
|
|
|
# function exit → continuation
|
|
f_end.add_child(cont)
|
|
|
|
return cont
|
|
|
|
|
|
class DECL(compiler.DECL):
|
|
def cfa(self, pred, end):
|
|
# function entry / exit
|
|
f_start = CFG_Node(self)
|
|
f_end = CFG_Node(self)
|
|
|
|
# register function
|
|
FUNCTIONS[self.f_name] = (f_start, f_end)
|
|
|
|
# build function body
|
|
body_end = self.body.cfa(f_start, f_end)
|
|
if body_end is not None:
|
|
body_end.add_child(f_end)
|
|
|
|
# function declaration does not alter current control flow
|
|
return pred
|
|
|
|
|
|
class LET(compiler.LET):
|
|
def cfa(self, pred, end):
|
|
current = pred
|
|
|
|
decls = self.decl if isinstance(self.decl, list) else [self.decl]
|
|
for d in decls:
|
|
current = d.cfa(current, end)
|
|
if current is None:
|
|
return None
|
|
|
|
return self.body.cfa(current, end)
|
|
|
|
|
|
class RETURN(syntax.EXPRESSION):
|
|
def cfa(self, pred, end):
|
|
n = CFG_RETURN(self)
|
|
pred.add_child(n)
|
|
n.add_child(end) # return to function exit
|
|
return None # no fallthrough
|