From fb14c03667552fe558e472056bb0b834a3652d8f Mon Sep 17 00:00:00 2001 From: Peter Wu Date: Sun, 27 Nov 2011 21:52:48 +0000 Subject: Support for break/continue --- README | 6 +++--- pp2cc.py | 45 ++++++++++++++++++++++++++++++++++++++++++++- 2 files changed, 47 insertions(+), 4 deletions(-) diff --git a/README b/README index f695e1a..fe2a379 100644 --- a/README +++ b/README @@ -85,9 +85,9 @@ A9.3 Compound statement - supported A9.4 Selection statements - if and if/else are supported, switch is not A9.5 Iteration statements - while, do/while and for are supported. A missing second expression in the for is equivalent to a non-zero constant -A9.6 Jump statements - goto is unsupported. continue, break are not supported - yet. return is supported with and without value. The function - result is undefined for the second case +A9.6 Jump statements - goto is unsupported. continue, break are supported. + return is supported with and without value. The function result is + undefined for the second case A10 External Declarations A10.1 Function Definitions - unsupported: extern static, parameters. Old style diff --git a/pp2cc.py b/pp2cc.py index bc782c3..57c53f3 100755 --- a/pp2cc.py +++ b/pp2cc.py @@ -159,6 +159,8 @@ class LinkedNode(object): self.node = node self.parent = parent self.function = None + self.break_label = None + self.continue_label = None self.level = 0 # inherit level from parent if parent: @@ -181,6 +183,23 @@ class LinkedNode(object): if hasattr(self.node, "coord"): return self.node.coord return "Unknown" + def setLoop(self, break_label, continue_label): + """Marks this node as a loop with the labels to continue after a jump + + Keywords list: + break_label -- The label to continue when using the break keyword + continue_label -- The label to continue when using the continue keyword + """ + self.break_label = break_label + self.continue_label = continue_label + def getLoopNode(self): + # continue_label is implied with break_label + if self.break_label is not None: + return self + if self.parent: + assert isinstance(self.parent, LinkedNode), "parent is not a LinkedNode!" + return self.parent.getLoopNode() + return None class Function(object): def __init__(self, node): @@ -739,18 +758,29 @@ class Parse(object): def parseDoWhile(self, linked_node): node = linked_node.node lbl_do = self.uniqLbl("do") + # used for supporting continue/break + lbl_cond = self.uniqLbl("doCond") + lbl_end = self.uniqLbl("doEnd") + linked_node.setLoop(lbl_end, lbl_doCond) + # provides a way to redo the loop lines = [self.asm.noop(lbl_do)] # do { ... }, expect do{/*empty*/} as well lines += self.parseStatement(node.stmt, linked_node) # while (...) + # used for supporting continue + lines.append(self.asm.noop(lbl_cond)) lines += self.parseStatement(node.cond, linked_node) lines.append(self.asm.branch_op("BNE", lbl_do)) + # used for supporting break + lines.append(self.asm.noop(lbl_end)) return lines def parseWhile(self, linked_node): node = linked_node.node lbl_while = self.uniqLbl("while") lbl_while_end = self.uniqLbl("whileEnd") + # used for supporting break/continue + linked_node.setLoop(lbl_while_end, lbl_while) # while ( lines = [self.asm.noop(lbl_while)] # .. @@ -774,6 +804,8 @@ class Parse(object): lines = [] lbl_for = self.uniqLbl("for") lbl_for_end = self.uniqLbl("forEnd") + # used for supporting break/continue + linked_node.setLoop(lbl_for_end, lbl_for) if node.init: # init; lines += self.parseStatement(node.init, linked_node) @@ -838,6 +870,16 @@ class Parse(object): else: lines += init_val return lines + def parseBreak(self, linked_node): + loop_node = linked_node.getLoopNode() + if not loop_node: + raise RuntimeError("break not in a loop") + return [self.asm.branch_op("BRA", loop_node.break_label)] + def parseContinue(self, linked_node): + loop_node = linked_node.getLoopNode() + if not loop_node: + raise RuntimeError("continue not in a loop") + return [self.asm.branch_op("BRA", loop_node.continue_label)] 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 @@ -850,7 +892,8 @@ class Parse(object): for entry in ("Compound", "BinaryOp", "If", "Constant", "ID", "Return", "FuncCall", "UnaryOp", "Cast", "TernaryOp", "DoWhile", "While", "For", "ExprList", - "Assignment", "Decl", "FuncDef"): + "Assignment", "Decl", "FuncDef", "Break", + "Continue"): if isinstance(node, getattr(c_ast, entry)): lines += getattr(self, "parse" + entry)(linked_node) break -- cgit v1.2.1