def ConvertShortCircuitIf(if_stmt: c_ast.If, parent: c_ast.Node, id_gen: common.UniqueId): cond = if_stmt.cond if isinstance(cond, c_ast.UnaryOp) and cond.op == "!": # for a not not just swap the branches if_stmt.cond = cond.expr if_stmt.iffalse, if_stmt.iftrue = if_stmt.iftrue, if_stmt.iffalse ConvertShortCircuitIf(if_stmt, parent, id_gen) return if not isinstance(cond, c_ast.BinaryOp): return if cond.op != "&&" and cond.op != "||": return labelnext = id_gen.next("branch") if cond.op == "&&": if_stmt2 = c_ast.If(cond.left, c_ast.Goto(labelnext), if_stmt.iffalse) else: assert cond.op == "||" if_stmt2 = c_ast.If(cond.left, if_stmt.iftrue, c_ast.Goto(labelnext)) if_stmt.cond = cond.right stmts = common.GetStatementList(parent) # this is easy to fix but basically guaranteed after running IfTransform assert stmts, parent pos = stmts.index(if_stmt) stmts[pos:pos + 1] = [if_stmt2, c_ast.Label(labelnext, c_ast.EmptyStatement()), if_stmt] ConvertShortCircuitIf(if_stmt2, parent, id_gen) ConvertShortCircuitIf(if_stmt, parent, id_gen)
def ConvertWhileLoop(ast, id_gen: common.UniqueId): def IsWhileLoop(node, _): return isinstance(node, (c_ast.DoWhile, c_ast.While)) candidates = common.FindMatchingNodesPostOrder(ast, ast, IsWhileLoop) for node, parent in candidates: loop_label = id_gen.next("while") test_label = loop_label + "_cond" exit_label = loop_label + "_exit" conditional = c_ast.If(node.cond, c_ast.Goto(loop_label), None) block = [c_ast.Label(loop_label, c_ast.EmptyStatement()), node.stmt, c_ast.Label(test_label, c_ast.EmptyStatement()), conditional, c_ast.Label(exit_label, c_ast.EmptyStatement())] if isinstance(node, c_ast.While): block = [c_ast.Goto(test_label)] + block common.ReplaceBreakAndContinue(node.stmt, node, test_label, exit_label) common.ReplaceNode(parent, node, c_ast.Compound(block))
def ConvertForLoop(ast, id_gen: common.UniqueId): candidates = common.FindMatchingNodesPostOrder( ast, ast, lambda n, _: isinstance(n, c_ast.For)) for node, parent in candidates: loop_label = id_gen.next("for") next_label = loop_label + "_next" test_label = loop_label + "_cond" exit_label = loop_label + "_exit" goto = c_ast.Goto(loop_label) conditional = c_ast.If(node.cond, goto, None) if node.cond else goto block = ExtractForInitStatements(node.init) + [ c_ast.Goto(test_label), c_ast.Label(loop_label, c_ast.EmptyStatement()), node.stmt, c_ast.Label(next_label, c_ast.EmptyStatement()), node.next if node.next else c_ast.EmptyStatement(), c_ast.Label(test_label, c_ast.EmptyStatement()), conditional, c_ast.Label(exit_label, c_ast.EmptyStatement()) ] common.ReplaceBreakAndContinue(node.stmt, node, next_label, exit_label) common.ReplaceNode(parent, node, c_ast.Compound(block))
def ConvertToGotos(if_stmt: c_ast.If, parent, id_gen: common.UniqueId): if (isinstance(if_stmt.iftrue, c_ast.Goto) and isinstance(if_stmt.iffalse, c_ast.Goto) and not isinstance(if_stmt.cond, c_ast.ExprList)): return label = id_gen.next("if") labeltrue = label + "_true" labelfalse = label + "_false" labelend = label + "_end" emptytrue = common.IsEmpty(if_stmt.iftrue) or isinstance(if_stmt.iftrue, c_ast.Goto) emptyfalse = common.IsEmpty(if_stmt.iffalse) or isinstance(if_stmt.iffalse, c_ast.Goto) seq: List[c_ast.Node] = [] # TODO: this should be done in EliminateExpressionLists( if isinstance(if_stmt.cond, c_ast.ExprList): exprs = if_stmt.cond.exprs if_stmt.cond = exprs.pop(-1) seq += exprs seq.append(if_stmt) if not emptytrue: seq += [c_ast.Label(labeltrue, c_ast.EmptyStatement()), if_stmt.iftrue] if not emptyfalse: seq.append(c_ast.Goto(labelend)) if not emptyfalse: seq += [c_ast.Label(labelfalse, c_ast.EmptyStatement()), if_stmt.iffalse] seq.append(c_ast.Label(labelend, c_ast.EmptyStatement())) if not isinstance(if_stmt.iftrue, c_ast.Goto): if_stmt.iftrue = c_ast.Goto(labelend if emptytrue else labeltrue) if not isinstance(if_stmt.iffalse, c_ast.Goto): if_stmt.iffalse = c_ast.Goto(labelend if emptyfalse else labelfalse) stmts = common.GetStatementList(parent) if not stmts: stmts = [if_stmt] parent = common.ReplaceNode(parent, if_stmt, c_ast.Compound(stmts)) pos = stmts.index(if_stmt) stmts[pos: pos + 1] = seq
def ReplaceBreakAndContinue(node, parent, test_label, exit_label): """ Starting at `node` recursively replace all `continue` statements with `goto test_label` and all `break` statements with `goto exit_label` """ if isinstance(node, c_ast.Continue): ReplaceNode(parent, node, c_ast.Goto(test_label)) return if exit_label and isinstance(node, c_ast.Break): ReplaceNode(parent, node, c_ast.Goto(exit_label)) return if isinstance(node, (c_ast.While, c_ast.DoWhile, c_ast.For)): # do not recurse into other loops return if isinstance(node, c_ast.Switch): # `break`s inside switches have their own meaning but we still need to replace `continue`s exit_label = None for c in node: ReplaceBreakAndContinue(c, node, test_label, exit_label)
def generic_visit(self, node): for ci, (c_name, c) in enumerate(node.children()): self.visit(c) # If child is sliced, then mark this as well if c.sliced: node.sliced = True # If adding an assignment, ensure that it is declared by adding lvalue # to dependency list # FIXME: Only need to declare this variable, not handle all its dependences if isinstance(node, c_ast.Assignment): self.id_visitor.new_visit(node.lvalue) self.rvalues += self.id_visitor.IDs """ print "Adding to slice:" print_node(node) print "because child is in slice:" print_node(c) print """ # Always include Returns, change them to Goto end of function if isinstance(c, c_ast.Return): # Create a new compound node insert_node = c_ast.Compound([]) """ # If there is a return value, add statement for return_value = value if c.expr: ret_id = c_ast.ID("return_value") ret_id.sliced = True assignment = c_ast.Assignment("=", ret_id, c.expr) assignment.sliced = True insert_node.block_items.append(assignment) """ # Goto end of function goto = c_ast.Goto(self.end_label) goto.sliced = True insert_node.block_items.append(goto) insert_node.sliced = True # Add compound node back to function if isinstance(node, c_ast.Compound): node.block_items[ci] = insert_node elif isinstance(node, c_ast.If): exec("node.%s = insert_node" % c_name) elif isinstance(node, c_ast.Case): node.stmts[ci - 1] = insert_node else: print_node(node) node.show(nodenames=True, showcoord=True) raise Exception( "Unsupported parent node type %s. Please implement." % (type(node)))
def generic_visit(self, node): for ci, (c_name, c) in enumerate(node.children()): # Return statement if isinstance(c, c_ast.Return): # Create a new compound node insert_node = c_ast.Compound([]) # If there is a return value, add statement for return_value = value if c.expr: insert_node.block_items.append(c_ast.Assignment("=", c_ast.ID("return_value"), c.expr)) # Add goto to end of function block insert_node.block_items.append(c_ast.Goto(self.goto_name)) # Replace original node with new node replace_node(node, insert_node, ci, c_name) # Non-return statement, continue visiting else: self.visit(c)
def do_jump(**kw): #goto {loc} # fmt_op returns an ID but Goto takes a bare string return c_ast.Goto(kw['loc'].name)