Este artigo é sobre como usar a popular ferramenta gráfica Graphviz em cooperação com o pré-processador C / C ++ (a seguir denominado simplesmente de pré-processador).
O ponto principal é que a linguagem do gráfico de pontos usada pelo Graphviz é sintaticamente adequada para processamento por um pré-processador. Tão concebido pelos desenvolvedores. Graças à sua visão, podemos usar os seguintes recursos ao descrever gráficos (cito a partir da Wikipedia de memória):
- substituir os digrafos e trigramas correspondentes pelos caracteres equivalentes "#" e "\";
- remoção de caracteres de avanço de linha com escape;
- substituindo comentários de linha e bloco por linhas vazias (com a remoção de espaços e guias ao redor);
- inserção (inclusão) do conteúdo de um arquivo arbitrário ( #include );
- substituição de macro ( #define );
- compilação condicional ( #if, #ifdef, #elif, #else, #endif );
Agora vamos demonstrar as oportunidades abertas na prática. Como exemplo, veja o gráfico do meu artigo no MediaStrimer2 , que está na figura abaixo.

O gráfico é grande o suficiente e, se você o descrever “na testa”, será necessário muito trabalho manual sem erros. Se você observar atentamente, poderá isolar elementos repetidos com uma diferença apenas no conteúdo de alguns campos. É assim que os nós do gráfico se parecem com m 1, m2, m2_1, m2_2, m3, m4 . Estes são os primeiros candidatos ao uso de pequenas mecanizações usando macros. Crie um arquivo de cabeçalho para o nosso arquivo de ponto principal. Vamos chamá-lo de common.dot :
#define Q(x) #x
#define QUOTE(x) Q(x)
#define msg_staff \
<p> *prev \
|<n> *next \
|<c> *cont \
|<d> *data \
| other\nstuff
#define msg(name, ... ) \
name[xlabel=mblk_t label=QUOTE(<h> name | msg_staff) \
];
#define dbuf(name ...) \
name[label=QUOTE(<h> name) xlabel="dblk_t"];
#define queue(name, ...) \
name[ xlabel="queue_t" label=QUOTE(<h> name | \
msg_staff)];
Agora é hora de escrever o arquivo gráfico principal. Vamos chamá-lo de my_graph.dot :
#include "common.dot"
digraph queue_demo
{
rankdir=LR;
node[shape=Mrecord];
dbuf(d1);
dbuf(d2);
dbuf(d2_1);
dbuf(d2_2);
dbuf(d3);
dbuf(d4);
msg(m1);
msg(m2);
msg(m2_1);
msg(m2_2);
msg(m3);
msg(m4);
queue(q1);
m1:d->d1;
m2:d->d2;
m2_1:d->d2_1;
m2_2:d->d2_2;
m3:d->d3;
m4:d->d4;
m1:n -> m2:h;
m1:p -> q1:h;
m2:n -> m3:h;
m2:c->m2_1:h;
m2_1:c->m2_2:h;
m3:n -> m4:h;
m2:p -> m1:h;
m3:p -> m2:h;
m4:p -> m3:h;
q1:n->m1:h;
q1:p->m4:h;
m4:n -> q1:h[color=blue];
}
Processamos o arquivo com um pré-processador:
cpp my_graph.dot -o my_graph_res.dot
my_graph_res.dot. :
# 1 "<built-in>"
# 1 "<command-line>"
# 1 "my_graph.dot"
# 1 "common.dot" 1
# 3 "my_graph.dot" 2
digraph queue_demo
{
rankdir=LR;
node[shape=Mrecord];
d1[label="<h> d1" xlabel="dblk_t"];;
d2[label="<h> d2" xlabel="dblk_t"];;
d2_1[label="<h> d2_1" xlabel="dblk_t"];;
d2_2[label="<h> d2_2" xlabel="dblk_t"];;
d3[label="<h> d3" xlabel="dblk_t"];;
d4[label="<h> d4" xlabel="dblk_t"];;
m1[xlabel=mblk_t label="<h> m1 | <p> *prev |<n> *next |<c> *cont |<d> *data | other\nstuff" ];;
m2[xlabel=mblk_t label="<h> m2 | <p> *prev |<n> *next |<c> *cont |<d> *data | other\nstuff" ];;
m2_1[xlabel=mblk_t label="<h> m2_1 | <p> *prev |<n> *next |<c> *cont |<d> *data | other\nstuff" ];;
m2_2[xlabel=mblk_t label="<h> m2_2 | <p> *prev |<n> *next |<c> *cont |<d> *data | other\nstuff" ];;
m3[xlabel=mblk_t label="<h> m3 | <p> *prev |<n> *next |<c> *cont |<d> *data | other\nstuff" ];;
m4[xlabel=mblk_t label="<h> m4 | <p> *prev |<n> *next |<c> *cont |<d> *data | other\nstuff" ];;
q1[ xlabel="queue_t" label="<h> q1 | <p> *prev |<n> *next |<c> *cont |<d> *data | other\nstuff"];;
m1:d->d1;
m2:d->d2;
m2_1:d->d2_1;
m2_2:d->d2_2;
m3:d->d3;
m4:d->d4;
m1:n -> m2:h;
m1:p -> q1:h;
m2:n -> m3:h;
m2:c->m2_1:h;
m2_1:c->m2_2:h;
m3:n -> m4:h;
m2:p -> m1:h;
m3:p -> m2:h;
m4:p -> m3:h;
q1:n->m1:h;
q1:p->m4:h;
m4:n -> q1:h[color=blue];
}
, . . Graphviz ( dot) : https://sketchviz.com/new
:

, , .
.