forked from JessicaDouthit00/C-Compiler
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathAST.py
More file actions
146 lines (128 loc) · 5.68 KB
/
AST.py
File metadata and controls
146 lines (128 loc) · 5.68 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
# Authors: Ariana Matcheama, Jessica Douthit, Deanna M. Wilborne
# College: Berea College
# Purpose: AST Class
# Copyright (2023) Deanna M. Wilborne
from anytree import NodeMixin, RenderTree
from Common import Common
from sys import platform
if platform != "win32":
import curses.ascii as ca
# noinspection SpellCheckingInspection
class AST(NodeMixin):
version = "2024-04-29"
# name: is the node name - this is used by anything that processes the AST after created, like an
# emitter
# value: is a dictionary - this dictionary contains annotations that can be useful for both
# compilation and emitting of machine code from an AST
# type - data type if applicable
# struct: is a dictionary - this dictionary contains annotations that can be useful for structural
# aspects of the AST
# term - node is a terminal node (False) otherwise True (set by grammar)
# parent: optional but can be used to link to the parent node
# children: represents the children the node is connected to - children go in a list
# line: the line number the AST node was created from
# index: ?? TODO: figure out purpose (it is likely the starting character in the source file by character #)
def __init__(self, name: str, value: {} = None, struct: {} = None, parent=None,
children: [] = None, line: int = None, index: int = None) -> None:
self.name = name
self.parent = parent
if value is None:
self.value = {'type': None}
else:
self.value = value
if struct is None:
self.struct = {'term': False}
else:
self.struct = struct
# 2023-04-16, DWM, line and index is based on:
# https://my.eng.utah.edu/~cs3100/lectures/l14/ply-3.4/doc/ply.html#ply_nn33
self.line = line
self.index = index
if children is not None:
self.children = children
# 2023-04-24, DMW, substitute control characters in value attibutes of type string
def safe_value(self) -> str:
output = ""
for char in self.value:
output += ca.unctrl(char)
return output
# 2023-04-24, DMW, provide ability to print node details
def __str__(self) -> str:
output_str = "{" + " name='{}'".format(self.name)
if self.value is not None:
if platform != "win32":
if Common.object_type(self.value) == "str":
output_str += ", value='{}'".format(self.safe_value())
else:
output_str += ", value='{}'".format(self.value)
else:
output_str += ", value='{}'".format(self.value)
if self.parent is not None:
output_str += ", parent='{}'".format(self.parent.name)
if self.children is not None:
if len(self.children) != 0:
children = ""
for child in self.children:
if children != "":
children += ", '{}'".format(child.name)
else:
children = "[ '{}'".format(child.name)
children += " ]"
output_str += ", children={}".format(children)
if self.line is not None:
output_str += ", line={}".format(self.line)
if self.index is not None:
output_str += ", index={}".format(self.index)
output_str += " }"
return output_str
# 2024-02-12, DMW, added class static method
@staticmethod
def render_tree(tree) -> None:
# 2024-04-27, DMW, added the follow error checking
if tree is None:
print("AST.render_tree(): There is no tree to render.")
return
for pre, fill, node in RenderTree(tree):
if node is None:
print("RENDER_TREE: Invalid Node Object")
continue
# print("node value={}".format(node.value))
if node.value is None:
node_info = node.name
else:
node_info = node.name + "(" + str(node.value) + ")"
pre_text = str(pre).replace("\t", " ")
ast_row = "%s%s" % (pre_text, node_info)
ast_row = ast_row.replace("\t", " ")
# print("%s%s" % (pre, node_info))
print(ast_row)
# 2024-04-23, DMW, created the following class that allows emitting the
# AST as a multiline string that can be included in the output from an emitter
@staticmethod
def render_tree_str(tree, prefix_str: str = "") -> str:
output = ""
for pre, fill, node in RenderTree(tree):
# print("node value={}".format(node.value))
if node.value is None:
node_info = node.name
else:
node_info = node.name + "(" + str(node.value) + ")"
pre_text = str(pre).replace("\t", " ")
ast_row = "%s%s" % (pre_text, node_info)
ast_row = ast_row.replace("\t", " ")
# print("%s%s" % (pre, node_info))
# print(ast_row)
output += prefix_str + ast_row + "\n"
return output
# limited functional testing
# 2023-04-24, DMW, updated to use test() to prevent pycharm warnings about shadowing "child"
if __name__ == "__main__":
def test():
child2 = AST("child2", value="2")
child3a = AST("child3a", value="3a")
child3b = AST("child3b", value="3b")
child3 = AST("child3", value="3", children=[child3a, child3b])
child = AST("child", children=[child2, child3])
root = AST("root", value="\ntest\n", children=[child])
AST.render_tree(root)
test()