LARA

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)
              }
            }
          }
        }
      }
    }
 
    // ...
  }
}