testado o compilador do gcc com as flags -fdump-tree-cfg-graph e após isso, usado o .dot gerado para criar a visualização do grafo
para gerar uma matriz de adjacencia foi usado o dotmatrix, um conversor de .dot para uma matriz de adjacencia (é necessário retirar o lixo do .dot gerado para o input do dotmatrix, normalmente as últimas linhas apenas que são importantes)
não há muitas opções de geradores de GFC a partir de arquivos .c, e não foi achado nada que converta um código .c diretamente em uma matriz/lista de adjacencia a partir do CFG do mesmo (só com essa maracutaiazinha que eu consegui).
python:
para o python foi testado pycfg e staticfg, de antemão os dois criam grafos mais fáceis de entender do que o do gcc.
pycfg:
depois de instalar o pycfg, usa-se esse comando:
python <caminho-para-pycfg>/pycfg-0.1/pycfg/pycfg.py exemplos/2.py -d 2> <arquivo DOT de saida>
staticfg:
depois de instalar o staticfg,, usa-se esse comando (dentro do diretório ../staticfg/):
python <caminho-para-staticfg>/examples/build_cfg.py <arquivo de entrada> <arquivo de saida>
o build_cfg.py gera um cfg em um pdf e também cria um arquivo dot. As arestas são mais descritivas do que a outra opção, o que ajuda em casos no qual quer saber se a condicional foi satisfeita ou não (se o if foi pra direita ou pra esquerda).
Foi testado os arquivos dot gerados pelas três opções. Os tres foram submetidos ao dotmatrix e retornaram matrizes de adj. condizentes com o grafo de fluxo de controle esperado. (O arquivo DOT do staticfg é mais legível se deixar apenas com as linhas com "->" e sem as relações de chamada de função, talvez eu crie algo para automatizar isso)
A diferença entre eles é a quantidade de informação dentro de cada vértice, os tres são úteis para gerar a matriz de adjacência, mas o pycfg é mais útil para entender o que está acontecendo no código, já que mostra o número da linha, coisa que o staticfg não apresenta.
Comparações em trechos de código:
O arquivo DOT apresenta as labels dos vértices como as suas respectivas linhas de código.
Uma ideia é gerar a string de isomorfismo de cada código e caso sejam diferentes em apenas um trecho, apresentar as strings de cada label para o usuário.
Por exemplo:
se há um codigo com um bloco sequencial dentro de um if-else e;
um código com um loop dentro de um if-else;
teremos dois grafos que não são isomórficos mas que são muito parecidos.
Apresentar o excesso e a falta de um bloco de código para o usuário pode ajudar a entender o que está acontecendo, algo bem parecido com as comparações de versionamento de código. (provavelmente uma concatenação das labels funcione).
Caso sejam isomórficos, fazer uma comparação de labels e apresentar as diferenças.
Numa comparação de códigos, talvez seja melhor apresentar a opção em python.