191 lines
5.7 KiB
Python
191 lines
5.7 KiB
Python
# (c) Stephan Diehl, University of Trier, Germany, 2025
|
|
|
|
class EXPRESSION:
|
|
pp_count = 0
|
|
|
|
def __init__(self):
|
|
self.pp = EXPRESSION.pp_count
|
|
EXPRESSION.pp_count += 1
|
|
|
|
@staticmethod
|
|
def copy():
|
|
return EXPRESSION()
|
|
|
|
def allNodes(self):
|
|
ret = [self]
|
|
for node in (self.__getattribute__(a) for a in self.__dict__.keys()):
|
|
if isinstance(node, EXPRESSION):
|
|
ret += node.allNodes()
|
|
if isinstance(node, list):
|
|
for n in node:
|
|
if isinstance(n, EXPRESSION):
|
|
ret += n.allNodes()
|
|
return ret
|
|
|
|
def children(self):
|
|
"""Return a list of (name, childNode)."""
|
|
out = []
|
|
for key, value in self.__dict__.items():
|
|
if key == "pp":
|
|
continue
|
|
if isinstance(value, EXPRESSION):
|
|
out.append((key, value))
|
|
elif isinstance(value, list):
|
|
for i, elem in enumerate(value):
|
|
if isinstance(elem, EXPRESSION):
|
|
out.append((f"{key}[{i}]", elem))
|
|
return out
|
|
|
|
def to_dot(self, out):
|
|
# node label is class name or class name + value
|
|
label = type(self).__name__
|
|
if hasattr(self, "operator"): # AOP/EQOP/COMP/LOP
|
|
label += f"({self.operator})"
|
|
if hasattr(self, "name"): # ID
|
|
label += f"({self.name})"
|
|
if hasattr(self, "value"): # CONST
|
|
label += f"({self.value})"
|
|
|
|
out.write(f' node{self.pp} [label="{label}"];\n')
|
|
|
|
for (edge_name, child) in self.children():
|
|
out.write(f' node{self.pp} -> node{child.pp} [label="{edge_name}"];\n')
|
|
child.to_dot(out)
|
|
|
|
class LET(EXPRESSION):
|
|
def __init__(self, declarations, body):
|
|
super().__init__()
|
|
self.declarations = declarations
|
|
self.body = body
|
|
|
|
def __str__(self):
|
|
return "let " + ", ".join(str(d) for d in self.declarations) + " in " + str(self.body)
|
|
|
|
class DECL(EXPRESSION):
|
|
def __init__(self, f_name, params, body):
|
|
super().__init__()
|
|
self.f_name = f_name
|
|
self.params = params
|
|
self.body = body
|
|
|
|
def __str__(self):
|
|
return f"{self.f_name}(" + ",".join(str(p) for p in self.params) + ") { " + str(self.body) + " }"
|
|
|
|
class CALL(EXPRESSION):
|
|
def __init__(self, f_name, arguments):
|
|
super().__init__()
|
|
self.f_name = f_name
|
|
self.arguments = arguments
|
|
|
|
def __str__(self):
|
|
return self.f_name + "(" + ",".join(str(a) for a in self.arguments) + ")"
|
|
|
|
class ID(EXPRESSION):
|
|
def __init__(self, name):
|
|
super().__init__()
|
|
self.name = name
|
|
|
|
def __str__(self):
|
|
return self.name
|
|
|
|
class CONST(EXPRESSION):
|
|
def __init__(self, value):
|
|
super().__init__()
|
|
self.value = value
|
|
|
|
def __str__(self):
|
|
return str(self.value)
|
|
|
|
class AOP(EXPRESSION):
|
|
def __init__(self, operator, arg1, arg2):
|
|
super().__init__()
|
|
self.operator = operator
|
|
self.arg1 = arg1
|
|
self.arg2 = arg2
|
|
|
|
def __str__(self):
|
|
return "(" + str(self.arg1) + " " + str(self.operator) + " " + str(self.arg2) + ")"
|
|
|
|
class EQOP(EXPRESSION):
|
|
def __init__(self, operator, arg1, arg2):
|
|
super().__init__()
|
|
self.operator = operator
|
|
self.arg1 = arg1
|
|
self.arg2 = arg2
|
|
|
|
def __str__(self):
|
|
return "(" + str(self.arg1) + " " + str(self.operator) + " " + str(self.arg2) + ")"
|
|
|
|
class COMP(EXPRESSION):
|
|
def __init__(self, operator, arg1, arg2):
|
|
super().__init__()
|
|
self.operator = operator
|
|
self.arg1 = arg1
|
|
self.arg2 = arg2
|
|
|
|
def __str__(self):
|
|
return "(" + str(self.arg1) + " " + str(self.operator) + " " + str(self.arg2) + ")"
|
|
|
|
class LOP(EXPRESSION):
|
|
def __init__(self, operator, arg1, arg2):
|
|
super().__init__()
|
|
self.operator = operator
|
|
self.arg1 = arg1
|
|
self.arg2 = arg2
|
|
|
|
def __str__(self):
|
|
return "(" + str(self.arg1) + " " + str(self.operator) + " " + str(self.arg2) + ")"
|
|
|
|
class ASSIGN(EXPRESSION):
|
|
def __init__(self, variable, expression):
|
|
super().__init__()
|
|
self.variable = variable
|
|
self.expression = expression
|
|
|
|
def __str__(self):
|
|
return self.variable.name + " = " + str(self.expression)
|
|
|
|
class SEQ(EXPRESSION):
|
|
def __init__(self, exp1, exp2):
|
|
super().__init__()
|
|
self.exp1 = exp1
|
|
self.exp2 = exp2
|
|
|
|
def __str__(self):
|
|
return str(self.exp1) + "; " + str(self.exp2)
|
|
|
|
class IF(EXPRESSION):
|
|
def __init__(self, condition, exp1, exp2):
|
|
super().__init__()
|
|
self.condition = condition
|
|
self.exp1 = exp1
|
|
self.exp2 = exp2
|
|
|
|
def __str__(self):
|
|
return "if (" + str(self.condition) + ") then { " + str(self.exp1) + " } else { " + str(self.exp2) + " }"
|
|
|
|
class WHILE(EXPRESSION):
|
|
def __init__(self, condition, body):
|
|
super().__init__()
|
|
self.condition = condition
|
|
self.body = body
|
|
|
|
def __str__(self):
|
|
return "while (" + str(self.condition) + ") do { " + str(self.body) + " }"
|
|
|
|
def pretty_print(clas, indent=0):
|
|
print(' ' * indent + type(clas).__name__ + ':')
|
|
indent += 4
|
|
for k, v in clas.__dict__.items():
|
|
if isinstance(v, EXPRESSION):
|
|
pretty_print(v, indent)
|
|
else:
|
|
print(' ' * indent + f"{k}: {v}")
|
|
|
|
def export_dot(ast, filename="ast.dot"):
|
|
with open(filename, "w") as f:
|
|
f.write("digraph AST {\n")
|
|
f.write(" node [shape=box];\n")
|
|
ast.to_dot(f)
|
|
f.write("}\n")
|