From eadd65d83414bb11bf1d1a821a783b716e5f0d1b Mon Sep 17 00:00:00 2001 From: Peter Wu Date: Mon, 28 Nov 2011 08:14:24 +0000 Subject: Fix bug in continue keyword in for-loop with a next expression which was never executed --- pp2cc.py | 46 ++++++++++++++++++++++++++++++++++------------ 1 file changed, 34 insertions(+), 12 deletions(-) diff --git a/pp2cc.py b/pp2cc.py index a3597aa..8e5c46d 100755 --- a/pp2cc.py +++ b/pp2cc.py @@ -196,22 +196,36 @@ 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 + def setBreak(self, break_label): + """Marks this node as a loop or switch by setting the label for break 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 + def setContinue(self, continue_label): + """Marks this node as a loop by setting the label for continue + + Keywords list: + continue_label -- The label to continue when using the continue keyword + """ self.continue_label = continue_label - def getLoopNode(self): - # continue_label is implied with break_label + def getBreakNode(self): + """Returns the label to the end of the nearest switch statement or for + loop""" 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 self.parent.getBreakNode() + return None + def getContinueNode(self): + """Returns the label to the label to continue a loop""" + if self.continue_label is not None: + return self + if self.parent: + assert isinstance(self.parent, LinkedNode), "parent is not a LinkedNode!" + return self.parent.getContinueNode() return None class Function(object): @@ -775,7 +789,8 @@ class Parse(object): # used for supporting continue/break lbl_cond = self.uniqLbl("doCond") lbl_end = self.uniqLbl("doEnd") - linked_node.setLoop(lbl_end, lbl_doCond) + linked_node.setBreak(lbl_end) + linked_node.setContinue(lbl_doCond) # provides a way to redo the loop lines = [self.asm.noop(lbl_do)] @@ -794,7 +809,8 @@ class Parse(object): lbl_while = self.uniqLbl("while") lbl_while_end = self.uniqLbl("whileEnd") # used for supporting break/continue - linked_node.setLoop(lbl_while_end, lbl_while) + linked_node.setBreak(lbl_while_end) + linked_node.setContinue(lbl_while) # while ( lines = [self.asm.noop(lbl_while)] # .. @@ -819,7 +835,12 @@ class Parse(object): lbl_for = self.uniqLbl("for") lbl_for_end = self.uniqLbl("forEnd") # used for supporting break/continue - linked_node.setLoop(lbl_for_end, lbl_for) + linked_node.setBreak(lbl_for_end) + if node.next: + lbl_cont = self.uniqLbl("forNext") + linked_node.setContinue(lbl_cont) + else: + linked_node.setContinue(lbl_for) if node.init: # init; lines += self.parseStatement(node.init, linked_node) @@ -831,6 +852,7 @@ class Parse(object): # ){ body; lines += self.parseStatement(node.stmt, linked_node) if node.next: # next; + lines.append(self.asm.noop(lbl_cont)) lines += self.parseStatement(node.next, linked_node) lines.append(self.asm.branch_op("BRA", lbl_for)) @@ -885,12 +907,12 @@ class Parse(object): lines += init_val return lines def parseBreak(self, linked_node): - loop_node = linked_node.getLoopNode() + loop_node = linked_node.getBreakNode() if not loop_node: - raise RuntimeError("break not in a loop") + raise RuntimeError("break not in a loop or switch") return [self.asm.branch_op("BRA", loop_node.break_label)] def parseContinue(self, linked_node): - loop_node = linked_node.getLoopNode() + loop_node = linked_node.getContinueNode() if not loop_node: raise RuntimeError("continue not in a loop") return [self.asm.branch_op("BRA", loop_node.continue_label)] -- cgit v1.2.1