DOT 语言

用于定义 Graphviz 节点、边、图、子图和集群 的抽象语法。

终结符以粗体显示,非终结符以斜体显示。文字字符用单引号给出。圆括号 () 在需要时表示分组。方括号 [] 括起可选项目。竖线 | 分隔备选方案。

graph : [ strict ] (graph | digraph) [ ID ] '{' stmt_list '}'
stmt_list : [ stmt [ ';' ] stmt_list ]
stmt : node_stmt
| edge_stmt
| attr_stmt
| ID '=' ID
| subgraph
attr_stmt : (graph | node | edge) attr_list
attr_list : '[' [ a_list ] ']' [ attr_list ]
a_list : ID '=' ID [ (';' | ',') ] [ a_list ]
edge_stmt : (node_id | subgraph) edgeRHS [ attr_list ]
edgeRHS : edgeop (node_id | subgraph) [ edgeRHS ]
node_stmt : node_id [ attr_list ]
node_id : ID [ port ]
port : ':' ID [ ':' compass_pt ]
| ':' compass_pt
subgraph : [ subgraph [ ID ] ] '{' stmt_list '}'
compass_pt : n | ne | e | se | s | sw | w | nw | c | _

关键字 nodeedgegraphdigraphsubgraphstrict 不区分大小写。还要注意,允许的罗盘点值不是关键字,因此这些字符串可以在其他地方用作普通标识符,反之亦然,解析器实际上会接受任何标识符。

ID

