From 806e7e40726f7262b3969994238861428a571724 Mon Sep 17 00:00:00 2001 From: Peter Wu Date: Sat, 26 Nov 2011 22:59:58 +0000 Subject: Fix some bugs in if handling, add support for ternary ?: --- pp2cc.py | 58 +++++++++++++++++++++++++++++++++++++++++++++++++++------- 1 file 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 -- cgit v1.2.1