summaryrefslogtreecommitdiff
path: root/pp2cc.py
diff options
context:
space:
mode:
authorPeter Wu <lekensteyn@gmail.com>2011-11-27 21:52:48 +0000
committerPeter Wu <lekensteyn@gmail.com>2011-11-27 21:52:48 +0000
commitfb14c03667552fe558e472056bb0b834a3652d8f (patch)
tree951c465fa67be041d18f783adb5862e4cc138b3e /pp2cc.py
parent0ac605d5a09ba80615b2e0c151f31741168e6d2d (diff)
downloadpp2cc-fb14c03667552fe558e472056bb0b834a3652d8f.tar.gz
Support for break/continue
Diffstat (limited to 'pp2cc.py')
-rwxr-xr-xpp2cc.py45
1 files changed, 44 insertions, 1 deletions
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