Hatena::Groupocaml-nagoya

Happy OCaml!!

2008-09-27

haXe コールグラフ

| はてなブックマーク - haXe コールグラフ - Happy OCaml!!

OCamlSpotterocamlc -dparsetreeを組合せて、haXeの各ファイルのコールグラフを作ってみた。

適当に作ったので、割と不正確。例えば、相互再帰な関数は無視してたりする。

ast.ml

f:id:mzp:20080927160024p:image:w600

codegen.ml

f:id:mzp:20080927160025p:image:w600

common.ml

f:id:mzp:20080927160026p:image:w600

genas3.ml

f:id:mzp:20080927163123p:image:w600

genjs.ml

f:id:mzp:20080927160915p:image:w600

genneko.ml

f:id:mzp:20080927160916p:image:w600

genphp.ml

f:id:mzp:20080927165158p:image:w600

genswf.ml

f:id:mzp:20080927160918p:image:w600

genswf8.ml

f:id:mzp:20080927163735p:image:w600

genswf9.ml

f:id:mzp:20080927163718p:image:w600

genxml.ml

f:id:mzp:20080927161911p:image:w600

lexer.ml

f:id:mzp:20080927161906p:image:w600

main.ml

f:id:mzp:20080927165223p:image:w600

parser.ml

f:id:mzp:20080927162338p:image:w600

type.ml

f:id:mzp:20080927162105p:image:w600

typecore.ml

f:id:mzp:20080927162103p:image:w600

typeload.ml

f:id:mzp:20080927162238p:image:w600

typer.ml

f:id:mzp:20080927165943p:image:w600

コールグラフ生成プログラム

| はてなブックマーク - コールグラフ生成プログラム - Happy OCaml!!

コールグラフを作るときに使ったやつ。

class Loc
  attr_reader :line,:start,:pos
  def self.make(line,start,delta)
    new(line.to_i,start.to_i,start.to_i + delta.to_i)
  end

  def initialize(line,start,pos)
    @line = line
    @start= start
    @pos  = pos
  end
end

class Block
  attr_reader :from,:to,:name,:irefs,:erefs
  attr_writer :name

  def initialize(from,to)
    @from = from
    @to   = to
    @irefs = []
    @erefs = []
  end

  def contain?(loc)
    @from.pos <= loc.pos && loc.pos <= @to.pos
  end

  def <=>(o)
    self.from.pos <=> o.from.pos
  end
end

class DumpTree
  include Enumerable
  def self.parse(io)
    blocks = []

    io.read.scan(/structure_item \(([^\]]+)\[(\d+),(\d+)\+(\d+)\]\.\.\1\[(\d+),(\d+)\+(\d+)\]\)
    Pstr_value/) do|x|
      file,from_line,from_start,from_pos,to_line,to_start,to_pos = x
      from = Loc.make from_line,from_start,from_pos
      to   = Loc.make to_line,to_start,to_pos
      blocks << Block.new(from,to)
    end

    self.new blocks
  end

  def initialize(blocks)
    @blocks = blocks
  end

  def each(&f)
    @blocks.each(&f)
  end
end

class Annot
  include Enumerable

  Def     = Struct.new 'Def'   ,:name,:loc
  IntRef  = Struct.new 'IntRef',:to,:loc
  ExtRef  = Struct.new 'ExtRef',:name,:loc

  def self.parse(io)
    annot = []
    io.read.scan(/^"[^"]+" (\d+) (\d+) (\d+).*
type\(
.*
\)
ident\(
\s*(.*)
\)/) do|x| # "
      loc = Loc.new(x[0].to_i,x[1].to_i,x[2].to_i)
      case x[-1]
      when /\Adef (\w*)/
        annot << Def.new($1,loc)
      when /\Aint_ref .* "[^"]+" (\d+) (\d+) (\d+)/
        annot << IntRef.new(Loc.new($1.to_i,$2.to_i,$3.to_i),loc)
      when /\Aext_ref (.*)/
        annot << ExtRef.new($1,loc)
      end
    end

    new(annot)
  end

  def initialize(annot)
    @annot = annot
  end

  def each(&f)
    @annot.each(&f)
  end
end

require 'pp'
blocks  = DumpTree.parse(File.open(ARGV[0]))
annot_file = Annot.parse(File.open(ARGV[1]))

