Add function for rendering the stack as a DOT graph

This commit is contained in:
Max Brunsfeld 2016-02-23 00:08:55 -08:00
parent b99c257e9e
commit 6dd92c3abe
2 changed files with 79 additions and 0 deletions

View file

@ -475,3 +475,80 @@ void ts_stack_delete(Stack *self) {
array_delete(&self->heads);
ts_free(self);
}
size_t ts_stack__write_dot_graph(Stack *self, char *string, size_t n,
const char **symbol_names) {
char *cursor = string;
char **s = n > 0 ? &cursor : &string;
cursor += snprintf(*s, n, "digraph stack {\n");
cursor += snprintf(*s, n, "rankdir=\"RL\";\n");
cursor += snprintf(*s, n, "node_%p [label=\"0:NULL\"];\n", NULL);
array_clear(&self->pop_paths);
for (int i = 0; i < self->heads.size; i++)
array_push(&self->pop_paths, ((PopPath){
.node = self->heads.contents[i],
}));
bool all_paths_done = false;
while (!all_paths_done) {
all_paths_done = true;
for (size_t i = 0; i < self->pop_paths.size; i++) {
PopPath *path = &self->pop_paths.contents[i];
StackNode *node = path->node;
if (!node)
continue;
all_paths_done = false;
cursor += snprintf(*s, n, "node_%p [label=\"%d:%s\"];\n", node,
node->entry.state,
symbol_names[node->entry.tree->symbol]);
path->node = node->successors[0];
cursor += snprintf(*s, n, "node_%p -> node_%p;\n", node, node->successors[0]);
for (int j = 1; j < node->successor_count; j++) {
if (!array_push(&self->pop_paths, *path))
goto error;
cursor += snprintf(*s, n, "node_%p -> node_%p;\n", node, node->successors[j]);
PopPath *next_path = array_back(&self->pop_paths);
next_path->node = node->successors[j];
next_path->is_shared = true;
}
}
}
cursor += snprintf(*s, n, "}\n");
return cursor - string;
error:
return (size_t)-1;
}
char *ts_stack_dot_graph(Stack *self, const char **symbol_names) {
static char SCRATCH[1];
char *result = NULL;
size_t size = ts_stack__write_dot_graph(self, SCRATCH, 0, symbol_names) + 1;
if (size == -1)
goto error;
result = ts_malloc(size * sizeof(char));
if (!result)
goto error;
size = ts_stack__write_dot_graph(self, result, size, symbol_names);
if (size == -1)
goto error;
return result;
error:
if (result)
ts_free(result);
return NULL;
}