ID 是以下之一

  • 任何字母 ([a-zA-Z\200-\377])、下划线 ('_') 或数字 ([0-9]) 字符串,但不能以数字开头;
  • 数字 [-]?(.[0-9]⁺ | [0-9]⁺(.[0-9]*)? );
  • 任何带双引号的字符串 ("..."),可能包含转义引号 (\")¹;
  • HTML 字符串 (<...>)。

ID 只是一个字符串;前两种形式中缺少引号字符只是为了简单起见。abc_2"abc_2" 之间没有语义差异,2.34"2.34" 之间也没有语义差异。显然,要使用关键字作为 ID,它必须用引号括起来。

HTML 字符串

请注意,在 HTML 字符串中,尖括号必须成对出现,并且允许换行符和其他格式空白字符。此外,内容必须是合法的 XML,因此可能需要使用 ", &, < 和 > 的特殊 XML 转义序列才能将这些字符嵌入属性值或原始文本中。作为 ID,HTML 字符串可以是任何合法的 XML 字符串。但是,如果用作 label 属性,它会以特殊方式解释,并且必须遵循 HTML 类标签 的语法。

带引号的字符串和 HTML 字符串都作为一个单元进行扫描,因此任何嵌入的注释都将被视为字符串的一部分。

边操作 (edgeops)

edgeop 在有向图中为 ->,在无向图中为 --

注释和可选格式

该语言支持 C++ 风格的注释:/* *///。此外,以 '#' 字符开头的行被认为是来自 C 预处理器的行输出(例如,# 34 表示第 34 行),并且会被丢弃。

分号和逗号有助于可读性,但不是必需的。此外,可以在终结符之间插入任意数量的空格。

作为另一个提高可读性的辅助手段,dot 允许带双引号的字符串使用标准 C 约定(在换行符之前直接加反斜杠)跨越多个物理行²。此外,带双引号的字符串可以使用 '+' 运算符连接。由于 HTML 字符串可以包含换行符,这些换行符仅用于格式化,因此该语言不允许在其中使用转义换行符或连接运算符。

子图和集群

子图在 Graphviz 中起着三种作用。首先,子图可以用来表示图结构,表明某些节点和边应该分组在一起。这是子图的通常作用,通常指定有关图组件的语义信息。它还可以提供边缘的便捷简写。边缘语句允许子图出现在边缘运算符的左侧和右侧。发生这种情况时,将从左侧的每个节点创建到右侧的每个节点的边。例如,规范

  A -> {B C}

等同于

  A -> B
  A -> C

在第二种作用中,子图可以提供设置属性的上下文。例如,子图可以指定蓝色是其中定义的所有节点的默认颜色。在图形绘制的上下文中,一个更有趣的例子是

subgraph { 
  rank = same; A; B; C; 
} 

这个(匿名)子图指定节点 A、B 和 C 应该在使用 dot 绘制时全部放置在同一层级上。

子图的第三种作用直接涉及某些布局引擎如何布局图形。如果子图的名称以 cluster 开头,Graphviz 会将子图标记为特殊的 集群 子图。如果支持,布局引擎将进行布局,以便属于集群的节点绘制在一起,整个集群的绘制包含在一个边界矩形内。请注意,好坏参半,集群子图不是 DOT 语言的一部分,而仅仅是某些布局引擎遵守的句法约定。

词法和语义说明

必须将图指定为**有向图**或**无向图**。语义上,这表示边的一个节点到另一个节点是否有自然方向。词法上,有向图必须使用边运算符->指定边,而无向图必须使用--。在操作上,这种区别用于定义不同的默认渲染属性。例如,默认情况下,有向图中的边将使用指向头部节点的箭头绘制。对于普通图,默认情况下,边不带箭头绘制。

图也可以描述为**严格**的。这禁止创建多边,即在有向情况下,最多只能有一条边具有给定的尾节点和头节点。对于无向图,最多只能有一条边连接到同一对节点。随后使用同一对节点的边语句将识别先前定义的边,并应用边语句中给出的任何属性。例如,图

strict graph { 
  a -- b
  a -- b
  b -- a [color=blue]
} 

将有一条连接节点ab的边,其颜色为蓝色。

如果使用**节点**、**边**或**图**语句定义了默认属性,或通过未附加到节点或边的属性赋值定义了默认属性,则随后定义的任何相应类型的对象将继承此属性值。这将持续到默认属性被设置为新值,从那时起,将使用新值。在设置默认属性之前定义的对象,一旦默认属性定义完成,将具有附加到属性的空字符串值。

请注意,子图在定义时会接收其父图的属性设置。这很有用;例如,可以为根图分配字体,所有子图也将使用该字体。但是,对于某些属性,此属性不可取。如果将标签附加到根图,则使用所有子图的标签可能不是预期效果。与其在图的顶部列出图属性,并在子图中根据需要重置属性,不如简单地推迟图中的属性定义,直到定义了适当的子图。

如果边属于集群,则其端点属于该集群。因此,放置边的位置会影响布局,因为集群有时会递归地布局。

子图和集群有一些限制。首先,目前,图及其子图的名称共享同一个命名空间。因此,每个子图都必须具有唯一的名称。其次,尽管节点可以属于任意数量的子图,但假设集群在被视为节点和边的子集时形成严格的层次结构。

字符编码

DOT 语言至少假设使用ASCII 字符集。普通字符串和 HTML 风格的字符串都可以包含非 ASCII 字符。在大多数情况下,这些字符串未解释:它们只是作为未经修改传递的唯一标识符或值。但是,标签旨在显示,这需要软件能够计算文本的大小并确定适当的字形。为此,它需要知道使用的是什么字符编码。

默认情况下,DOT 假设使用UTF-8 字符编码。它还接受Latin1 (ISO-8859-1) 字符集,假设输入图使用**charset** 属性来指定这一点。对于使用其他字符集的图,通常会有像iconv这样的程序可以将字符集从一种转换为另一种。

避免标签中出现非 ASCII 字符的另一种方法是使用特殊字符的 HTML 实体。在标签评估期间,这些实体将被转换为底层字符。此表格显示了支持的实体,以及它们的 Unicode 值、典型字形和 HTML 实体名称。因此,要在字符串中包含小写希腊字母 beta,可以使用 ASCII 序列&beta;。通常,应只使用输出字符集中允许的实体,并且对于这些实体,字体中存在字形。


  1. 在 DOT 中的引号字符串中,唯一转义的字符是双引号"。也就是说,在引号字符串中,二元组\" 将转换为";所有其他字符保持不变。特别是,\\ 仍然是\\。布局引擎可能会应用其他转义序列。
  2. 在 2.30 之前,该语言允许在 HTML 字符串之外的任何地方使用转义的换行符。新的基于 lex 的扫描器使得这难以实现。鉴于人们认为这种通用性缺乏用处,我们已将此功能限制在双引号字符串中,在这些字符串中,它实际上可能会有帮助。
最后修改日期:2024 年 9 月 28 日:更新 lang.md 语法修正 (888a216)