From 8975b08d5b5cb59da1d0f8a14a35472f52ab66d5 Mon Sep 17 00:00:00 2001 From: Peter Wu Date: Wed, 30 Nov 2011 15:26:23 +0000 Subject: Proper support for array declarations and initialization, support array reference --- pp2cc.py | 101 +++++++++++++++++++++++++++++++++++++++++++++------------------ 1 file changed, 73 insertions(+), 28 deletions(-) diff --git a/pp2cc.py b/pp2cc.py index dc99a71..dda8c2f 100755 --- a/pp2cc.py +++ b/pp2cc.py @@ -233,13 +233,13 @@ class Variables(object): if self.parent_variables: return self.parent_variables.getName(name) raise RuntimeError("Use of undefined variable '{}'".format(name)) - def declName(self, name, size=1): + def declName(self, name, size=1, prefix="var"): """Declares a variable in the nearest scope and returns the label name""" if name in self.local_vars: raise RuntimeError("Redeclaration of variable '{}'".format(name)) # global variables are prefixed "var_", locals with "varl_" - var_name = ("varl_" if self.parent_variables else "var_") + name + var_name = prefix + ("l_" if self.parent_variables else "_") + name var_name = self.uniqName(var_name) self.local_vars[name] = var_name self.defined_names[var_name] = size @@ -1146,44 +1146,64 @@ class Parse(object): lines = [] size = 1 linked_type = LinkedNode(linked_node.node.type, linked_node) + var_name = linked_node.variables.declName(linked_node.node.name, 1) if linked_type.type == "ArrayDecl": - size = self.determineConstValue(LinkedNode(linked_type.node.dim, linked_node)) + size = self.determineConstValue(LinkedNode(linked_type.node.dim, + linked_node)) + node_init = linked_node.node.init + if node_init and isinstance(node_init, c_ast.ExprList): + real_size = len(node_init.exprs) + if real_size > size: + self.logger.warning("excess elements in array initializer", + linked_node=linked_node) + var_array = linked_node.variables.declName(var_name, size, + prefix="arr") elif linked_type.type == "PtrDecl": # no check whether the pointer is valid or not pass elif linked_type.type == "TypeDecl": if not linked_type.node.type.names[0] in ("int", "void"): self.logger.warning("Only void and int types are supported", linked_node) - var_name = linked_node.variables.declName(linked_node.node.name, size) # if the declaration also has a definition if linked_node.node.init: init_vals = [] - node_init = linked_node.node.init + linked_init = LinkedNode(linked_node.node.init, linked_node) if (linked_type.type == "ArrayDecl" and - isinstance(node_init, c_ast.ExprList)): + linked_init.type == "ExprList"): + reg_value = "R0" + # contains the address of the first array element + reg_array = "R1" + # store the address of the first array element in the pointer + init_vals.append(self.asm.binary_op("LOAD", reg_array, "GB")) + init_vals.append(self.asm.binary_op("ADD", reg_array, var_array)) + init_vals.append(self.asm.binary_op("STOR", reg_array, + "[GB+" + var_name + "]")) array_index = 0 - for array_elm in node_init.exprs: - init_val = self.parseExpression(array_elm, linked_node) - result_reg = self.registers.find_register(init_val, fatal=True) - # find a free register for storing the address of variable. - # We could modify the GB register as well, but that does - # not decrease the instructions count and is not safe with - # interrupts - self.registers.alloc(result_reg) - var_reg = self.registers.alloc() - self.registers.free(var_reg) - self.registers.free(result_reg) - - init_val.append(self.asm.binary_op("LOAD", var_reg, var_name)) - if array_index: - init_val.append(self.asm.binary_op("ADD", var_reg, array_index)) - init_val.append(self.asm.binary_op("STOR", result_reg, "[GB+" + var_reg + "]")) - init_vals += init_val + for array_elm in linked_init.node.exprs: + linked_arrelm = LinkedNode(array_elm, linked_init) + # only constant expressions are allowed in array init + init_val = self.determineConstValue(linked_arrelm) + + # store the array element in the array instead of the + # pointer itself + init_vals.append(self.asm.binary_op("LOAD", reg_value, + init_val)) + # save the value to the array's base address + index + init_vals.append(self.asm.binary_op("STOR", reg_value, + "[" + reg_array + "+" + + str(array_index) + "]")) + array_index += 1 + # ignore elements which do not fit in the allocated space + if array_index > size: + break else: - init_vals = self.parseExpression(linked_node.node.init, linked_node) + init_vals = self.parseExpression(linked_node.node.init, + linked_node) result_reg = self.registers.find_register(init_vals) - init_vals.append(self.asm.binary_op("STOR", result_reg, "[GB+" + var_name + "]")) + init_vals.append(self.asm.binary_op("STOR", result_reg, + "[GB+" + var_name + "]")) + # if global context (i.e. not in a function) if linked_node.getFunctionNode() is None: self.globalInit += init_vals @@ -1254,6 +1274,29 @@ class Parse(object): lines = [] for cn in linked_node.decls: lines += self.parseStatement(cn, linked_node) + def parseArrayRef(self, linked_node): + lines = [] + name_expr = self.parseExpression(linked_node.node.name, linked_node) + name_reg = self.registers.find_register(name_expr, fatal=True) + lines += name_expr + index_expr = self.parseExpression(linked_node.node.subscript, linked_node) + index_reg = self.registers.find_register(index_expr, fatal=True) + for line in index_expr: + if self.registers.is_register_changed(line, name_reg): + lines.append(self.asm.push(name_reg)) + lines += index_expr + self.registers.alloc(index_reg) + name_reg = self.registers.alloc() + self.registers.free(name_reg) + self.registers.free(index_reg) + lines.append(self.asm.pull(name_reg)) + break + else: + lines += index_expr + + lines.append(self.asm.binary_op("LOAD", name_reg, + "[" + name_reg + "+" + index_reg + "]")) + return lines def parseStatement(self, node, parent_linked_node, level_increment=False): linked_node = LinkedNode(node, parent_linked_node, level_increment=level_increment) self.asm.level = linked_node.level @@ -1277,14 +1320,13 @@ class Parse(object): lines = [] if linked_node.type in ("ID", "Constant", "UnaryOp", "FuncCall", "Cast", - "BinaryOp", "TernaryOp", "Assignment", "ExprList"): + "BinaryOp", "TernaryOp", "Assignment", "ExprList", "ArrayRef"): lines += getattr(self, "parse" + linked_node.type)(linked_node) elif linked_node.type in ("Compound", "If", "Return", "DoWhile", "While", "For", "Decl", "FuncDef", "Break", "Continue", "EmptyStatement"): raise RuntimeError("A statement is used in expression context") - elif linked_node.type in ("ArrayRef", - "CompoundLiteral",# won't be supported + elif linked_node.type in ("CompoundLiteral",# won't be supported "IdentifierType", "NamedInitializer",# attributes, remove "StructRef", "Typename"): raise RuntimeError("Not implemented for expression type " + repr(node)) @@ -1292,6 +1334,9 @@ class Parse(object): raise RuntimeError("Not implemented expression and unknown type: " + repr(node)) return lines def determineConstValue(self, linked_node): + """Returns the value of the constant expression of linked_node as an + integer. An exception is thrown if the expression is not constant + """ node = linked_node.node value = None -- cgit v1.2.1