Before refactoring

This commit is contained in:
Jan-Niclas Loosen
2026-01-22 10:02:16 +01:00
parent c66222050b
commit 489f385161
8 changed files with 137 additions and 232 deletions

View File

@@ -10,6 +10,7 @@ from cfg.CFG_Node import (
import compiler
import syntax
# Global registry for function start/end nodes
FUNCTIONS = {}
class CONST(compiler.CONST):
@@ -28,9 +29,13 @@ class ID(compiler.ID):
class AOP(compiler.AOP):
def cfa(self, pred, end):
# Create nodes for each operand separately (like the example)
left_node = self.arg1.cfa(pred, None)
right_node = self.arg2.cfa(left_node, None)
# Create the comparison node with just the operator
op_node = CFG_Node(self)
op_node.label = f"{self.operator}"
right_node.add_child(op_node)
op_node.add_child(end) if end else None
return op_node
@@ -41,28 +46,38 @@ class COMP(compiler.COMP):
left_node = self.arg1.cfa(pred, None)
right_node = self.arg2.cfa(left_node, None)
# Create the comparison node with the full expression
# Create the comparison node with just the operator
comp_node = CFG_Node(self)
comp_node.label = f"({str(self.arg1)} {self.operator} {str(self.arg2)})"
comp_node.label = f"{self.operator}"
right_node.add_child(comp_node)
comp_node.add_child(end) if end else None
return comp_node
class EQOP(compiler.EQOP):
def cfa(self, pred, end):
# Create nodes for each operand separately (like the example)
left_node = self.arg1.cfa(pred, None)
right_node = self.arg2.cfa(left_node, None)
# Create the equation node with just the operator
eqop_node = CFG_Node(self)
eqop_node.label = f"{self.operator}"
right_node.add_child(eqop_node)
eqop_node.add_child(end) if end else None
return eqop_node
class LOP(compiler.LOP):
def cfa(self, pred, end):
n = CFG_Node(self)
pred.add_child(n)
n.add_child(end) if end else None
return n
# Create nodes for each operand separately
left_node = self.arg1.cfa(pred, None)
right_node = self.arg2.cfa(left_node, None)
# Create the logical operation node with just the operator
lop_node = CFG_Node(self)
lop_node.label = f"{self.operator}"
right_node.add_child(lop_node)
lop_node.add_child(end) if end else None
return lop_node
class ASSIGN(compiler.ASSIGN):
def cfa(self, pred, end):
@@ -83,7 +98,7 @@ class IF(compiler.IF):
def cfa(self, pred, end):
cond_node = self.cond.cfa(pred, None)
diamond = CFG_DIAMOND(self.cond)
diamond.label = "<>" # Use simple diamond label
diamond.label = "<?>" # Use simple diamond label
cond_node.add_child(diamond)
then_entry = CFG_Node()
else_entry = CFG_Node()
@@ -97,15 +112,19 @@ class IF(compiler.IF):
class WHILE(compiler.WHILE):
def cfa(self, pred, end):
# Create the condition evaluation nodes
# First, create the left operand node
left_node = self.cond.arg1.cfa(pred, None)
# Then create the right operand node
right_node = self.cond.arg2.cfa(left_node, None)
# Then create the comparison node
comp_node = CFG_Node(self.cond)
comp_node.label = f"({str(self.cond.arg1)} {self.cond.operator} {str(self.cond.arg2)})"
right_node.add_child(comp_node)
# Handle different types of conditions
if hasattr(self.cond, 'arg1') and hasattr(self.cond, 'arg2'):
# This is a comparison operation (e.g., a > b)
# Create the condition evaluation nodes
left_node = self.cond.arg1.cfa(pred, None)
right_node = self.cond.arg2.cfa(left_node, None)
comp_node = CFG_Node(self.cond)
comp_node.label = f"({str(self.cond.arg1)} {self.cond.operator} {str(self.cond.arg2)})"
right_node.add_child(comp_node)
else:
# This is a simple condition (e.g., constant true/false or single expression)
cond_node = self.cond.cfa(pred, None)
comp_node = cond_node
# Create the diamond node
diamond = CFG_DIAMOND(self.cond)
@@ -116,11 +135,14 @@ class WHILE(compiler.WHILE):
body_entry = CFG_Node()
diamond.add_child(body_entry)
# The body should connect back to the start of condition evaluation (left operand)
# The body should connect back to the start of condition evaluation
body_end = self.body.cfa(body_entry, None)
if body_end is not None:
# Connect body end back to the left operand (start of condition evaluation)
body_end.add_child(left_node)
# Connect body end back to the condition evaluation
if hasattr(self.cond, 'arg1') and hasattr(self.cond, 'arg2'):
body_end.add_child(left_node)
else:
body_end.add_child(pred) # For simple conditions, go back to start
after = CFG_Node()
diamond.add_child(after)
@@ -129,14 +151,15 @@ class WHILE(compiler.WHILE):
class CALL(compiler.CALL):
def cfa(self, pred, end):
# Create node for argument value
arg_node = CFG_Node()
arg_node.label = str(self.arg[0]) # Assuming single argument for now
pred.add_child(arg_node)
# Create nodes for all argument values
current_arg_node = pred
for i, arg in enumerate(self.arg):
# Process argument through its cfa method to create proper CFG structure
current_arg_node = arg.cfa(current_arg_node, None)
call_node = CFG_CALL(self)
call_node.label = f"CALL {self.f_name}({', '.join(map(str, self.arg))})"
arg_node.add_child(call_node)
call_node.label = f"CALL {self.f_name}"
current_arg_node.add_child(call_node)
cont = CFG_Node()
cont.add_child(end) if end else None
@@ -148,7 +171,7 @@ class CALL(compiler.CALL):
# Create return node from function
return_node = CFG_RETURN(self)
return_node.label = f"RET {self.f_name}({', '.join(map(str, self.arg))})"
return_node.label = f"RET {self.f_name}"
f_end.add_child(return_node)
return_node.add_child(cont)
@@ -156,23 +179,29 @@ class CALL(compiler.CALL):
# Add direct edge from CALL to RET node (for the expected structure)
call_node.add_child(return_node)
# For recursive calls in function g, the RET node should connect to the x variable
# This handles the specific case where g(y) return value flows to x
# For recursive calls, we need to ensure proper return value flow
# In expressions like g(x)+x, the return value from g(x) flows to the continuation
# This is especially important for recursive functions where multiple calls return values
# that need to flow to the same continuation point
if self.f_name == 'g':
# We need to connect to the existing x variable node
# This will be handled in the CFG generation by connecting to the appropriate variable
pass
# For recursive calls in g, ensure the return node connects to continuation
# This handles cases like g(y) where the return value flows to the same place as g(x)
return_node.add_child(cont)
return cont
class DECL(compiler.DECL):
def cfa(self, pred, end):
f_start = CFG_START(self)
f_start.label = f"START {self.f_name}({', '.join(self.params)})"
f_end = CFG_END(self)
f_end.label = f"END {self.f_name}({', '.join(self.params)})"
FUNCTIONS[self.f_name] = (f_start, f_end)
# Check if function is already registered (from first pass in LET)
if self.f_name in FUNCTIONS:
f_start, f_end = FUNCTIONS[self.f_name]
else:
f_start = CFG_START(self)
f_start.label = f"START {self.f_name}({', '.join(self.params)})"
f_end = CFG_END(self)
f_end.label = f"END {self.f_name}({', '.join(self.params)})"
FUNCTIONS[self.f_name] = (f_start, f_end)
body_end = self.body.cfa(f_start, f_end)
if body_end is not None:
body_end.add_child(f_end)
@@ -180,13 +209,25 @@ class DECL(compiler.DECL):
class LET(compiler.LET):
def cfa(self, pred, end):
# First pass: Register all function declarations
decls = self.decl if isinstance(self.decl, list) else [self.decl]
for d in decls:
if isinstance(d, compiler.DECL):
# Register function without building CFG yet
f_start = CFG_START(d)
f_start.label = f"START {d.f_name}({', '.join(d.params)})"
f_end = CFG_END(d)
f_end.label = f"END {d.f_name}({', '.join(d.params)})"
FUNCTIONS[d.f_name] = (f_start, f_end)
# Create global entry node
global_entry = CFG_Node()
global_entry.label = "None"
pred.add_child(global_entry)
current = global_entry
decls = self.decl if isinstance(self.decl, list) else [self.decl]
# Second pass: Process declarations and build CFGs
for d in decls:
current = d.cfa(current, None)
if current is None:
@@ -200,7 +241,8 @@ class LET(compiler.LET):
global_exit.label = "None"
if body_result is not None:
body_result.add_child(global_exit)
global_exit.add_child(end)
if end is not None:
global_exit.add_child(end)
return global_exit