/* Output Graphviz specification of a state machine genetated by Bison. Copyright (C) 2001, 2002, 2005, 2006 Free Software Foundation, Inc. This file is part of Bison, the GNU Compiler Compiler. Bison is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2, or (at your option) any later version. Bison is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with Bison; see the file COPYING. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include #include "system.h" #include #include "graphviz.h" #include "graphviz_defaults.h" /** Local functions */ static void output_color(enum color, FILE *); static void output_node_attributes(struct node_attributes *, FILE *); static void output_edge_attributes(struct edge_attributes *, FILE *); static void output_graph_attributes(struct graph_attributes *, FILE *); static void new_node_attributes(struct node_attributes *); static void new_edge_attributes(struct edge_attributes *); static void new_graph_attributes(struct graph_attributes *); static bool output_separator(bool, FILE *); /* Return an unambiguous printable representated, for NAME, suitable for C strings. Use slot 2 since the user may use slots 0 and 1. */ static char const * quote (char const *name) { return quotearg_n_style (2, c_quoting_style, name); } void new_graph (graph *g) { g->title = G_TITLE; new_graph_attributes(&g->graph_attributes); /* Some default attributes for all nodes and edges */ new_node_attributes(&g->node_attributes); g->node_attributes.shape = circle; g->node_attributes.fillcolor = white; g->node_attributes.textcolor = blue; g->node_attributes.bordercolor = black; new_edge_attributes(&g->edge_attributes); g->edge_attributes.weight=2.0; g->edge_attributes.color=black; g->edge_attributes.textcolor=black; g->edge_attributes.arrowstyle=normal; } void open_graph (FILE *fout) { fprintf(fout,"digraph "); } void output_graph(graph *g, FILE *fout) { bool atleastone= false; /* output the graph attributes first */ if(g->title != G_TITLE) { fprintf(fout,"%s {\n",g->title); } fprintf(fout,"\tgraph"); output_graph_attributes(&g->graph_attributes,fout); fprintf(fout,"\n"); /* Done with graph params; output node and edge params */ fprintf(fout,"\tnode"); output_node_attributes(&g->node_attributes,fout); fprintf(fout,"\n"); fprintf(fout,"\tedge"); output_edge_attributes(&g->edge_attributes,fout); fprintf(fout,"\n"); /*An extra new line to separate the states */ fprintf(fout,"\n"); } void close_graph(FILE *fout) { fprintf(fout,"\n}"); } /** Create a new node */ void new_node(node *n) { n->title = N_TITLE; new_node_attributes(&n->attrs); } void open_node(FILE *fout) { fprintf(fout,"\t"); } void output_node(node *n, FILE *fout) { /** Ouput the node name and then properties */ fprintf(fout, "%s",n->title); output_node_attributes(&n->attrs,fout); } void close_node(FILE *fout) { fprintf(fout,"\n"); } /** Create a new edge. */ void new_edge(edge *e) { e->sourcename = E_SOURCENAME; e->targetname = E_TARGETNAME; new_edge_attributes(&e->attrs); } void open_edge(FILE *fout) { fprintf(fout,"\t"); } void output_edge(edge *e, FILE *fout) { fprintf(fout,"%s -> %s",e->sourcename,e->targetname); output_edge_attributes(&e->attrs,fout); } void close_edge(FILE *fout) { fprintf(fout, "\n"); } void output_color(enum color color, FILE *fout) { switch(color) { case black: fprintf(fout, "black"); break; case red: fprintf(fout, "red"); break; case blue: fprintf(fout, "blue"); break; case green: fprintf(fout, "green"); break; case white: default: fprintf(fout, "white"); break; } } void output_node_attributes(struct node_attributes *na, FILE *fout) { bool atleastone = false; fprintf(fout," ["); /** Output the label */ if(na->label != NA_LABEL) { fprintf(fout,"label=%s", quote(na->label)); atleastone = true; } /** Output shape attribute. */ if(na->shape != NA_SHAPE) { atleastone = output_separator(atleastone,fout); fprintf(fout,"shape="); switch(na->shape) { case box: fprintf(fout,"box"); break; case doublecircle: fprintf(fout, "doublecircle"); break; case circle: default: fprintf(fout,"circle"); break; } } /** Output fillcolor. */ if(na->fillcolor != NA_FILLCOLOR) { atleastone = output_separator(atleastone,fout); fprintf(fout,"fillcolor="); output_color(na->fillcolor,fout); } /** Output node textcolor. */ if(na->textcolor != NA_FONTCOLOR) { atleastone = output_separator(atleastone,fout); fprintf(fout,"fontcolor="); output_color(na->textcolor, fout); } /** Output node border color. */ if(na->bordercolor != NA_COLOR) { atleastone = output_separator(atleastone,fout); fprintf(fout,"color="); output_color(na->bordercolor, fout); } /** Close the node attributes. */ fprintf(fout, "];"); } void output_edge_attributes(struct edge_attributes *ea, FILE *fout){ bool atleastone = false; /** Output generic edge properties. */ fprintf(fout, " ["); /** Edge label */ if(ea->label != EA_LABEL) { fprintf(fout, "label=%s",quote(ea->label)); atleastone = true; } /** Edge weight. */ if(ea->weight != EA_WEIGHT) { atleastone = output_separator(atleastone,fout); fprintf(fout, "weight=%2.1f", ea->weight); } /** Edge colors. */ if(ea->color != EA_COLOR) { atleastone = output_separator(atleastone,fout); fprintf(fout, "fontcolor="); output_color(ea->color,fout); } if(ea->textcolor != EA_FONTCOLOR) { atleastone = output_separator(atleastone,fout); fprintf(fout, "color="); output_color(ea->textcolor, fout); } /** Arrow style. */ if(ea->arrowstyle != EA_ARROWSTYLE) { atleastone = output_separator(atleastone,fout); fprintf(fout, "arrowhead="); switch(ea->arrowstyle) { case empty: fprintf(fout, "empty" ); break; case vee: fprintf(fout, "vee" ); break; case normal: default: fprintf(fout, "normal"); break; } } /** Close the general edge properties */ fprintf(fout, "];"); } void output_graph_attributes(struct graph_attributes *ga, FILE *fout) { bool atleastone = false; fprintf(fout," ["); if(ga->orientation != G_ORIENTATION) { fprintf(fout,"rankdir="); switch(ga->orientation) { case top_to_bottom: fprintf(fout,"TB"); break; case right_to_left: fprintf(fout,"RL"); break; case bottom_to_top: fprintf(fout,"BT"); break; case left_to_right: default: fprintf(fout,"LR"); break; } atleastone = true; } if(ga->splines != G_SPLINES) { atleastone = output_separator(atleastone,fout); fprintf(fout,"splines="); if(ga->splines == yes) fprintf(fout,"true"); else fprintf(fout,"false"); } if(ga->center != G_CENTER) { atleastone = output_separator(atleastone,fout); fprintf(fout, "center="); if(ga->center == yes) fprintf(fout,"true"); else fprintf(fout,"false"); } if(ga->landscape != G_LANDSCAPE) { atleastone = output_separator(atleastone,fout); fprintf(fout,"landscape="); if(ga->landscape == yes) fprintf(fout,"true"); else fprintf(fout,"false"); } fprintf(fout,"];"); } void new_node_attributes(struct node_attributes *na) { na->label = NA_LABEL; na->shape = NA_SHAPE; na->fillcolor = NA_FILLCOLOR; na->textcolor = NA_FONTCOLOR; na->bordercolor = NA_COLOR; } void new_edge_attributes(struct edge_attributes *ea) { ea->label = EA_LABEL; ea->weight = EA_WEIGHT; ea->color = EA_COLOR; ea->textcolor = EA_FONTCOLOR; ea->arrowstyle= EA_ARROWSTYLE; } void new_graph_attributes(struct graph_attributes *ga){ ga->orientation = G_ORIENTATION; ga->splines = G_SPLINES; ga->center = G_CENTER; ga->landscape = G_LANDSCAPE; } bool output_separator(bool atleastone, FILE *fout) { if(atleastone) { fprintf(fout,", "); } return true; }