تتناول هذه المقالة كيفية استخدام أداة الرسم البياني Graphviz الشائعة بالتعاون مع المعالج المسبق C / C ++ (المشار إليه فيما يلي باسم المعالج المسبق).
النقطة الأساسية هي أن لغة الرسم البياني النقطي التي يستخدمها Graphviz مناسبة للمعالجة المسبقة في تركيبها. تصور ذلك من قبل المطورين. بفضل رؤيتهم ، يمكننا استخدام الميزات التالية عند وصف الرسوم البيانية (أقتبس من ويكيبيديا من الذاكرة):
- استبدال الحروف والأشكال المقابلة بالحروف المكافئة "#" و "\" ؛
- إزالة أحرف تغذية الخط الفرار ؛
- استبدال الخط وحظر التعليقات بخطوط فارغة (مع إزالة المسافات وعلامات التبويب المحيطة) ؛
- إدراج (تضمين) محتويات ملف تعسفي ( تضمين # ) ؛
- استبدال الماكرو ( # تعريف ) ؛
- الترجمة الشرطية ( #if ، #ifdef ، #elif ، #else ، #endif ) ؛
الآن سنوضح الفرص المفتوحة في الممارسة. كمثال ، خذ الرسم البياني من مقالتي على MediaStrimer2 ، في الشكل أدناه.

الرسم البياني كبير بما يكفي وإذا وصفته "على الجبهة" ، فسوف يستغرق الكثير من العمل اليدوي الخالي من الأخطاء. إذا نظرت عن كثب ، يمكنك عزل العناصر المتكررة باختلاف فقط في محتوى بعض الحقول. هذه هي الطريقة التي تبدو بها العقد في الرسم البياني م 1 ، م 2 ، م 2_1 ، م 2_2 ، م 3 ، م 4 . هؤلاء هم المرشحون الأوائل لاستخدام الميكنة الصغيرة باستخدام وحدات الماكرو. إنشاء ملف رأس لملف النقطة الرئيسي لدينا. دعنا نسميها شائعة. النقطة :
#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)];
حان الوقت الآن لكتابة ملف الرسم البياني الرئيسي. دعنا نسميها 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];
}
نعالج الملف باستخدام معالج مسبق:
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
:

, , .
.