package minijava.controlflow object ASTtoCFG { import parser.Trees._ import analyzer.Symbols._ import analyzer.Types._ import CFGTrees._ /** Builds a control flow graph from a method declaration. */ def convertAST(meth: MethodDecl): CFG = { val cfg: CFG = new CFG type Vertex = cfg.Vertex /** Creates fresh variable names on demand. */ object FreshName { var count = 0 def apply(prefix: String): String = { val post = count count = count + 1 prefix + "#" + post } } /** Creates fresh variable tree nodes on demand. */ object FreshVariable { def apply(prefix: String, tpe: Type) = CFGTempID(FreshName(prefix)).setType(tpe) } /** Helper to add edges and vertices to the nascent CFG while maintaining * the current "program counter", that is, the point from which the rest * of the graph should be built. */ object Emit { private var pc: Vertex = cfg.entry def getPC: Vertex = pc def setPC(v: Vertex) = { pc = v } // emits a statement between two program points def statementBetween(from: Vertex, stat: CFGStatement, to : Vertex): Unit = { cfg += (from, stat, to) } // emits a statement from the current PC and sets the new PC after it def statement(stat: CFGStatement): Unit = { val v = cfg.newVertex cfg += (pc, stat, v) setPC(v) } // emits a statement from the current PC to an existing program point def statementCont(stat: CFGStatement, cont: Vertex) = { cfg += (pc, stat, cont) } // emits an ''empty'' statement (equivalent to unconditional branch) from the current PC to an existing point def goto(cont: Vertex) = { cfg += (pc, CFGSkip, cont) } } /** Generates the part of the graph corresponding to the branching on a conditional expression */ def condExpr(ex: ExprTree, falseCont: Vertex, trueCont: Vertex): Unit = { // should have been enforced by type checking. assert(ex.getType == TBoolean) ex match { // ... } } /** Emits the proper statemtents to flatten out the expression and to assign it to lhs. */ def exprStore(lhs: CFGVariable, ex: ExprTree) = ex match { // ... } /** Transforms an identifier from the AST to one for the CFG. */ def idFromId(id: Identifier): CFGIdentifier = { // should be enforced by type checking and by construction assert(id.getSymbol.isInstanceOf[VariableSymbol]) CFGIdentifier(id.getSymbol.asInstanceOf[VariableSymbol]).setPos(id) } /** If an expression can be translated without flattening, does it and * returns the result in a Some(...) instance. Otherwise returns None. */ def alreadySimple(ex: ExprTree): Option[CFGSimpleValue] = ex match { // ... } /** Flattens complex expressions, or simply returns simple ones. */ def expr(ex: ExprTree): CFGSimpleValue = alreadySimple(ex) match { // ... } /** Emits a sequence of statements. */ def stmts(sts: List[StatTree], cont: Vertex): Unit = sts match { // ... } /** Emits a single statement. cont = where to continue after the statement */ def stmt(s: StatTree, cont: Vertex): Unit = s match { // ... } /** Removes useless Skip edges by short-circuiting them. */ def fewerSkips = { for (v <- cfg.V) { if ((v != cfg.entry) && (v != cfg.exit) && (v.out.size == 1)) { for (eOut <- v.out) { if (eOut.lab == CFGSkip) { for (eIn <- v.in) { // remove old edge cfg -= (eIn.v1, eIn.lab, eIn.v2) cfg -= (eOut.v1, eOut.lab, eOut.v2) // insert new edge with label of incoming one cfg += (eIn.v1, eIn.lab, eOut.v2) } } } } } } // ... } }