-/* Output a VCG description on generated parser, for bison,
- Copyright 1984, 1986, 1989, 2000, 2001 Free Software Foundation, Inc.
+/* Output a VCG description on generated parser, for Bison,
+ Copyright 2001 Free Software Foundation, Inc.
This file is part of Bison, the GNU Compiler Compiler.
#include "obstack.h"
#include "print_graph.h"
#include "vcg.h"
+#include "quotearg.h"
static graph_t graph;
+static unsigned node_output_size = 0;
+
+/* Return an unambiguous printable representated, allocated in slot 0,
+ for NAME, suitable for C strings. */
+static char const *
+quote (char const *name)
+{
+ return quotearg_n_style (0, escape_quoting_style, name);
+}
+
/* This part will construct the label of nodes. */
static void
-print_core (int state)
+print_core (int state, struct obstack *node_obstack)
{
int i;
int k;
core *statep;
short *sp;
short *sp1;
-
+
statep = state_table[state];
k = statep->nitems;
if (k == 0)
return;
-
- obstack_sgrow(&graph_obstack, "\t\tlabel:\t\"");
for (i = 0; i < k; i++)
{
+ if (i)
+ obstack_sgrow (node_obstack, "\\n");
+
sp1 = sp = ritem + statep->items[i];
while (*sp > 0)
rule = -(*sp);
- obstack_fgrow1(&graph_obstack, _("%d: "), rule);
- obstack_fgrow1(&graph_obstack, " %s -> ", tags[rlhs[rule]]);
+ obstack_fgrow1 (node_obstack, "%d: ", rule);
+ obstack_fgrow1 (node_obstack, " %s -> ", quote (tags[rlhs[rule]]));
for (sp = ritem + rrhs[rule]; sp < sp1; sp++)
- obstack_fgrow1(&graph_obstack, "%s ", tags[*sp]);
+ obstack_fgrow1 (node_obstack, "%s ", quote (tags[*sp]));
+
+ obstack_1grow (node_obstack, '.');
- obstack_1grow(&graph_obstack, '.');
-
while (*sp > 0)
- obstack_fgrow1(&graph_obstack, " %s", tags[*sp++]);
-
- obstack_sgrow(&graph_obstack, "\\n");
+ obstack_fgrow1 (node_obstack, " %s", quote (tags[*sp++]));
}
- obstack_sgrow(&graph_obstack, "\"\n");
}
+/* Output in graph_obstack edges specifications in incidence with current
+ node. */
static void
-print_actions (int state, node_t *node)
+print_actions (int state, const char *node_name, struct obstack *node_obstack)
{
int i;
int k;
int rule;
static char buff[10];
edge_t edge;
-
+
shiftp = shift_table[state];
redp = reduction_table[state];
errp = err_table[state];
if (!shiftp && !redp)
{
if (final_state == state)
- ;//fprintf(f, " $default\taccept\n");
+ obstack_sgrow (node_obstack, "$default: accept");
else
- ;//fprintf(f, " NO ACTIONS\n");
+ obstack_sgrow (node_obstack, "NO ACTIONS");
return;
}
if (ISVAR (symbol))
break;
-
+
{
new_edge (&edge);
if (state > state1)
edge.type = back_edge;
open_edge (&edge, &graph_obstack);
- edge.sourcename = node->title;
+ /* The edge source is the current node. */
+ edge.sourcename = node_name;
+ sprintf (buff, "%d", state1);
edge.targetname = buff;
- sprintf (edge.targetname, "%d", state1);
- edge.color = (symbol == 0) ? blue : red;
- edge.label = tags[symbol];
- output_edge (&edge, &graph_obstack);
+ edge.color = (symbol == 0) ? red : blue;
+ /* FIXME: Be aware that quote uses static memory. The string
+ must be output immediately (which is the case here). */
+ edge.label = tags[symbol] ? quote (tags[symbol]) : NULL;
+ output_edge (&edge, &graph_obstack);
close_edge (&graph_obstack);
- }
+ }
}
}
else
if (!errp->errs[j])
continue;
symbol = errp->errs[j];
+ /* If something has been added in the NODE_OBSTACK after
+ the declaration of the label, then we need a `\n'. */
+ if (obstack_object_size (node_obstack) > node_output_size)
+ obstack_sgrow (node_obstack, "\\n");
+ obstack_fgrow1 (node_obstack, _("%-4s\terror (nonassociative)"),
+ tags[symbol]);
}
+ if (j > 0)
+ obstack_sgrow (node_obstack, "\\n");
}
-
+
if (consistent[state] && redp)
{
rule = redp->rules[0];
symbol = rlhs[rule];
+ if (obstack_object_size (node_obstack) > node_output_size)
+ obstack_sgrow (node_obstack, "\\n");
+ obstack_fgrow2 (node_obstack, _("$default\treduce using rule %d (%s)"),
+ rule, tags[symbol]);
}
-
+
if (i < k)
{
for (; i < k; i++)
new_edge (&edge);
open_edge (&edge, &graph_obstack);
- edge.sourcename = node->title;
+ edge.sourcename = node_name;
+ sprintf (buff, "%d", state1);
edge.targetname = buff;
edge.color = red;
- sprintf (edge.targetname, "%d", state1);
- edge.label = tags[symbol];
+ edge.label = tags[symbol] ? quote (tags[symbol]) : NULL;
output_edge (&edge, &graph_obstack);
close_edge (&graph_obstack);
}
}
}
+/* Output in GRAPH_OBSTACK the current node specifications and edges
+ which go out from that node. */
static void
print_state (int state)
{
static char name[10];
- node_t node;
+ struct obstack node_obstack;
+ node_t node;
- new_node (&node);
- open_node (&graph_obstack);
-
- sprintf(name, "%d", state);
- node.title = name;
- output_node (&node, &graph_obstack);
+ obstack_init (&node_obstack);
+ new_node (&node); /* Set node attributs default value. */
+ sprintf (name, "%d", state);
+ node.title = name; /* Give a name to the node. */
+ open_node (&node_obstack);
+ /* Output a VCG formatted attributs list. */
+ output_node (&node, &node_obstack);
- print_core (state); /* node label */
+ {
+ /* Here we begin to compute the node label. */
+ obstack_sgrow (&node_obstack, "\t\tlabel:\t\""); /* Open Label */
+
+ /* Keep the size of NODE_OBSTACK before computing the label. It is
+ useful to format the label. */
+ node_output_size = obstack_object_size (&node_obstack);
+
+ /* Compute the labels of nodes on the fly. */
+ print_core (state, &node_obstack);
+ /* Compute edges and additionnal parts of node label. */
+ print_actions (state, node.title, &node_obstack);
+
+ obstack_sgrow (&node_obstack, "\"\n"); /* Close Label. */
+
+ close_node (&node_obstack);
+ }
- close_node (&graph_obstack);
-
- print_actions (state, &node); /* edges */
+ /* `obstack_cat' NODE_OBSTACK to GRAPH_OBSTACK. */
+ obstack_grow (&graph_obstack,
+ obstack_base (&node_obstack),
+ obstack_object_size (&node_obstack));
+ obstack_finish (&node_obstack);
}
\f
print_graph (void)
{
int i;
-
+
if (!graph_flag)
- return ;
+ return;
new_graph (&graph);
-
- /* graph.smanhattan_edges = yes;
- graph.manhattan_edges = yes; */
-
+
+#if 0
+ graph.smanhattan_edges = yes;
+ graph.manhattan_edges = yes;
+#endif
+
graph.display_edge_labels = yes;
graph.layoutalgorithm = 0;
-
+
graph.port_sharing = no;
graph.finetuning = yes;
graph.straight_phase = yes;
graph.priority_phase = yes;
graph.splines = yes;
-
+
graph.crossing_weight = median;
/* Output graph options. */
output_graph (&graph, &graph_obstack);
for (i = 0; i < nstates; i++)
- /* Output nodes & edges. */
- print_state (i);
+ /* Output nodes & edges. */
+ print_state (i);
/* Close graph. */
close_graph (&graph, &graph_obstack);
}
-