Files
gonum/graph/formats/dot/internal/dot.bnf
2018-06-03 22:10:54 +09:30

360 lines
8.1 KiB
BNF

// The DOT Language
//
// http://www.graphviz.org/doc/info/lang.html
// ### [ Tokens ] ##############################################################
// The keywords node, edge, graph, digraph, subgraph, and strict are case-
// independent.
node
: 'n' 'o' 'd' 'e'
| 'N' 'o' 'd' 'e'
| 'N' 'O' 'D' 'E'
;
edge
: 'e' 'd' 'g' 'e'
| 'E' 'd' 'g' 'e'
| 'E' 'D' 'G' 'E'
;
// TODO: Rename graphx to graph once gocc#20 is fixed [1].
//
// [1]: https://github.com/goccmack/gocc/issues/20
graphx
: 'g' 'r' 'a' 'p' 'h'
| 'G' 'r' 'a' 'p' 'h'
| 'G' 'R' 'A' 'P' 'H'
;
digraph
: 'd' 'i' 'g' 'r' 'a' 'p' 'h'
| 'D' 'i' 'g' 'r' 'a' 'p' 'h'
| 'd' 'i' 'G' 'r' 'a' 'p' 'h'
| 'D' 'i' 'G' 'r' 'a' 'p' 'h'
| 'D' 'I' 'G' 'R' 'A' 'P' 'H'
;
subgraph
: 's' 'u' 'b' 'g' 'r' 'a' 'p' 'h'
| 'S' 'u' 'b' 'g' 'r' 'a' 'p' 'h'
| 's' 'u' 'b' 'G' 'r' 'a' 'p' 'h'
| 'S' 'u' 'b' 'G' 'r' 'a' 'p' 'h'
| 'S' 'U' 'B' 'G' 'R' 'A' 'P' 'H'
;
strict
: 's' 't' 'r' 'i' 'c' 't'
| 'S' 't' 'r' 'i' 'c' 't'
| 'S' 'T' 'R' 'I' 'C' 'T'
;
// An arbitrary ASCII character except null (0x00), double quote (0x22) and
// backslash (0x5C).
_ascii_char
// skip null (0x00)
: '\x01' - '\x21'
// skip double quote (0x22)
| '\x23' - '\x5B'
// skip backslash (0x5C)
| '\x5D' - '\x7F'
;
_ascii_letter
: 'a' - 'z'
| 'A' - 'Z'
;
_ascii_digit : '0' - '9' ;
_unicode_char
: _ascii_char
| _unicode_byte
;
_unicode_byte
: '\u0080' - '\uFFFC'
// skip invalid code point (\uFFFD)
| '\uFFFE' - '\U0010FFFF'
;
_letter : _ascii_letter | _unicode_byte | '_' ;
_decimal_digit : _ascii_digit ;
_decimals : _decimal_digit { _decimal_digit } ;
// An ID is one of the following:
//
// 1) Any string of alphabetic ([a-zA-Z\200-\377]) characters, underscores
// ('_') or digits ([0-9]), not beginning with a digit;
//
// 2) a numeral [-]?(.[0-9]+ | [0-9]+(.[0-9]*)? );
//
// 3) any double-quoted string ("...") possibly containing escaped quotes
// (\");
//
// 4) an HTML string (<...>).
id
: _letter { _letter | _decimal_digit }
| _int_lit
| _string_lit
| _html_lit
;
_int_lit
: [ '-' ] '.' _decimals
| [ '-' ] _decimals [ '.' { _decimal_digit } ]
;
// In quoted strings in DOT, the only escaped character is double-quote (").
// That is, in quoted strings, the dyad \" is converted to "; all other
// characters are left unchanged. In particular, \\ remains \\.
// As another aid for readability, dot allows double-quoted strings to span
// multiple physical lines using the standard C convention of a backslash
// immediately preceding a newline character.
// In addition, double-quoted strings can be concatenated using a '+' operator.
_escaped_char : '\\' ( _unicode_char | '"' | '\\' ) ;
_char : _unicode_char | _escaped_char ;
_string_lit : '"' { _char } '"' ;
// An arbitrary HTML character except null (0x00), left angle bracket (0x3C) and
// right angle bracket (0x3E).
_html_char
// skip null (0x00)
: '\x01' - '\x3B'
// skip left angle bracket (0x3C)
| '\x3D'
// skip right angle bracket (0x3E)
| '\x3F' - '\xFF'
| _unicode_byte
;
_html_chars : { _html_char } ;
_html_tag : '<' _html_chars '>' ;
_html_lit : '<' { _html_chars | _html_tag } '>' ;
// The language supports C++-style comments: /* */ and //. In addition, a line
// beginning with a '#' character is considered a line output from a C
// preprocessor (e.g., # 34 to indicate line 34 ) and discarded.
_line_comment
: '/' '/' { . } '\n'
| '#' { . } '\n'
;
_block_comment : '/' '*' { . | '*' } '*' '/' ;
!comment : _line_comment | _block_comment ;
!whitespace : ' ' | '\t' | '\r' | '\n' ;
// ### [ Syntax ] ##############################################################
<< import (
"gonum.org/v1/gonum/graph/formats/dot/ast"
"gonum.org/v1/gonum/graph/formats/dot/internal/astx"
) >>
// === [ Files ] ===============================================================
File
: Graph << astx.NewFile($0) >>
| File Graph << astx.AppendGraph($0, $1) >>
;
// === [ Graphs ] ==============================================================
// Graph : [ "strict" ] ( "graph" | "digraph" ) [ ID ] "{" [ StmtList ] "}"
Graph
: OptStrict DirectedGraph OptID
"{" OptStmtList "}" << astx.NewGraph($0, $1, $2, $4) >>
;
OptStrict
: empty << false, nil >>
| strict << true, nil >>
;
DirectedGraph
: graphx << false, nil >>
| digraph << true, nil >>
;
// === [ Statements ] ==========================================================
// StmtList
// : Stmt [ ";" ]
// | StmtList Stmt [ ";" ]
StmtList
: Stmt OptSemi << astx.NewStmtList($0) >>
| StmtList Stmt OptSemi << astx.AppendStmt($0, $1) >>
;
OptStmtList
: empty
| StmtList
;
Stmt
: NodeStmt
| EdgeStmt
| AttrStmt
| Attr
| Subgraph
;
OptSemi
: empty
| ";"
;
// --- [ Node statement ] ------------------------------------------------------
// NodeStmt : Node [ AttrList ]
NodeStmt
: Node OptAttrList << astx.NewNodeStmt($0, $1) >>
;
// --- [ Edge statement ] ------------------------------------------------------
// EdgeStmt : ( Node | Subgraph ) Edge [ AttrList ]
EdgeStmt
: Vertex Edge OptAttrList << astx.NewEdgeStmt($0, $1, $2) >>
;
// Edge : ( "--" | "-->" ) ( Node | Subgraph ) [ Edge ]
Edge
: DirectedEdge Vertex OptEdge << astx.NewEdge($0, $1, $2) >>
;
DirectedEdge
: "--" << false, nil >>
| "->" << true, nil >>
;
OptEdge
: empty
| Edge
;
// --- [ Attribute statement ] -------------------------------------------------
// AttrStmt : ( "graph" | "node" | "edge" ) AttrList
AttrStmt
: Component AttrList << astx.NewAttrStmt($0, $1) >>
;
Component
: graphx << ast.GraphKind, nil >>
| node << ast.NodeKind, nil >>
| edge << ast.EdgeKind, nil >>
;
// AttrList : "[" [ AList ] "]" [ AttrList ]
AttrList
: "[" OptAList "]" << $1, nil >>
| AttrList "[" OptAList "]" << astx.AppendAttrList($0, $2) >>
;
OptAttrList
: empty
| AttrList
;
// AList
// : Attr [ ( ";" | "," ) ]
// | AList Attr [ ( ";" | "," ) ]
AList
: Attr OptSep << astx.NewAttrList($0) >>
| AList Attr OptSep << astx.AppendAttr($0, $1) >>
;
OptAList
: empty
| AList
;
OptSep
: empty
| ";"
| ","
;
// --- [ Attribute ] -----------------------------------------------------------
Attr
: ID "=" ID << astx.NewAttr($0, $2) >>
;
// --- [ Subgraph ] ------------------------------------------------------------
// Subgraph : [ "subgraph" [ ID ] ] "{" [ StmtList ] "}"
Subgraph
: OptSubgraphID "{" OptStmtList "}" << astx.NewSubgraph($0, $2) >>
;
OptSubgraphID
: empty
| subgraph OptID << $1, nil >>
;
// === [ Vertices ] ============================================================
Vertex
: Node
| Subgraph
;
// --- [ Node identifier ] -----------------------------------------------------
// Node : ID [ Port ]
Node
: ID OptPort << astx.NewNode($0, $1) >>
;
// Port
// : ":" ID [ ":" CompassPoint ]
// | ":" CompassPoint
//
// CompassPoint
// : "n" | "ne" | "e" | "se" | "s" | "sw" | "w" | "nw" | "c" | "_"
// Note also that the allowed compass point values are not keywords, so these
// strings can be used elsewhere as ordinary identifiers and, conversely, the
// parser will actually accept any identifier.
Port
: ":" ID << astx.NewPort($1, nil) >>
| ":" ID ":" ID << astx.NewPort($1, $3) >>
;
OptPort
: empty
| Port
;
// === [ Identifiers ] =========================================================
ID
: id << astx.NewID($0) >>
;
OptID
: empty << "", nil >>
| ID
;