%{ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include <stdio.h> typedef void *Tobj; #include "dot2l.h" #ifdef HAVE_STDLIB_H # include <stdlib.h> #endif #include <string.h> static char portstr[SMALLBUF]; extern void yyerror(char *); %} %union { long i; char *s; void *o; } %token <i> T_graph T_digraph T_strict %token <i> T_node T_edge T_edgeop %token <s> T_id %type <o> node_name node_id subg_stmt %left <i> T_subgraph /* to eliminate subgraph hdr shift/reduce conflict */ %left '{' %% file: graph_type T_id { D2Lbegin ($2); free ($2); } '{' stmt_list '}' { D2Lend (); } | error { D2Labort (); } | /* empty*/ { D2Labort (); } ; graph_type: T_graph /* safe to change graph type/name before contents appear */ { gtype = "graph"; etype = "--"; } | T_strict T_graph { gtype = "strict graph"; etype = "--"; } | T_digraph { gtype = "digraph"; etype = "->"; } | T_strict T_digraph { gtype = "strict digraph"; etype = "->"; } ; stmt_list: stmt_list1 | /* empty */ ; stmt_list1: stmt | stmt_list1 stmt ; stmt: stmt1 | stmt1 ';' ; stmt1: node_stmt /* create nodes and set attributes */ | edge_stmt /* create edges and set attributes */ | attr_stmt /* reset value of attributes */ | subg_stmt {} ; node_stmt: node_id { attrclass = NODE; portstr[0] = '\000'; } opt_attr_list { attrclass = GRAPH; } ; node_id: node_name node_port { $$ = $1; } ; node_name: T_id { $$ = D2Linsertnode ($1); free ($1); } ; edge_stmt: node_id { D2Lbeginedge (NODE, $1, portstr); portstr[0] = '\000'; } edgeRHS { attrclass = EDGE; } opt_attr_list { D2Lendedge (); attrclass = GRAPH; } | subg_stmt { D2Lbeginedge (GRAPH, $1, ""); } edgeRHS { attrclass = EDGE; } opt_attr_list { D2Lendedge (); attrclass = GRAPH; } ; edgeRHS: T_edgeop node_id { D2Lmidedge (NODE, $2, portstr); portstr[0] = '\000'; } | T_edgeop node_id { D2Lmidedge (NODE, $2, portstr); portstr[0] = '\000'; } edgeRHS | T_edgeop subg_stmt { D2Lmidedge (GRAPH, $2, ""); portstr[0] = '\000'; } | T_edgeop subg_stmt { D2Lmidedge (GRAPH, $2, ""); portstr[0] = '\000'; } edgeRHS ; node_port: /* empty */ | port_location | port_angle | port_angle port_location | port_location port_angle ; port_location: ':' T_id { strcat (portstr, $2); free ($2); } | ':' '(' T_id ',' T_id ')' { strcat (portstr, "("); strcat (portstr, $3); strcat (portstr, ","); strcat (portstr, $5); strcat (portstr, ")"); free ($3), free ($5); } ; port_angle: '@' T_id { strcat (portstr, "@"); strcat (portstr, $2); free ($2); } ; attr_stmt: attr_class { inattrstmt = TRUE; } attr_list { attrclass = GRAPH; inattrstmt = FALSE; } | attr_set { attrclass = GRAPH; } ; attr_class: T_graph { attrclass = GRAPH; } | T_node { attrclass = NODE; } | T_edge { attrclass = EDGE; } ; opt_attr_list: rec_attr_list ; rec_attr_list: rec_attr_list attr_list | /* empty */ ; attr_list: '[' inside_attr_list ']' ; inside_attr_list: attr_set optcomma inside_attr_list | /* empty */ ; attr_set: T_id '=' T_id { D2Lsetattr ($1, $3); free ($1); free ($3); } ; optcomma: /* empty */ | ',' ; subg_stmt: subg_hdr '{' stmt_list '}' %prec '{' { $$ = D2Lpopgraph (); } | '{' { D2Lpushgraph (NULL); } stmt_list '}' { $$ = D2Lpopgraph (); } | subg_hdr %prec T_subgraph { $$ = D2Lpopgraph (); } ; subg_hdr: T_subgraph T_id { D2Lpushgraph ($2); free ($2); } ;