Below is the file 'dot_parser.mly' from this revision. You can also download the file.
%{
open Dot_types
%}
%token STRICT
%token GRAPH
%token DIGRAPH
%token NODE
%token EDGE
%token SUBGRAPH
%token LBRACE
%token RBRACE
%token LPAREN
%token RPAREN
%token LBRACKET
%token RBRACKET
%token COMMA
%token SEMICOLON
%token EQUAL
%token AT
%token COLON
%token PLUS
%token DIR_EDGEOP
%token UNDIR_EDGEOP
%token <string> IDENT
%token <string> STRING
%token <string> NUMBER
%nonassoc below_LBRACE
%nonassoc LBRACE
%start graph
%type <Dot_types.graph> graph
%%
graph:
strict_flag graph_kind opt_id LBRACE stmt_list RBRACE
{ { strict = $1 ; kind = $2 ;
id = $3 ; stmt = Q.to_list $5 } }
;
strict_flag:
/* empty */ { false }
| STRICT { true }
;
graph_kind:
GRAPH { `GRAPH }
| DIGRAPH { `DIGRAPH }
;
opt_id:
/* empty */ { None }
| id { Some $1 }
;
stmt_list:
stmt_semi { Q.push Q.empty $1 }
| stmt_list stmt_semi { Q.push $1 $2 }
;
stmt_semi:
stmt { $1 }
| stmt SEMICOLON { $1 }
;
stmt:
node_stmt { `NODE $1 }
| edge_stmt { `EDGE $1 }
| attr_stmt { $1 }
| id_equal { `ID_EQUAL $1 }
| subgraph { `SUBGRAPH $1 }
;
id_equal:
id EQUAL id { ($1, $3) }
;
node_stmt:
node_id opt_attr_list { let (id, port) = $1 in
(id, port, Q.to_list $2) }
;
node_id:
id opt_port { ($1, $2) }
;
opt_port:
/* empty */ { None }
| port { Some $1 }
;
port:
port_location { (`LOCATION $1, `NO_ANGLE) }
| port_location port_angle { (`LOCATION $1, `ANGLE $2) }
| port_angle port_location { (`LOCATION $2, `ANGLE $1) }
| port_angle { (`NO_LOCATION, `ANGLE $1) }
;
port_location:
COLON id { `ONE_ID $2 }
| COLON LPAREN id COMMA id RPAREN { `TWO_ID ($3, $5) }
;
port_angle:
AT id { $2 }
;
subgraph:
| SUBGRAPH id LBRACE stmt_list RBRACE { (Some $2, Q.to_list $4) }
| SUBGRAPH LBRACE stmt_list RBRACE { (None, Q.to_list $3) }
| LBRACE stmt_list RBRACE { (None, Q.to_list $2) }
| SUBGRAPH id %prec below_LBRACE { (Some $2, []) }
;
opt_attr_list:
/* empty */ { Q.empty }
| attr_list { $1 }
;
attr_list:
| LBRACKET a_list RBRACKET { $2 }
| attr_list LBRACKET a_list RBRACKET { Q.concat $1 $3 }
;
a_list:
a_list_item { Q.push Q.empty $1 }
| a_list a_list_item { Q.push $1 $2 }
;
a_list_item:
id EQUAL id COMMA { ($1, $3) }
| id EQUAL id { ($1, $3) }
| id COMMA { ($1, "true") }
| id { ($1, "true") }
;
attr_stmt:
GRAPH attr_list { `ATTR_GRAPH (Q.to_list $2) }
| NODE attr_list { `ATTR_NODE (Q.to_list $2) }
| EDGE attr_list { `ATTR_EDGE (Q.to_list $2) }
;
node_or_subgraph:
node_id { `NODEID $1 }
| subgraph { `SUBGRAPH $1 }
;
edge_stmt:
node_or_subgraph edgeRHS_list opt_attr_list { ($1, Q.to_list $2, Q.to_list $3) }
;
edgeRHS_list:
edgeRHS { Q.push Q.empty $1 }
| edgeRHS_list edgeRHS { Q.push $1 $2 }
;
edgeRHS:
DIR_EDGEOP node_or_subgraph { (`DIRECTED, $2) }
| UNDIR_EDGEOP node_or_subgraph { (`UNDIRECTED, $2) }
;
id:
IDENT { $1 }
| string { String.concat "" (Q.to_list $1) }
| NUMBER { $1 }
;
string:
STRING { Q.push Q.empty $1 }
| string PLUS STRING { Q.push $1 $3 }
;