dot.bnf 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292
  1. //Copyright 2013 GoGraphviz Authors
  2. //
  3. //Licensed under the Apache License, Version 2.0 (the "License");
  4. //you may not use this file except in compliance with the License.
  5. //You may obtain a copy of the License at
  6. //
  7. // http://www.apache.org/licenses/LICENSE-2.0
  8. //
  9. //Unless required by applicable law or agreed to in writing, software
  10. //distributed under the License is distributed on an "AS IS" BASIS,
  11. //WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  12. //See the License for the specific language governing permissions and
  13. //limitations under the License.
  14. //This bnf has been derived from https://graphviz.gitlab.io/_pages/doc/info/lang.html
  15. //The rules have been copied and are shown in the comments, with their derived bnf rules below.
  16. // ### [ Tokens ] ##############################################################
  17. // The keywords node, edge, graph, digraph, subgraph, and strict are case-
  18. // independent.
  19. node
  20. : 'n' 'o' 'd' 'e'
  21. | 'N' 'o' 'd' 'e'
  22. | 'N' 'O' 'D' 'E'
  23. ;
  24. edge
  25. : 'e' 'd' 'g' 'e'
  26. | 'E' 'd' 'g' 'e'
  27. | 'E' 'D' 'G' 'E'
  28. ;
  29. // TODO: Rename graphx to graph once gocc#20 is fixed [1].
  30. //
  31. // [1]: https://github.com/goccmack/gocc/issues/20
  32. graphx
  33. : 'g' 'r' 'a' 'p' 'h'
  34. | 'G' 'r' 'a' 'p' 'h'
  35. | 'G' 'R' 'A' 'P' 'H'
  36. ;
  37. digraph
  38. : 'd' 'i' 'g' 'r' 'a' 'p' 'h'
  39. | 'D' 'i' 'g' 'r' 'a' 'p' 'h'
  40. | 'd' 'i' 'G' 'r' 'a' 'p' 'h'
  41. | 'D' 'i' 'G' 'r' 'a' 'p' 'h'
  42. | 'D' 'I' 'G' 'R' 'A' 'P' 'H'
  43. ;
  44. subgraph
  45. : 's' 'u' 'b' 'g' 'r' 'a' 'p' 'h'
  46. | 'S' 'u' 'b' 'g' 'r' 'a' 'p' 'h'
  47. | 's' 'u' 'b' 'G' 'r' 'a' 'p' 'h'
  48. | 'S' 'u' 'b' 'G' 'r' 'a' 'p' 'h'
  49. | 'S' 'U' 'B' 'G' 'R' 'A' 'P' 'H'
  50. ;
  51. strict
  52. : 's' 't' 'r' 'i' 'c' 't'
  53. | 'S' 't' 'r' 'i' 'c' 't'
  54. | 'S' 'T' 'R' 'I' 'C' 'T'
  55. ;
  56. // An arbitrary ASCII character except null (0x00), double quote (0x22) and
  57. // backslash (0x5C).
  58. _ascii_char
  59. // skip null (0x00)
  60. : '\x01' - '\x21'
  61. // skip double quote (0x22)
  62. | '\x23' - '\x5B'
  63. // skip backslash (0x5C)
  64. | '\x5D' - '\x7F'
  65. ;
  66. _ascii_letter
  67. : 'a' - 'z'
  68. | 'A' - 'Z'
  69. ;
  70. _ascii_digit : '0' - '9' ;
  71. _unicode_char
  72. : _ascii_char
  73. | _unicode_byte
  74. ;
  75. _unicode_byte
  76. : '\u0080' - '\uFFFC'
  77. // skip invalid code point (\uFFFD)
  78. | '\uFFFE' - '\U0010FFFF'
  79. ;
  80. _letter : _ascii_letter | _unicode_byte | '_' ;
  81. _decimal_digit : _ascii_digit ;
  82. _decimals : _decimal_digit { _decimal_digit } ;
  83. // An ID is one of the following:
  84. //
  85. // 1) Any string of alphabetic ([a-zA-Z\200-\377]) characters, underscores
  86. // ('_') or digits ([0-9]), not beginning with a digit;
  87. //
  88. // 2) a numeral [-]?(.[0-9]+ | [0-9]+(.[0-9]*)? );
  89. //
  90. // 3) any double-quoted string ("...") possibly containing escaped quotes
  91. // (\");
  92. //
  93. // 4) an HTML string (<...>).
  94. id
  95. : _letter { _letter | _decimal_digit }
  96. | _int_lit
  97. | _string_lit
  98. | _html_lit
  99. ;
  100. _int_lit
  101. : [ '-' ] '.' _decimals
  102. | [ '-' ] _decimals [ '.' { _decimal_digit } ]
  103. ;
  104. // In quoted strings in DOT, the only escaped character is double-quote (").
  105. // That is, in quoted strings, the dyad \" is converted to "; all other
  106. // characters are left unchanged. In particular, \\ remains \\.
  107. _escaped_char : '\\' ( _unicode_char | '"' | '\\' ) ;
  108. _char : _unicode_char | _escaped_char ;
  109. _string_lit : '"' { _char } '"' ;
  110. // An arbitrary HTML character except null (0x00), left angle bracket (0x3C) and
  111. // right angle bracket (0x3E).
  112. _html_char
  113. // skip null (0x00)
  114. : '\x01' - '\x3B'
  115. // skip left angle bracket (0x3C)
  116. | '\x3D'
  117. // skip right angle bracket (0x3E)
  118. | '\x3F' - '\xFF'
  119. ;
  120. _html_chars : { _html_char } ;
  121. _html_tag : '<' _html_chars '>' ;
  122. _html_lit : '<' { _html_chars | _html_tag } '>' ;
  123. // The language supports C++-style comments: /* */ and //. In addition, a line
  124. // beginning with a '#' character is considered a line output from a C
  125. // preprocessor (e.g., # 34 to indicate line 34 ) and discarded.
  126. _line_comment
  127. : '/' '/' { . } '\n'
  128. | '#' { . } '\n'
  129. ;
  130. _block_comment : '/' '*' { . | '*' } '*' '/' ;
  131. !comment : _line_comment | _block_comment ;
  132. !whitespace : ' ' | '\t' | '\r' | '\n' ;
  133. // ### [ Syntax ] ##############################################################
  134. << import "github.com/awalterschulze/gographviz/ast" >>
  135. //graph : [ strict ] (graph | digraph) [ ID ] '{' stmt_list '}'
  136. DotGraph
  137. : graphx "{" "}" << ast.NewGraph(ast.GRAPH, ast.FALSE, nil, nil) >>
  138. | strict graphx "{" "}" << ast.NewGraph(ast.GRAPH, ast.TRUE, nil, nil) >>
  139. | graphx Id "{" "}" << ast.NewGraph(ast.GRAPH, ast.FALSE, $1, nil) >>
  140. | strict graphx Id "{" "}" << ast.NewGraph(ast.GRAPH, ast.TRUE, $2, nil) >>
  141. | graphx "{" StmtList "}" << ast.NewGraph(ast.GRAPH, ast.FALSE, nil, $2) >>
  142. | graphx Id "{" StmtList "}" << ast.NewGraph(ast.GRAPH, ast.FALSE, $1, $3) >>
  143. | strict graphx "{" StmtList "}" << ast.NewGraph(ast.GRAPH, ast.TRUE, nil, $3) >>
  144. | strict graphx Id "{" StmtList "}" << ast.NewGraph(ast.GRAPH, ast.TRUE, $2, $4) >>
  145. | digraph "{" "}" << ast.NewGraph(ast.DIGRAPH, ast.FALSE, nil, nil) >>
  146. | strict digraph "{" "}" << ast.NewGraph(ast.DIGRAPH, ast.TRUE, nil, nil) >>
  147. | digraph Id "{" "}" << ast.NewGraph(ast.DIGRAPH, ast.FALSE, $1, nil) >>
  148. | strict digraph Id "{" "}" << ast.NewGraph(ast.DIGRAPH, ast.TRUE, $2, nil) >>
  149. | digraph "{" StmtList "}" << ast.NewGraph(ast.DIGRAPH, ast.FALSE, nil, $2) >>
  150. | digraph Id "{" StmtList "}" << ast.NewGraph(ast.DIGRAPH, ast.FALSE, $1, $3) >>
  151. | strict digraph "{" StmtList "}" << ast.NewGraph(ast.DIGRAPH, ast.TRUE, nil, $3) >>
  152. | strict digraph Id "{" StmtList "}" << ast.NewGraph(ast.DIGRAPH, ast.TRUE, $2, $4) >>
  153. ;
  154. //stmt_list : [ stmt [ ';' ] [ stmt_list ] ]
  155. StmtList
  156. : Stmt1 << ast.NewStmtList($0) >>
  157. | StmtList Stmt1 << ast.AppendStmtList($0, $1) >>
  158. ;
  159. Stmt1
  160. : Stmt << $0, nil >>
  161. | Stmt ";" << $0, nil >>
  162. ;
  163. //stmt : node_stmt | edge_stmt | attr_stmt | (ID '=' ID) | subgraph
  164. Stmt
  165. : Id "=" Id << ast.NewAttr($0, $2) >>
  166. | NodeStmt << $0, nil >>
  167. | EdgeStmt << $0, nil >>
  168. | AttrStmt << $0, nil >>
  169. | SubGraphStmt << $0, nil >>
  170. ;
  171. //attr_stmt : (graph | node | edge) attr_list
  172. AttrStmt
  173. : graphx AttrList << ast.NewGraphAttrs($1) >>
  174. | node AttrList << ast.NewNodeAttrs($1) >>
  175. | edge AttrList << ast.NewEdgeAttrs($1) >>
  176. ;
  177. //attr_list : '[' [ a_list ] ']' [ attr_list ]
  178. AttrList
  179. : "[" "]" << ast.NewAttrList(nil) >>
  180. | "[" AList "]" << ast.NewAttrList($1) >>
  181. | AttrList "[" "]" << ast.AppendAttrList($0, nil) >>
  182. | AttrList "[" AList "]" << ast.AppendAttrList($0, $2) >>
  183. ;
  184. //a_list : ID [ '=' ID ] [ ',' ] [ a_list ]
  185. AList
  186. : Attr << ast.NewAList($0) >>
  187. | AList Attr << ast.AppendAList($0, $1) >>
  188. | AList "," Attr << ast.AppendAList($0, $2) >>
  189. ;
  190. //An a_list clause of the form ID is equivalent to ID=true.
  191. Attr
  192. : Id << ast.NewAttr($0, nil) >>
  193. | Id "=" Id << ast.NewAttr($0, $2) >>
  194. ;
  195. //edge_stmt : (node_id | subgraph) edgeRHS [ attr_list ]
  196. EdgeStmt
  197. : NodeId EdgeRHS << ast.NewEdgeStmt($0, $1, nil) >>
  198. | NodeId EdgeRHS AttrList << ast.NewEdgeStmt($0, $1, $2) >>
  199. | SubGraphStmt EdgeRHS << ast.NewEdgeStmt($0, $1, nil) >>
  200. | SubGraphStmt EdgeRHS AttrList << ast.NewEdgeStmt($0, $1, $2) >>
  201. ;
  202. //edgeRHS : edgeop (node_id | subgraph) [ edgeRHS ]
  203. EdgeRHS
  204. : EdgeOp NodeId << ast.NewEdgeRHS($0, $1) >>
  205. | EdgeOp SubGraphStmt << ast.NewEdgeRHS($0, $1) >>
  206. | EdgeRHS EdgeOp NodeId << ast.AppendEdgeRHS($0, $1, $2) >>
  207. | EdgeRHS EdgeOp SubGraphStmt << ast.AppendEdgeRHS($0, $1, $2) >>
  208. ;
  209. //node_stmt : node_id [ attr_list ]
  210. NodeStmt
  211. : NodeId << ast.NewNodeStmt($0, nil) >>
  212. | NodeId AttrList << ast.NewNodeStmt($0, $1) >>
  213. ;
  214. //node_id : ID [ port ]
  215. NodeId
  216. : Id << ast.NewNodeID($0, nil) >>
  217. | Id Port << ast.NewNodeID($0, $1) >>
  218. ;
  219. //compass_pt : (n | ne | e | se | s | sw | w | nw | c | _)
  220. //Note also that the allowed compass point values are not keywords,
  221. //so these strings can be used elsewhere as ordinary identifiers and,
  222. //conversely, the parser will actually accept any identifier.
  223. //port : ':' ID [ ':' compass_pt ]
  224. // | ':' compass_pt
  225. Port
  226. : ":" Id << ast.NewPort($1, nil), nil >>
  227. | ":" Id ":" Id << ast.NewPort($1, $3), nil >>
  228. ;
  229. //TODO: Semicolons aid readability but are not required except in the rare case that a named subgraph with no body immediately preceeds an anonymous subgraph,
  230. //since the precedence rules cause this sequence to be parsed as a subgraph with a heading and a body. Also, any amount of whitespace may be inserted between terminals.
  231. //subgraph : [ subgraph [ ID ] ] '{' stmt_list '}'
  232. SubGraphStmt
  233. : "{" StmtList "}" << ast.NewSubGraph(nil, $1) >>
  234. | subgraph "{" StmtList "}" << ast.NewSubGraph(nil, $2) >>
  235. | subgraph Id "{" StmtList "}" << ast.NewSubGraph($1, $3) >>
  236. | subgraph "{" "}" << ast.NewSubGraph(nil, nil) >>
  237. | subgraph Id "{" "}" << ast.NewSubGraph($1, nil) >>
  238. ;
  239. //An edgeop is -> in directed graphs and -- in undirected graphs.
  240. EdgeOp
  241. : "->" << ast.DIRECTED, nil >>
  242. | "--" << ast.UNDIRECTED, nil >>
  243. ;
  244. Id
  245. : id << ast.NewID($0) >>
  246. ;