Synergie de Graphviz et du préprocesseur C / C ++

Cet article explique comment utiliser l'outil graphique populaire Graphviz en coopération avec le préprocesseur C / C ++ (ci-après simplement appelé le préprocesseur).


Le point clé est que le langage de graphes à points utilisé par Graphviz convient au traitement du préprocesseur dans sa syntaxe. Ainsi conçu par les développeurs. Grâce à leur perspicacité, nous pouvons utiliser les fonctionnalités suivantes lors de la description des graphiques (je cite de Wikipedia de mémoire):


  • remplacer les digraphes et trigraphes correspondants par les caractères équivalents "#" et "\";
  • suppression des caractères de saut de ligne échappés;
  • remplacer les commentaires de ligne et de bloc par des lignes vides (avec la suppression des espaces et des tabulations environnants);
  • insertion (inclusion) du contenu d'un fichier arbitraire ( #include );
  • substitution de macro ( #define );
  • compilation conditionnelle ( #if, #ifdef, #elif, #else, #endif );

Nous allons maintenant montrer les opportunités ouvertes dans la pratique. À titre d'exemple, prenez le graphique de mon article sur MediaStrimer2 , il est dans la figure ci-dessous.



Le graphique est suffisamment grand et si vous le décrivez «sur le front», alors beaucoup de travail manuel sans erreur sera nécessaire. Si vous regardez attentivement, vous pouvez isoler les éléments récurrents avec une différence uniquement dans le contenu de certains champs. Voici à quoi ressemblent les nœuds du graphe m 1, m2, m2_1, m2_2, m3, m4 . Ce sont les premiers candidats à l'utilisation de la petite mécanisation à l'aide de macros. Créez un fichier d'en-tête pour notre fichier dot principal. Appelons cela 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)];

Il est maintenant temps d'écrire le fichier graphique principal. Appelons-le 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]; //    .
}

Nous traitons le fichier avec un préprocesseur:


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