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
|
#!/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"
class Variables(object):
def __init__(self, parent_variables):
"""A scope for holding variable names
Keywords arguments:
parent_variables -- the parent Variables object. If None, it's a global
variable scope
"""
self.parent_variables = parent_variables
self.function = None
if self.parent_variables and hasattr(self.parent_variables, "function"):
self.function = self.parent_variables.function
# key: name, value: address n relative to BP (n >= 1)
self.local_vars = {}
self.param_vars = []
def setFunction(self, function):
"""Sets the function object containing the stack allocation function"""
self.function = function
def getAddress(self, name):
"""Gets the address for a variable as a tuple containing a register and
displacement
To get the address of the variable, add the register value and
displacement
"""
# first try the local scope
if name in self.local_vars:
# XXX don't hardcode R5
return ("R5", str(-self.local_vars[name]))
try:
return ("R5", str(1 + self.param_vars.index(name)))
except ValueError:
pass
# lookup in the parent
if self.parent_variables:
return self.parent_variables.getAddress(name)
raise RuntimeError("Use of undefined variable '{}'".format(name))
def declName(self, name, size=1, is_param=False):
"""Declares a variable in the nearest scope
Keyword arguments:
name -- The symbolic name of the variable
size -- The size of the memory to be allocated in words (default 1)
is_param -- Whether the name is a function parameter or not
"""
if name in self.local_vars or name in self.param_vars:
raise RuntimeError("Redeclaration of variable '{}'".format(name))
# parameters do not need a special allocation because the callee
# pushes it into the stack
if is_param:
self.param_vars.append(name)
else:
self.local_vars[name] = self.function.allocStack(size)
class GlobalVariables(Variables):
def __init__(self, defined_names):
"""A scope for holding variable names
Keywords arguments:
defined_names -- A dictionary holding identifiers which are already
defined in assembly
"""
self.defined_names = defined_names
self.global_vars = {}
def _uniqName(self, name):
"""Returns an unique global variable name for assembly"""
uniq_name = name
i = 0
while uniq_name in self.defined_names:
uniq_name = name + "_" + str(i)
i += 1
return uniq_name
def getAddress(self, name):
"""Gets the address for a variable as a tuple containing a register and
displacement
To get the address of the variable, add the register value and
displacement
"""
if name in self.global_vars:
return ("GB", self.global_vars[name])
raise RuntimeError("Use of undefined variable '{}'".format(name))
def declName(self, name, size=1, is_param=False):
"""Declares a variable in the nearest scope
Keyword arguments:
name -- The symbolic name of the variable
size -- The size of the memory to be allocated in words (default 1)
is_param -- Whether the name is a function parameter or not
"""
if name in self.global_vars:
raise RuntimeError("Redeclaration of variable '{}'".format(name))
if is_param:
raise RuntimeError("Parameter '{}' declared in global context".format(name))
else:
# global variables are prefixed "var_"
var_name = self._uniqName("var_" + name)
self.global_vars[name] = var_name
self.defined_names[var_name] = size
|