Synergie von Graphviz und C / C ++ - Präprozessor

In diesem Artikel wird beschrieben, wie Sie das beliebte Graphviz- Grafiktool in Zusammenarbeit mit dem C / C ++ - Präprozessor (im Folgenden einfach als Präprozessor bezeichnet) verwenden.


Der entscheidende Punkt ist , dass die Punkt Graph Sprache verwendet durch Graphviz ist für Präprozessor Verarbeitung in seiner Syntax geeignet. So konzipiert von den Entwicklern. Dank ihrer Einsicht können wir die folgenden Funktionen zur Beschreibung von Grafiken verwenden (ich zitiere aus Wikipedia aus dem Speicher):


  • Ersetzen der entsprechenden Digraphen und Trigraphen durch die entsprechenden Zeichen "#" und "\";
  • Entfernen von Escapezeichen für Zeilenumbrüche;
  • Ersetzen von Zeilen- und Blockkommentaren durch leere Zeilen (durch Entfernen der umgebenden Leerzeichen und Tabulatoren);
  • Einfügen (Einschließen) des Inhalts einer beliebigen Datei ( #include );
  • Makrosubstitution ( #define );
  • bedingte Kompilierung ( #if, #ifdef, #elif, #else, #endif );

Jetzt werden wir die eröffneten Möglichkeiten in der Praxis demonstrieren. Nehmen Sie als Beispiel das Diagramm aus meinem Artikel über MediaStrimer2 ( siehe Abbildung unten).



Das Diagramm ist groß genug, und wenn Sie es „auf der Stirn“ beschreiben, ist viel manuelle fehlerfreie Arbeit erforderlich. Wenn Sie genau hinschauen, können Sie sich wiederholende Elemente mit einem Unterschied nur im Inhalt einiger Felder isolieren. So sehen die Knoten des Graphen aus wie m 1, m2, m2_1, m2_2, m3, m4 . Dies sind die ersten Kandidaten für die Verwendung einer kleinen Mechanisierung unter Verwendung von Makros. Erstellen Sie eine Header-Datei für unsere Haupt-Dot-Datei. Nennen wir es 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)];

Jetzt ist es Zeit, die Hauptdiagrammdatei zu schreiben. Nennen wir es 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]; //    .
}

Wir verarbeiten die Datei mit einem Präprozessor:


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