From 6aaff7ae54dbe34ea6bf3f9ee8c93e9d79db3c22 Mon Sep 17 00:00:00 2001 From: Peter Wu Date: Thu, 1 Dec 2011 22:18:27 +0000 Subject: Fix stack corruption, support func calls with arguments and automatic variables --- Variables.py | 104 +++++++++++++++++++++++++++++++++-------------------------- 1 file changed, 59 insertions(+), 45 deletions(-) (limited to 'Variables.py') 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 -- cgit v1.2.1