class Bpl::CfgConstruction

Public Instance Methods

run!(program) click to toggle source
# File lib/bpl/passes/analysis/cfg_construction.rb, line 11
def run! program
  program.each do |b|
    next unless b.is_a?(Block)
    successors[b] = Set.new
    predecessors[b] = Set.new
  end

  program.each do |elem|
    next unless elem.is_a?(GotoStatement)
    if block = elem.each_ancestor.find {|b| b.is_a?(Block)}
      elem.identifiers.each do |id|
        if id.declaration
          predecessors[id.declaration] << block
          successors[block] << id.declaration
        end
      end
    end
  end

  if print
    require 'graphviz'

    program.each_child do |decl|
      next unless decl.is_a?(ProcedureDeclaration)
      next unless decl.body
      cfg = ::GraphViz.new(decl.name, type: :digraph)
      cfg.add_nodes(decl.body.blocks.map(&:name), shape: :rect)
      decl.body.blocks.each do |b|
        cfg.add_edges("entry", b.name) if predecessors[b].empty?
        if b.statements.last.is_a?(ReturnStatement) ||
          !b.statements.last.is_a?(GotoStatement) && successors[b].empty?
        then
          cfg.add_edges(b.name, "return")
        end
        successors[b].each do |c|
          cfg.add_edges(b.name,c.name)
        end
      end
      cfg.output(pdf: "#{decl.name}.cfg.pdf")
    end
  end

end