graphviz和cc预处理器的协同作用

This article tells how to make Graphviz graphs drawing easy and faster by using C preprocessor.

本文介绍如何通过使用C预处理程序使Graphviz图形绘制变得容易和快捷。

The key point is that the dot graph language that Graphviz (graph visualization software) uses is preprocessable in its syntax. This is what the Graphviz developers intended. Thanks to their foresight, when describing graphs, we can use the following features (I am citing Wikipedia from memory):

关键是Graphviz (图形可视化软件)使用的图语言的语法可以预处理。 这就是Graphviz开发人员的意图。 由于他们的远见卓识,在描述图形时,我们可以使用以下功能(我从内存中引用了Wikipedia):

  • replacing the corresponding digraphs and trigraphs with the equivalent symbols “#” and “\”;

    用等价符号“#”和“ \”替换相应的二合字母和三合字母;
  • removing escaped line feed characters;

    删除转义的换行符;
  • Replacing inline and block comments with empty lines (removing surrounding spaces and tabs);

    用空行替换行内注释和阻止注释(删除周围的空格和制表符);
  • inserting (including) the content of an arbitrary file (#include);

    插入(包括)任意文件(#include)的内容;
  • macro substitution (#define);

    宏替换(#define);
  • conditional compilation (#if, #ifdef, #elif, #else, #endif).

    条件编译(#if,#ifdef,#elif,#else,#endif)。

Now let’s demonstrate the new opportunities in practice. As an example, let’s take the graph from my article about MediaStreamer2, it is in the figure below.

现在让我们演示实践中的新机会。 作为示例,让我们从有关MediaStreamer2的文章中获取图表,如下图所示。

The graph is large enough and if you describe it “head-on” you will need a lot of manual error-free work. If you look closely, you can isolate duplicate elements with a difference only in the content of some fields. This is how the nodes of the graph look like m1, m2, m2_1, m2_2, m3, m4. These are the first candidates for small-scale mechanization using macros. Create a header file for our main dot file. Let’s call it common.dot:

该图足够大,如果您“正面”描述它,则将需要进行许多手动无错误的工作。 如果仔细观察,您可以隔离重复的元素,仅在某些字段的内容上有所不同。 这就是图的节点看起来像m1,m2,m2_1,m2_2,m3,m4的样子 。 这些是使用宏进行小型机械化的首批候选对象。 为我们的主文件创建头文件。 我们称之为common.dot

// The common.dot file contains definitions for the main graph file.#define Q(x) #x         // Auxiliary macro for "quoting" a string inside a macro.#define QUOTE(x) Q(x)   // A macro to "quote" a string within another macro.// We define a macro for a conditional image of the internal
// fields of the mblk_t structure.// The macro will only show some of the structure fields.
#define msg_staff \
<p> *prev \
|<n> *next \
|<c> *cont \
|<d> *data \
| other\nstuff// We define a macro for the conditional image of
// the mblk_t structure itself.
#define msg(name, ... ) \
name[xlabel=mblk_t label=QUOTE(<h> name | msg_staff) \
];// We define a macro for a conditional image of
// the dblk_t structure itself.
#define dbuf(name ...) \
name[label=QUOTE(<h> name) xlabel="dblk_t"];// We define a macro for a conditional image of
// the queue_t structure.// Some of the fields of this structure coincide with
// the fields of the mblk_t structure, // therefore, the msg_staff macro is substituted
// into the definition.
#define queue(name, ...) \
name[ xlabel="queue_t" label=QUOTE(<h> name | \
msg_staff)];

Now it’s time to write the main graph file. Let’s call it my_graph.dot:

现在是时候编写主图形文件了。 我们称之为my_graph.dot

// file my_graph.dot// Including mocro definitions file.
#include "common.dot"digraph queue_demo
{
rankdir=LR;
node[shape=Mrecord]; // Using the macros we defined above,// we create nodes that will symbolize data blocks on the graph.
dbuf(d1);
dbuf(d2);
dbuf(d2_1);
dbuf(d2_2);
dbuf(d3);
dbuf(d4); // We create nodes that will symbolize messages on the graph,// to which the data blocks are bound.
msg(m1);
msg(m2);
msg(m2_1);
msg(m2_2);
msg(m3);
msg(m4); // We create an instance of the control queue structure.// The node will be named q1.
queue(q1); // We describe the connections of data blocks
// with message nodes.
m1:d->d1;
m2:d->d2;
m2_1:d->d2_1;
m2_2:d->d2_2;
m3:d->d3;
m4:d->d4; // We Describe the connections of messages to each other.
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; // Describe the connection of messages to the queue structure.
q1:n->m1:h;
q1:p->m4:h;
m4:n -> q1:h[color=blue];
}

We process the file with a preprocessor:

我们使用预处理器处理文件:

$ cpp my_graph.dot -o my_graph_res.dot

The result will be placed in the my_graph_res.dot file. As a result of the preprocessor operation, the graph description file will take the form:

结果将放置在my_graph_res.dot文件中。 作为预处理器操作的结果,图形描述文件将采用以下格式:

# 1 "<built-in>"
# 1 "<command-line>"
# 1 "my_graph.dot"# 1 "common.dot" 1
# 3 "my_graph.dot" 2digraph 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];
}

As you can see, all macros are expanded and substituted. The lines are longer and more complex. It remains to transfer the file for rendering to one of the utilities of the Graphviz package (for example dot) or to render on the website: https://sketchviz.com/new

如您所见,所有宏都被扩展和替换。 线更长,也更复杂。 仍然需要将要渲染的文件传输到Graphviz软件包的某个实用程序(例如dot )或在网站上进行渲染: https : //sketchviz.com/new

The result will be like this:

结果将是这样的:

Image for post

The graph differs in the arrangement of nodes from the original at the beginning of the article, due to the fact that for the sake of consistency, I changed the order of declaration of nodes.

该图的节点排列方式与本文开头的原始节点有所不同,原因是为了保持一致,我更改了节点的声明顺序。

If you wish, you can go further and move the connection of queue nodes into the macro.

如果愿意,可以走得更远,然后将队列节点的连接移到宏中。

翻译自: https://medium.com/swlh/synergy-of-graphviz-and-the-c-c-preprocessor-254e5d0db542

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值