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
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
|
#!/usr/bin/env python
"""Compiles C into assembly for the practicum processor (PP2)
All rights reserved, you may not redistribute or use this program without prior
permission from Peter Wu or Xander Houtman. Use of this program is entirely
your own risk. In no circumstances can the authors of this program be held
responsible for any damage including, but not limited to, financial damage or
data loss. Modification of this program is not allowed without prior
permission. The generated output (assembly and messages) are not subject to
this license.
"""
__author__ = "Peter Wu"
__copyright__ = "Copyright 2011, Peter Wu"
__credits__ = ["Peter Wu"]
__license__ = "Proprietary"
__version__ = "1.0"
__maintainer__ = "Peter Wu"
__email__ = "uwretep@gmail.com"
from Variables import Variables
class LinkedNode(object):
"""Stores nodes with a reference to the parent"""
def __init__(self, node, parent=None, level_increment=False,
defined_names=None):
"""Holds properties for a node
Keyword arguments:
node -- a Node object which is an object from the c_ast class
parent -- a parent LinkedNode object
level_increment -- True if the indentation level needs to be
incremented, False otherwise
defined_names -- a list of names which will be used in the @DATA
section. If not set, it'll be looked up in the parent
"""
self.node = node
if parent:
assert isinstance(parent, LinkedNode), "parent is not a LinkedNode!"
self.parent = parent
self.function = None
self.break_label = None
self.continue_label = None
self.type = type(node).__name__
self.level = 0
self.variables = None
# for supporting post increment and post decrement
self.post_lines = []
parent_variables = None
# inherit level and variables from parent
if parent:
self.level = parent.level
self.variables = parent_variables = parent.variables
if not defined_names:
defined_names = parent.variables.defined_names
# for is added for the init part (C99)
if self.type in ("Compound", "FileAST", "For"):
# the node appears to have an own variable scope
if defined_names is None:
raise RuntimeError("No object found for storing variables")
# pass function object for local variables allocation
function = self.getFunctionNode()
if function:
function = function.function
self.variables = Variables(parent_variables, defined_names,
function=function)
# Identifiers which are in use (think of variables and labels)
self.defined_names = defined_names
if not self.variables:
raise RuntimeError("No variables object found")
if level_increment:
self.incrementLevel()
# labels are limited to function contexts
if self.type == "FuncDef":
self.goto_labels = {}
def handle_post_lines(self, lines):
"""Add post-increment lines to the lines list and clear the queue"""
lines += self.post_lines
self.post_lines = []
def getScopeNode(self):
"""Get the nearest node which introduces a new scope.
If there is no node found an exception is raised because it expects at
least a global scope"""
if self.local_vars is not None:
return self
if self.parent:
return self.parent.getScopeNode()
raise RuntimeError("No global variable scope was found")
def isTypeStatement(self):
"""Returns True if the node is a statement type"""
return self.type in ("Compound", "If", "Return", "DoWhile", "While",
"For", "Decl", "FuncDef", "Break", "Continue",
"EmptyStatement", "Switch", "DeclList",
"FuncDecl", "ArrayDecl", "Case",
"Default", "EllipsisParam",# (int a, ...)
"Enum", # enum type
"Enumerator", # enum value
"EnumeratorList", # list of enum values
"Goto", "Label", "ParamList", "PtrDecl", "Struct",
"TypeDecl", "Typedef", "Union")
def getStatementNode(self):
"""Returns the nearest LinkedNode which is a statement node type"""
if self.isTypeStatement():
return self
if self.parent:
return self.parent.getStatementNode()
return None
def incrementLevel(self):
self.level += 1
def getFunctionNode(self):
"""Returns the nearest LinkedNode which is a function definition node
type"""
if self.type == "FuncDef":
return self
if self.parent:
return self.parent.getFunctionNode()
return None
def setFunction(self, function):
"""Sets the function object containing label information"""
self.function = function
def getLocation(self):
if hasattr(self.node, "coord"):
return self.node.coord
return "Unknown"
def setBreak(self, break_label):
"""Marks this node as a loop or switch by setting the label for break
Keywords arguments:
break_label -- The label to continue when using the break keyword
"""
self.break_label = break_label
def setContinue(self, continue_label):
"""Marks this node as a loop by setting the label for continue
Keywords arguments:
continue_label -- The label to continue when using the continue keyword
"""
self.continue_label = continue_label
def getBreakNode(self):
"""Returns the label to the end of the nearest switch statement or for
loop"""
if self.break_label is not None:
return self
if self.parent:
return self.parent.getBreakNode()
return None
def getContinueNode(self):
"""Returns the label to the label to continue a loop"""
if self.continue_label is not None:
return self
if self.parent:
return self.parent.getContinueNode()
return None
def setLabel(self, label_name):
"""Sets the label for this node and return the label name as it appears
in assembly
"""
if self.parent:
function = self.parent.getFunctionNode()
if not self.parent or not function:
raise RuntimeError("Labels are only allowed in functions")
if label_name in function.goto_labels:
raise RuntimeError("Duplicate label '{}'".format(label_name))
label_asm = "lbl_" + label_name
i = 0
while label_asm in self.defined_names:
label_asm = "lbl_" + label_name + str(i)
i += 1
function.goto_labels[label_name] = label_asm
return label_asm
def lookupLabel(self, label_name):
"""Returns the label name as it appears in assembly for label_name"""
# get the nearest function for this node
if self.parent:
function = self.parent.getFunctionNode()
if not self.parent or not function:
raise RuntimeError("Labels are only allowed in functions")
if label_name in function.goto_labels:
return function.goto_labels[label_name]
raise RuntimeError("Label '{}' used but not defined".format(name))
|