def visit_FuncDef(self, node): # Skip if no loop counters exist if self.loop_counter_size == 0: return # Create loop_counter declaration/initialization constants = [c_ast.Constant("int", '0') for i in range(self.loop_counter_size)] init_list = c_ast.InitList(constants) identifier_type = c_ast.IdentifierType(["int"]) type_decl = c_ast.TypeDecl("loop_counter", [], identifier_type) dim = c_ast.Constant("int", str(self.loop_counter_size)) array_decl = c_ast.ArrayDecl(type_decl, dim, []) decl = c_ast.Decl("loop_counter", [], [], [], array_decl, init_list, None) node.body.block_items.insert(0, decl) # Label for return values to goto start_label = c_ast.Label("print_loop_counter", c_ast.EmptyStatement()) # Start and end labels used for inserting preprocessor commands for #if DEBUG_EN end_label = c_ast.Label("print_loop_counter_end", c_ast.EmptyStatement()) # Write to file if self.write_to_file: stmt = c_ast.ID("write_array(loop_counter, %d)\n" % (self.loop_counter_size)) compound = c_ast.Compound([start_label, stmt, end_label]) # Print to stdout else: # Add printf to the end of function # Start of printing stmt_start = c_ast.ID("printf(\"loop counter = (\")") # For loop # int i; identifier_type = c_ast.IdentifierType(["int"]) type_decl = c_ast.TypeDecl("i", [], identifier_type) for_decl = c_ast.Decl("i", [], [], [], type_decl, [], None) # i = 0 init = c_ast.Assignment("=", c_ast.ID("i"), c_ast.Constant("int", '0')) # i < self.loop_counter_size cond = c_ast.BinaryOp("<", c_ast.ID("i"), c_ast.Constant("int", str(self.loop_counter_size))) # i++ next_stmt = c_ast.UnaryOp("p++", c_ast.ID("i")) # printf in for stmt = c_ast.ID("printf(\"%d, \", loop_counter[i])") # Cosntruct for loop stmt_for = c_ast.For(init, cond, next_stmt, stmt) # End of printing stmt_end = c_ast.ID("printf(\")\\n\")") # Put it all together body = c_ast.Compound([stmt_start, for_decl, stmt_for, stmt_end]) # Surround with labels compound = c_ast.Compound([start_label, body, end_label]) node.body.block_items.append(compound)
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 visit_FuncDef(self, node): label = c_ast.Label("predict_exec_time", c_ast.EmptyStatement()) decl = c_ast.Decl("exec_time", None, None, None, c_ast.TypeDecl("exec_time", None, c_ast.IdentifierType(["float"])), None, None) assignment = c_ast.Assignment('=', c_ast.ID("exec_time"), c_ast.Constant("int", 0)) ret = c_ast.Return(c_ast.ID("exec_time")) compound = c_ast.Compound([label, decl, assignment, ret]) node.body.block_items.append(compound)
def callback(expr: ca.Node, is_expr: bool) -> Optional[ca.Node]: if indices[expr] in repl_cands_set: return copy.deepcopy(repl_expr) if expr == write and isinstance(write, ca.Assignment) and not keep_var: if is_expr: return write.lvalue else: return ca.EmptyStatement() return None
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 generic_visit(self, node): #print(node.coord) if (isinstance(node, c_ast.If)): if (node.iftrue and not (isinstance(node.iftrue, c_ast.Compound))): node.iftrue = c_ast.Compound([node.iftrue]) if (node.iffalse and not (isinstance(node.iffalse, c_ast.Compound))): node.iffalse = c_ast.Compound([node.iffalse]) elif (node.iffalse == None): node.iffalse = c_ast.Compound([c_ast.EmptyStatement()]) elif (isinstance(node, c_ast.For)): if (node.stmt and not (isinstance(node.stmt, c_ast.Compound))): node.stmt = c_ast.Compound([node.stmt]) for c_name, c in node.children(): self.visit(c)
def _pt_trash(self, node): if self._rounds == 0: return c_ast.EmptyStatement() filename = random.choice(random.choice(self._patterns)) with open(filename) as f: ast = self._parser.parse(f.read()) code = None for child in ast.ext: if type(child) == c_ast.FuncDef and child.decl.name == 'pattern': code = child.body pattern = PatternVisitor(self._patterns, self._rounds - 1, node) pattern.visit(code) self._pt_add_decls(pattern.decls) elif type(child) == c_ast.Decl and type( child.type) == c_ast.FuncDecl: self._pt_add_decls([child]) assert code, 'Invalid pattern: {}'.format(filename) return code
def generate_code(request, response): for proto_file in request.proto_file: output = [] ast = c_ast.FileAST([]) generator = c_generator.CGenerator() ast.ext += [c_ast.EmptyStatement()] # Parse request for item, package in traverse(proto_file): data = { 'package': proto_file.package or '<root>', 'filename': proto_file.name, 'name': item.name, } if isinstance(item, DescriptorProto): data.update({ 'type': 'Message', 'properties': [{'name': f.name, 'type': int(f.type)} for f in item.field] }) elif isinstance(item, EnumDescriptorProto): data.update({ 'type': 'Enum', 'values': [{'name': v.name, 'value': v.number} for v in item.value] }) output.append(data) # Fill response f = response.file.add() f.name = proto_file.name + '.c' f.content = generator.visit(ast)
def _pt_assign_choise(self, node): return c_ast.EmptyStatement()
def do_nop(**kw): return c_ast.EmptyStatement()
def __init__(self): astnode = c_ast.EmptyStatement() super().__init__(astnode)
def ast_to_cfg(self, ast: c_ast.Node) -> (c_ast.Node, c_ast.Node): """Recursively compute the CFG from a AST. Given a AST node (can be any complex structure) the function will return the first and last nodes of the CFG in a tuple and will modify `cfg` adding the corresponding nodes and edges representing the final CFG. Parameters ---------- ast : pycparser.c_ast.Node to be translated into a CFG Returns ------- A tuple with references to the first and last element of the CFG """ typ = type(ast) entrynode = ControlFlowGraph.EntryNode() exitnode = ControlFlowGraph.ExitNode() self.add_node(entrynode) self.add_node(exitnode) # A c_ast.If in CFG is: # cfg(body.true) # / \ # if(cond) endif* # \ / # ---------------------- # # returns (if(c), endif) if typ == c_ast.If: astif = c_ast.If(ast.cond, None, None, coord=ast.coord) if_start = ControlFlowGraph.IfNode(astif) self.add_node(if_start) self.add_edge(entrynode, if_start) true_branch_body_entry, true_branch_body_exit = self.ast_to_cfg(ast.iftrue) asserttrue = ControlFlowGraph.AssertNode(ast.cond) self.add_node(asserttrue) self.add_edge(if_start, asserttrue) self.add_edge(asserttrue, true_branch_body_entry) self.join_adjacents_and_merge(asserttrue, removed_node=true_branch_body_entry) self.join_adjacents_and_merge(exitnode, removed_node=true_branch_body_exit) if ast.iffalse is not None: false_branch_body_start, false_branch_body_last = self.ast_to_cfg(ast.iffalse) if self.iffalse: assertfalse = ControlFlowGraph.AssertNode(c_ast.UnaryOp("!", ast.cond)) self.add_node(assertfalse) self.add_edge(if_start, assertfalse) self.add_edge(assertfalse, false_branch_body_start) else: self.add_edge(if_start, false_branch_body_start) self.join_adjacents_and_merge(assertfalse, removed_node=false_branch_body_start) self.join_adjacents_and_merge(exitnode, removed_node=false_branch_body_last) else: if self.iffalse: assertfalse = ControlFlowGraph.AssertNode(c_ast.UnaryOp("!", ast.cond)) self.add_node(assertfalse) self.add_edge(if_start, assertfalse) self.add_edge(assertfalse, exitnode) else: self.add_edge(if_start, exitnode) # A c_ast.While in CFG is: # cfg(body) # / \ # while(c) endwhile* -->--+ # ^ \ / | # | ---->---- | # +----------------------------+ # # returns (while(c), endwhile*) elif typ == c_ast.While: while_body_entry, while_body_exit = self.ast_to_cfg(ast.stmt) astwhile = c_ast.While(ast.cond, None, coord=ast.coord) whilenode = ControlFlowGraph.Node(astwhile) self.add_node(whilenode) self.add_edge(whilenode, exitnode) self.add_edge(entrynode, whilenode) asserttrue = ControlFlowGraph.AssertNode(ast.cond) self.add_node(asserttrue) self.add_edge(whilenode, asserttrue) self.add_edge(asserttrue, while_body_entry) self.join_adjacents_and_merge(asserttrue, removed_node=while_body_entry) # In a while the last statement return to the while condition if self.loop: self.join_adjacents_and_merge(whilenode, removed_node=while_body_exit) else: self.join_adjacents_and_merge(exitnode, removed_node=while_body_exit) # A c_ast.Compound in CFG is: # # cfg(block(1)) --> cfg(block(2)) --> ... --> cfg(block(n)) # # return (cfg(block(1)).first, cfg(block(n)).last) elif typ == c_ast.Compound: items = ast.block_items if items is not None: first_node = items[0] first_node_entry, prev_node_exit = self.ast_to_cfg(first_node) self.join_adjacents_and_merge(entrynode, removed_node=first_node_entry) if len(items) > 1: for i in items[1:-1]: i_node_entry, i_node_exit = self.ast_to_cfg(i) self.join_adjacents_and_remove(prev_node_exit, i_node_entry) prev_node_exit = i_node_exit last_node = items[-1] last_node_entry, last_node_exit = self.ast_to_cfg(last_node) self.join_adjacents_and_remove(prev_node_exit, last_node_entry) else: last_node = first_node last_node_exit = prev_node_exit self.join_adjacents_and_merge(exitnode, removed_node=last_node_exit) else: noopnode = ControlFlowGraph.Node(c_ast.EmptyStatement(coord=ast.coord)) self.add_node(noopnode) self.add_edge(entrynode, noopnode) self.add_edge(noopnode, exitnode) # A c_ast.Compound in CFG is: # # function.name --> cfg(function.body).first # # return (function.name, cfg(function.body).last) elif typ == c_ast.FuncDef: (first_body, last_body) = self.ast_to_cfg(ast.body) astfuncdef = c_ast.FuncDef(ast.decl, ast.param_decls, None, coord=ast.coord) funcdefnode = ControlFlowGraph.Node(astfuncdef) self.add_node(funcdefnode) self.add_edge(entrynode, funcdefnode) self.add_edge(last_body, exitnode) # we insert the FuncDef body CFG discarding its entry and exit nodes self.join_adjacents_and_merge(funcdefnode, removed_node=first_body) self.join_adjacents_and_merge(exitnode, removed_node=last_body) else: basicnode = ControlFlowGraph.Node(ast) self.add_node(basicnode) self.add_edge(entrynode, basicnode) self.add_edge(basicnode, exitnode) return entrynode, exitnode
def create_inline_function(self, function, caller): """ Create a modified version of the passed function that can be inlined. """ # Create a copy of the function function_copy = copy.deepcopy(function) # Find all declared variables and rename them to prevent aliasing with upper-level self.decl_visitor = GetDeclVisitor() self.decl_visitor.visit(function_copy.body) for decl in self.decl_visitor.decls: self.rename_visitor.new_visit(decl, decl + "_rename%d" % self.rename_counter, function_copy) ################################### # Function Arguments ################################### function_copy.body.block_items.insert(0, c_ast.ID("// End of arguments")) args = [] ptr_args = [] # If it has arguments if function_copy.decl.type.args: # For each function argument and passed value for (arg, init) in zip(function_copy.decl.type.args.params, caller.args.exprs): # Pointers just get renamed, no re-declare if isinstance(arg.type, c_ast.PtrDecl): # Add pointer name to list if isinstance(init, c_ast.UnaryOp): ptr_args.append((self.get_Decl_name(arg), init.expr.name)) elif isinstance(init, c_ast.StructRef): ptr_args.append((self.get_Decl_name(arg), self.cgenerator.visit(init))) elif isinstance(init, c_ast.ID): ptr_args.append((self.get_Decl_name(arg), init.name)) elif isinstance(init, c_ast.ArrayRef): ptr_args.append((self.get_Decl_name(arg), init)) else: raise Exception("Unsupported init type %s" % (type(init))) # Arrays also get renamed, no re-declare elif isinstance(arg.type, c_ast.ArrayDecl): ptr_args.append((self.get_Decl_name(arg), init)) else: # Assign passed value to argument declaration arg.init = init # Save list of argument name for renaming arg_name = self.get_Decl_name(arg) args.append(arg_name) # Rename arguments to prevent aliasing with upper-level self.rename_visitor.new_visit(arg_name, arg_name + "_rename%d" % self.rename_counter, function_copy.body) self.set_Decl_name(arg, arg_name + "_rename%d" % self.rename_counter) # Insert into start of function function_copy.body.block_items.insert(0, arg) # Rename pointers and arrays to the passed variable for arg in ptr_args: self.rename_visitor.new_visit(arg[0], arg[1], function_copy) # Increment rename counter to ensure unique names self.rename_counter += 1 # Add declaration for return value (if function is non-void) if self.get_Function_type(function_copy) != "void": # Copy the function type declaration typedecl = copy.deepcopy(function.decl.type.type) # Create a variable declaration using the function type decl = c_ast.Decl(None, None, None, None, typedecl, None, None) # Replace the variable name as return_value self.set_Decl_name(decl, "return_value") # Insert the return_value declaration at the start of the function function_copy.body.block_items.insert(0, decl) function_copy.body.block_items.insert(0, c_ast.ID("// Inline function: %s" % (function_copy.decl.name))) ################################### # Return statements ################################### # Replace returns with goto statement return_label = "return%d" % (self.return_counter) self.return_counter += 1 self.rtg_visitor.new_visit(return_label, function_copy) # Create label for goto function_copy.body.block_items.append(c_ast.Label(return_label, c_ast.EmptyStatement())) return function_copy
# Generate AST ast = parse_file(filename, use_cpp=True) # Find all defined functions v = GetFunctionsVisitor() v.visit(ast) functions = v.funcs # Remove function calls from being embedded in conditionals v = GetFuncDeclVisitor() v.visit(ast) v = RemoveIfFunctionVisitor(v.func_decls) v.visit(ast) # Inline functions v = ExpandFunctionVisitor(top_func, functions) v.visit(ast) # Keep performing until no changes while v.expanded: v.expanded = False v.visit(ast) # Print out non-function top-levels for c_name, c in ast.children(): if not isinstance(c, c_ast.FuncDef): print_node(c) print_node(c_ast.EmptyStatement()) # Print out top-level function for function in functions: if function.decl.name == top_func: print_node(function)