Wire offline message
This commit is contained in:
@@ -9,6 +9,13 @@ import compiler
|
||||
import syntax
|
||||
|
||||
|
||||
# -------------------------------------------------
|
||||
# Global function environment
|
||||
# -------------------------------------------------
|
||||
|
||||
FUNCTIONS = {} # name -> (func_start, func_end)
|
||||
|
||||
|
||||
# -------------------------------------------------
|
||||
# Expressions — NO CFG NODES
|
||||
# -------------------------------------------------
|
||||
@@ -64,13 +71,21 @@ class SEQ(compiler.SEQ):
|
||||
|
||||
class IF(compiler.IF):
|
||||
def cfa(self, pred, end):
|
||||
cond = CFG_DIAMOND(self)
|
||||
# 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(cond, end)
|
||||
else_end = self.exp2.cfa(cond, end)
|
||||
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)
|
||||
@@ -82,13 +97,19 @@ class IF(compiler.IF):
|
||||
|
||||
class WHILE(compiler.WHILE):
|
||||
def cfa(self, pred, end):
|
||||
cond = CFG_DIAMOND(self)
|
||||
# loop condition
|
||||
cond = CFG_DIAMOND(self.cond)
|
||||
pred.add_child(cond)
|
||||
|
||||
body_end = self.body.cfa(cond, end)
|
||||
if body_end is not None:
|
||||
body_end.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)
|
||||
|
||||
@@ -96,21 +117,47 @@ class WHILE(compiler.WHILE):
|
||||
|
||||
|
||||
# -------------------------------------------------
|
||||
# Functions / calls
|
||||
# Functions / calls (interprocedural CFG)
|
||||
# -------------------------------------------------
|
||||
|
||||
class CALL(compiler.CALL):
|
||||
def cfa(self, pred, end):
|
||||
n = CFG_CALL(self)
|
||||
pred.add_child(n)
|
||||
return n
|
||||
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):
|
||||
entry = CFG_Node(self)
|
||||
pred.add_child(entry)
|
||||
return self.body.cfa(entry, 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):
|
||||
@@ -130,5 +177,5 @@ class RETURN(syntax.EXPRESSION):
|
||||
def cfa(self, pred, end):
|
||||
n = CFG_RETURN(self)
|
||||
pred.add_child(n)
|
||||
n.add_child(end) # direct jump to global END
|
||||
n.add_child(end) # return to function exit
|
||||
return None # no fallthrough
|
||||
|
||||
Reference in New Issue
Block a user