summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPeter Wu <lekensteyn@gmail.com>2011-11-30 15:26:23 +0000
committerPeter Wu <lekensteyn@gmail.com>2011-11-30 15:26:23 +0000
commit8975b08d5b5cb59da1d0f8a14a35472f52ab66d5 (patch)
tree2b5abd4c7a0dd217c3f701feebf24a0a73b3431c
parenta62cbd3e76c0e937b224158a206fe343a9c4d2eb (diff)
downloadpp2cc-8975b08d5b5cb59da1d0f8a14a35472f52ab66d5.tar.gz
Proper support for array declarations and initialization, support array reference
-rwxr-xr-xpp2cc.py101
1 files 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