summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPeter Wu <lekensteyn@gmail.com>2011-11-26 22:59:58 +0000
committerPeter Wu <lekensteyn@gmail.com>2011-11-26 22:59:58 +0000
commit806e7e40726f7262b3969994238861428a571724 (patch)
treea30071d57bdd5e876039b1cde517f02af162480f
parent6f5cdb9f833238f9bea7c403d7e0c068350a4a20 (diff)
downloadpp2cc-806e7e40726f7262b3969994238861428a571724.tar.gz
Fix some bugs in if handling, add support for ternary ?:
-rwxr-xr-xpp2cc.py58
1 files changed, 51 insertions, 7 deletions
diff --git a/pp2cc.py b/pp2cc.py
index 30dc5e0..3ae5c0a 100755
--- a/pp2cc.py
+++ b/pp2cc.py
@@ -10,7 +10,7 @@ permission. The generated output (assembly and messages) are not subject to
this license.
"""
-import sys
+import sys, re
from pycparser import c_parser, c_ast
__author__ = "Peter Wu"
@@ -123,6 +123,10 @@ class Asm(object):
indent_size = len(instruction) - len(new_instruction)
return self.format_line(new_instruction, label, indent_size)
+ def has_label(self, line):
+ """"Returns True if a line appears to contain a label, False otherwise"""
+ return Parse.is_identifier(line.split(":", 1)[0].strip())
+
def noop(self, label, register="R0"):
"""Returns a labelled no operation operator
@@ -182,6 +186,10 @@ class Logger(object):
print type + ":" + source + message
class Parse(object):
+ re_identifier = re.compile("^[0-9a-zA-Z_][0-9a-zA-Z_]*$")
+ @classmethod
+ def is_identifier(cls, text):
+ return cls.re_identifier.match(text)
def __init__(self, filename, source=''):
if source is "":
file = open(filename, 'r')
@@ -547,6 +555,42 @@ class Parse(object):
else:
raise RuntimeError("Unknown unary operator '{}'".format(op))
return lines
+ def parseTernaryOp(self, linked_node):
+ """Returns lines of ASM for ternary operation cond?expr_true:expr_false
+
+ It looks very similar to an If expect that the return value is important
+ """
+ linked_node.incrementLevel()
+ node = linked_node.node
+ lbl_el = self.uniqLbl("el") # else
+ lbl_end = self.uniqLbl("fi") # endif
+
+ lines = self.parseStatement(node.cond, linked_node)
+ lines.append(self.asm.branch_op("BEQ", lbl_el))
+
+ # if true...
+ then_block = self.parseStatement(node.iftrue, linked_node)
+ # use a single register for the result, using the one of expr_true
+ result_reg = self.registers.find_register(then_block, fatal=True)
+ lines += then_block
+ lines.append(self.asm.branch_op("BRA", lbl_end))
+
+ # else...
+ else_block = self.parseStatement(node.iffalse, linked_node)
+ assert len(else_block), "Else block is empty"
+ result_reg_else = self.registers.find_register(else_block, fatal=True)
+ # for consistency with the result of expr_true
+ if result_reg_else != result_reg:
+ lines.append(self.asm.binary_op("LOAD", result_reg, result_reg_else))
+ # add labels for the else block
+ if self.asm.has_label(else_block[0]):
+ lines.append(self.asm.noop(lbl_el))
+ else:
+ else_block[0] = self.asm.insert_label(else_block[0], lbl_el)
+ lines += else_block
+
+ lines.append(self.asm.noop(lbl_end, register=result_reg))
+ return lines
def convertInteger(self, value=None, node=None):
if value is None:
if isinstance(node, c_ast.Constant) and node.type == "int":
@@ -595,7 +639,8 @@ class Parse(object):
#lbl_if = self.uniqLbl("if") # if
#lbl_th = self.uniqLbl("th") # then
if node.iffalse:
- lbl_end = lbl_el = self.uniqLbl("el") # else
+ lbl_el = self.uniqLbl("el") # else
+ lbl_end = self.uniqLbl("fi") # endif
else:
lbl_end = lbl_fi = self.uniqLbl("fi") # endif
@@ -607,7 +652,7 @@ class Parse(object):
# lines[0] = self.asm.insert_label(lines[0], lbl_if)
# if cond is zero, go to else (BEQ branches if Z=0). Do not use CMP
- lines.append(self.asm.branch_op("BEQ", lbl_end))
+ lines.append(self.asm.branch_op("BEQ", lbl_el))
# if true...
then_block = self.parseStatement(node.iftrue, linked_node)
@@ -627,7 +672,7 @@ class Parse(object):
if self.asm.has_label(else_block[0]):
lines.append(self.asm.noop(lbl_el))
else:
- else_block[0] = self.asm.insert_label(else_block, lbl_el)
+ else_block[0] = self.asm.insert_label(else_block[0], lbl_el)
lines += else_block
# why branch if already at the end of the block? hmm
#lines.append(self.asm.branch_op("BRA", lbl_end))
@@ -682,13 +727,12 @@ class Parse(object):
raise RuntimeError("Not implemented for type " + repr(node))
elif isinstance(node, c_ast.PtrDecl):
raise RuntimeError("Not implemented for type " + repr(node))
- elif isinstance(node, c_ast.TernaryOp):
- raise RuntimeError("Not implemented for type " + repr(node))
elif isinstance(node, c_ast.While):
raise RuntimeError("Not implemented for type " + repr(node))
else:
for entry in ("Compound", "BinaryOp", "If", "Constant", "ID",
- "Return", "FuncCall", "UnaryOp", "Cast"):
+ "Return", "FuncCall", "UnaryOp", "Cast",
+ "TernaryOp"):
if isinstance(node, getattr(c_ast, entry)):
lines += getattr(self, "parse" + entry)(linked_node)
break