blocks.each do|block|
  annots = annot_file.select{|a| block.contain? a.loc }
  block.name = annots.first.name
  
  annots.each do|annot|
    case annot
    when Annot::IntRef
      block.irefs << blocks.find{|b| b.contain? annot.to }
    when Annot::ExtRef
      block.erefs << annot.name
    end
  end
end

# post process
blocks.each do|block|
  block.erefs.sort!.uniq!
  block.irefs.sort!.uniq!
end

# draw
puts 'digraph call {'
blocks.each do|block|
  block.irefs.each do|ref|
    puts %("#{block.name}" -> "#{ref.name}")
  end

  block.erefs.each do|ref|
    puts %("#{block.name}" -> "#{ref}")
  end
end
puts '}'

動かすシェルスクリプト。

#!/bin/sh
for i in *.ml; do
    basename=$(basename $i .ml)
    echo $basename
    ocamlc -dparsetree $i > $basename.dump 2>&1
    ruby ~/c/junk/2008/09/2008-09-27-120140.rb ${basename}.dump ${basename}.annot > ${basename}.dot
    dot -Tpng -o ${basename}.png ${basename}.dot
done

osiireosiire2008/09/28 22:08すばらしい。よく作ったね。genxmlなんかは高階関数が関数同士の「糊」になっている様が見て取れる気がします。
スタンダードライブラリの関数は除外すると、もう少し見やすくなるかも。

mzpmzp2008/09/29 10:32ありがとうございます。OCamlSpotterのおかげで割と簡単にできました。
標準関数の無視はあとでやってみます。

camlspottercamlspotter2009/07/24 17:36今更ながら見つけました。これはいいですねぇ。

fcdcwompxhfcdcwompxh2011/03/07 15:02S7wnS4 <a href="http://ocnllpfjaxlr.com/">ocnllpfjaxlr</a>, [url=http://uryosicjcriq.com/]uryosicjcriq[/url], [link=http://nkcsfliwazwh.com/]nkcsfliwazwh[/link], http://hkkxvwksjwwa.com/

MirannarahMirannarah2012/12/08 01:32A few years ago I'd have to pay someone for this ifnoramtion.

ZiggyZiggy2012/12/08 06:08Your answer shows real inetlligecne.

loyavziloyavzi2012/12/10 00:15FmsCpG , [url=http://iagsgsbqzift.com/]iagsgsbqzift[/url], [link=http://mfcodutxnrtd.com/]mfcodutxnrtd[/link], http://lelwtyujjoid.com/

adozvvwkdadozvvwkd2012/12/11 15:54BJejLm <a href="http://rjpyghsecyya.com/">rjpyghsecyya</a>

qujpzygpqujpzygp2012/12/29 21:28XU76bU , [url=http://cqurlipqoevq.com/]cqurlipqoevq[/url], [link=http://ammwjjkxfxiu.com/]ammwjjkxfxiu[/link], http://tqcopnixlamf.com/

aquplaljmodaquplaljmod2012/12/30 04:063FfWDf <a href="http://ojnzdurkhkqh.com/">ojnzdurkhkqh</a>

inobthsinobths2012/12/30 12:25AdKDfV , [url=http://nbidwruzaonz.com/]nbidwruzaonz[/url], [link=http://movkumovtysa.com/]movkumovtysa[/link], http://awdgavxekdge.com/

opmkmfopmkmf2013/01/17 15:09IQGAY0 <a href="http://hqhlglkkrgac.com/">hqhlglkkrgac</a>

opmkmfopmkmf2013/01/17 15:10IQGAY0 <a href="http://hqhlglkkrgac.com/">hqhlglkkrgac</a>

zurkwlizurkwli2013/01/17 19:57I0i1gS , [url=http://rwqcnanxqymg.com/]rwqcnanxqymg[/url], [link=http://pkfhsfybnfhb.com/]pkfhsfybnfhb[/link], http://rwwduolulacq.com/

oqrdiikxoqrdiikx2013/01/18 05:19nnBZY3 <a href="http://ovkknnbjoebo.com/">ovkknnbjoebo</a>

lhtyraxjnflhtyraxjnf2013/01/19 02:368gwctC , [url=http://zmhnlsdtpupj.com/]zmhnlsdtpupj[/url], [link=http://hcyssmewslhw.com/]hcyssmewslhw[/link], http://zeugxvrfqtba.com/