summaryrefslogtreecommitdiff
path: root/Variables.py
diff options
context:
space:
mode:
Diffstat (limited to 'Variables.py')
-rw-r--r--Variables.py104
1 files changed, 59 insertions, 45 deletions
diff --git a/Variables.py b/Variables.py
index 338cfdf..bab1a34 100644
--- a/Variables.py
+++ b/Variables.py
@@ -19,31 +19,71 @@ __maintainer__ = "Peter Wu"
__email__ = "uwretep@gmail.com"
class Variables(object):
- def __init__(self, parent_variables, defined_names, function=None):
+ 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
- defined_names -- A list of defined variables to which additional
- variables might be appended
- function -- The function object used for allocating memory. If not set,
- the variables object will ask the parent_variables object for it
"""
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
- # if there is a parent_variables object, it must be a 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:
- # key: name, value: address n relative to BP (n >= 1)
- self.local_vars = {}
- self.param_vars = []
- if not self.function:
- self.function = self.parent_variables.function
+ 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:
- # key: name of var, value: label of var
- self.global_vars = {}
+ 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
- def uniqName(self, name):
+ self.global_vars = {}
+ def _uniqName(self, name):
"""Returns an unique global variable name for assembly"""
uniq_name = name
i = 0
@@ -58,22 +98,8 @@ class Variables(object):
To get the address of the variable, add the register value and
displacement
"""
- # first try the local scope
- if self.function:
- if name in self.local_vars:
- # XXX don't hardcode R5
- return ("R5", str(self.local_vars[name]))
- try:
- return ("R5", str(-self.param_vars.index(name)))
- except ValueError:
- pass
- else:
- # lookup in global vars
- if name in self.global_vars:
- return ("GB", self.global_vars[name])
- # lookup in the parent
- if self.parent_variables:
- return self.parent_variables.getAddress(name)
+ 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
@@ -83,25 +109,13 @@ class Variables(object):
size -- The size of the memory to be allocated in words (default 1)
is_param -- Whether the name is a function parameter or not
"""
- already_defined = False
- if self.function:
- already_defined = name in self.local_vars or name in self.param_vars
- else:
- already_defined = name in self.global_vars
- if already_defined:
+ if name in self.global_vars:
raise RuntimeError("Redeclaration of variable '{}'".format(name))
- if self.function:
- # 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)
- elif is_param:
+ if is_param:
raise RuntimeError("Parameter '{}' declared in global context".format(name))
else:
# global variables are prefixed "var_"
- var_name = "var_" + name
+ var_name = self._uniqName("var_" + name)
self.global_vars[name] = var_name
self.defined_names[var_name] = size