Sinergia de Graphviz y el preprocesador C / C ++

Este artículo trata sobre cómo usar la popular herramienta gráfica Graphviz en cooperación con el preprocesador C / C ++ (en adelante, simplemente denominado preprocesador).


El punto clave es que el lenguaje de gráfico de puntos utilizado por Graphviz es adecuado para el procesamiento del preprocesador en su sintaxis. Así concebido por los desarrolladores. Gracias a su conocimiento, podemos usar las siguientes características al describir gráficos (cito de Wikipedia de memoria):


  • reemplazar los correspondientes dígrafos y trigrafos con los caracteres equivalentes "#" y "\";
  • eliminación de caracteres de avance de línea escapados;
  • reemplazar la línea y bloquear comentarios con líneas vacías (con la eliminación de espacios y pestañas circundantes);
  • inserción (inclusión) del contenido de un archivo arbitrario ( #include );
  • sustitución macro ( #define );
  • compilación condicional ( #if, #ifdef, #elif, #else, #endif );

Ahora demostraremos las oportunidades abiertas en la práctica. Como ejemplo, tome el gráfico de mi artículo sobre MediaStrimer2 , está en la figura a continuación.



El gráfico es lo suficientemente grande y si lo describe “en la frente”, requerirá mucho trabajo manual sin errores. Si observa detenidamente, puede aislar elementos repetidos con una diferencia solo en el contenido de algunos campos. Así es como los nodos del gráfico se ven como m 1, m2, m2_1, m2_2, m3, m4 . Estos son los primeros candidatos para el uso de mecanización pequeña usando macros. Cree un archivo de encabezado para nuestro archivo de puntos principal. Llamémoslo common.dot :


//  common.dot       .

#define Q(x) #x         //    ""   .

#define QUOTE(x) Q(x)   //   ""    .

//         mblk_t.
//       . 
#define msg_staff \
   <p> *prev \
  |<n> *next \
  |<c> *cont  \
  |<d> *data \
  | other\nstuff

//        mblk_t.
#define msg(name, ... ) \
name[xlabel=mblk_t label=QUOTE(<h> name | msg_staff) \
];

//        dblk_t.
#define dbuf(name ...) \
name[label=QUOTE(<h> name) xlabel="dblk_t"];

//       queue_t.
//         mblk_t, 
//      msg_staff.
#define queue(name, ...) \
name[ xlabel="queue_t" label=QUOTE(<h> name | \
msg_staff)];

Ahora es el momento de escribir el archivo gráfico principal. Llamémoslo my_graph.dot :


//  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);

    //     .
    //     q1.
    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]; //    .
}

Procesamos el archivo con un preprocesador:


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


:



, , .


.


All Articles