summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPeter Wu <lekensteyn@gmail.com>2011-12-02 21:57:45 +0000
committerPeter Wu <lekensteyn@gmail.com>2011-12-02 21:57:45 +0000
commit30fc12c61857d9f242953e49b97118c976170d13 (patch)
tree92abf2646d97cc7729bada75d6c5986a3c59dba6
parentd48fb25678e10c79bf8971892b8573fb7cb9e247 (diff)
downloadpp2cc-30fc12c61857d9f242953e49b97118c976170d13.tar.gz
Fix constant value eval and declaration and initialization of array elements
-rw-r--r--Registers.py11
-rwxr-xr-xpp2cc.py145
2 files changed, 109 insertions, 47 deletions
diff --git a/Registers.py b/Registers.py
index 1d080f1..7fac4dd 100644
--- a/Registers.py
+++ b/Registers.py
@@ -70,6 +70,17 @@ class Registers(object):
raise RuntimeError("free() of unused register")
else:
raise RuntimeError("free() of invalid register")
+ def next_free(self, use_register=None):
+ """Mark use_register as in use, find the next free register and then
+ free both.
+ """
+ if use_register:
+ self.alloc(use_register)
+ next_avail = self.alloc()
+ self.free(next_avail)
+ if use_register:
+ self.free(use_register)
+ return next_avail
def get_register(self, text):
"""Retrieve the first register from a binary instruction"""
text = text.strip()
diff --git a/pp2cc.py b/pp2cc.py
index d3aac94..9de64dd 100755
--- a/pp2cc.py
+++ b/pp2cc.py
@@ -950,13 +950,17 @@ class Parse(object):
return lines
def parseDecl(self, linked_node):
lines = []
- size = 1
+ in_function = linked_node.getFunctionNode() is not None
+ size = 0
linked_type = LinkedNode(linked_node.node.type, linked_node)
name = linked_node.node.name
if linked_type.type == "ArrayDecl":
if linked_type.node.dim is not None:
- size = self.determineConstValue(LinkedNode(linked_type.node.dim,
- linked_node))
+ linked_dim_node = LinkedNode(linked_type.node.dim, linked_node)
+ try:
+ size = self.determineConstValue(linked_dim_node)
+ except RuntimeError as errmsg:
+ self.logger.error(errmsg, linked_node=linked_dim_node)
else:
size = None
node_init = linked_node.node.init
@@ -987,6 +991,10 @@ class Parse(object):
self.logger.error("Unknown declaration type '{}'".format(linked_type.type),
linked_node=linked_node)
+ # increment size here because the array dimension calculation does not
+ # take the pointer into account
+ size += 1
+
try:
linked_node.variables.declName(name, size)
# address of variable split up in register and displacement
@@ -994,52 +1002,92 @@ class Parse(object):
except RuntimeError as errmsg:
self.logger.error(errmsg, linked_node=linked_node)
+ # initialize pointer address of array
+ if linked_type.type == "ArrayDecl" and not in_function:
+ reg_array = self.registers.next_free()
+ # store the address of the first array element in the pointer
+ self.globalInit.append(self.asm.binary_op("LOAD", reg_array, var_reg))
+ # in this particular case, it happens that the array values are
+ # next to the pointer to the array
+ self.globalInit.append(self.asm.binary_op("ADD", reg_array, 1))
+ # store address of the first array element in the array pointer
+ self.globalInit.append(self.asm.binary_op("STOR", reg_array, "[" +
+ var_reg + "+" + var_disp + "]"))
# if the declaration also has a definition
if linked_node.node.init:
init_vals = []
linked_init = LinkedNode(linked_node.node.init, linked_node)
if (linked_type.type == "ArrayDecl" and
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, var_reg))
- # in this particular case, it happens that the array values are
- # next to the pointer to the array
- init_vals.append(self.asm.binary_op("ADD", reg_array, 1))
- # store address of the first array element in the array pointer
- init_vals.append(self.asm.binary_op("STOR", reg_array,
- "[" + var_reg + "+" +
- var_disp + "]"))
+ # next available register for storing the value
+ reg_value = self.registers.next_free(reg_array)
array_index = 0
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) + "]"))
+ try:
+ # only constant expressions are allowed in array init
+ init_val = str(self.determineConstValue(linked_arrelm))
+ if in_function:
+ init_vals.append(self.asm.binary_op("LOAD",
+ reg_value, init_val))
+ else:
+ # +1 because the first element is reserved for pointer
+ self.varNames[var_disp][array_index + 1] = init_val
+ except RuntimeError as errmsg:
+ # only functions are allowed to have non-constant
+ # expressions
+ if not in_function:
+ self.logger.error(errmsg, linked_node=linked_arrelm)
+
+ init_vals.append(self.asm.push(reg_array))
+ init_val = self.parseExpression(array_elm, linked_init)
+ # if the result register has changed, update
+ res_reg = self.registers.find_register(init_val, fatal=True)
+ init_vals += init_val
+
+ # swap registers if the result would be overwritten
+ if res_reg == reg_array:
+ reg_value, reg_array = reg_array, res_value
+ init_vals.append(self.asm.pull(reg_array))
+
+ # store the array element in the array instead of the
+ # pointer itself
+ init_vals.append(self.asm.binary_op("LOAD", reg_value,
+ init_val))
+ if in_function:
+ # 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
+ if init_vals:
+ init_vals = pre_init + init_vals
else:
- init_vals = self.parseExpression(linked_node.node.init,
+ try:
+ init_val = str(self.determineConstValue(linked_init))
+ if in_function:
+ init_vals.append(self.asm.binary_op("LOAD", result_reg,
+ init_val))
+ else:
+ self.varNames[var_disp][0] = init_val
+ except RuntimeError as errmsg:
+ # only constant expressions are allowed in global init
+ if not in_function:
+ self.logger.error(errmsg, linked_node=linked_init)
+
+ 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,
- "[" + var_reg + "+" +
- var_disp + "]"))
+ result_reg = self.registers.find_register(init_vals)
+ if in_function:
+ init_vals.append(self.asm.binary_op("STOR", result_reg,
+ "[" + var_reg + "+" +
+ var_disp + "]"))
# if global context (i.e. not in a function)
- if linked_node.getFunctionNode() is None:
+ if not in_function:
self.globalInit += init_vals
else:
lines += init_vals
@@ -1187,8 +1235,8 @@ class Parse(object):
self.asm.level = linked_node.level
lines = []
if linked_node.isTypeStatement():
- lines.append(self.asm.format_line("; " + linked_node.type + " " +
- linked_node.getLocation()))
+ #lines.append(self.asm.format_line("; " + linked_node.type + " " +
+ # linked_node.getLocation()))
if hasattr(self, "parse" + linked_node.type):
lines += getattr(self, "parse" + linked_node.type)(linked_node)
# add for support post increment and decrement
@@ -1207,8 +1255,8 @@ class Parse(object):
self.asm.level = linked_node.level
lines = []
- lines.append(self.asm.format_line("; " + linked_node.type + " " +
- linked_node.getLocation()))
+ #lines.append(self.asm.format_line("; " + linked_node.type + " " +
+ # linked_node.getLocation()))
if linked_node.type in ("ID", "Constant", "UnaryOp", "FuncCall", "Cast",
"BinaryOp", "TernaryOp", "Assignment", "ExprList", "ArrayRef"):
lines += getattr(self, "parse" + linked_node.type)(linked_node)
@@ -1238,9 +1286,12 @@ class Parse(object):
if linked_node.type == "Constant":
if node.type != "int":
- self.logger.error("Unsupported constant type '{}'".format(node.type),
- linked_node=linked_node)
+ raise RuntimeError("Unsupported constant type '{}'".format(node.type))
value = self.convertStrToInteger(self.convertInteger(node.value))
+ elif linked_node.type == "Cast":
+ self.logger.warning("Found a type cast, but these are unsupported",
+ linked_node=linked_node)
+ value = self.determineConstValue(LinkedNode(node.expr, linked_node))
elif linked_node.type == "UnaryOp":
op = node.op
operators = {
@@ -1250,10 +1301,10 @@ class Parse(object):
"~": "invert"
}
if op not in operators:
- self.logger.error("Operator '{}' is not supported".format(op),
- linked_node=linked_node)
+ raise RuntimeError("Operator '{}' is not supported".format(op))
else:
- operand = self.determineConstValue(node.expr)
+ operand = self.determineConstValue(LinkedNode(node.expr,
+ linked_node))
if op == "-":
# negating a value in PP2 is flipping the WORDSIZE-th bit
value = operand ^ msb
@@ -1285,11 +1336,12 @@ class Parse(object):
">>": "rshift"
}
if op not in operators:
- self.logger.error("Operator '{}' is not supported".format(op),
- linked_node=linked_node)
+ raise RuntimeError("Operator '{}' is not supported".format(op))
else:
- operand1 = self.determineConstValue(node.left)
- operand2 = self.determineConstValue(node.right)
+ operand1 = self.determineConstValue(LinkedNode(node.left,
+ linked_node))
+ operand2 = self.determineConstValue(LinkedNode(node.right,
+ linked_node))
if op == "-":
# ensure that the result of substraction is positive by
# setting the (WORDSIZE+1)-nth bit on the first operand
@@ -1309,8 +1361,7 @@ class Parse(object):
else:
value = int(getattr(operator, op)(operand1, operand2))
else:
- self.logger.error("Unsupported node type '{}'".format(linked_node.type),
- linked_node=linked_node)
+ raise RuntimeError("Unsupported node type '{}'".format(linked_node.type))
# The PP2 can only count in 18-bit, therefore AND the result. Note that
# overflow may occur for large numbes. This is a non-issue for unary +
# - ~ (and ! because it results in 0 or 1). For binary comparison