added function to convert AST to graphviz diagram
This commit is contained in:
parent
e918139f88
commit
914935aafb
|
@ -1,10 +1,11 @@
|
||||||
|
|
||||||
#include <ast/ast.h>
|
#include <ast/ast.h>
|
||||||
|
#include <bits/posix2_lim.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <sys/log.h>
|
#include <sys/log.h>
|
||||||
|
|
||||||
struct AST_Node_t *AST_new_node(void) {
|
struct AST_Node_t *AST_new_node(enum AST_SyntaxElement_t kind, const char* value) {
|
||||||
struct AST_Node_t *node = malloc(sizeof(struct AST_Node_t));
|
struct AST_Node_t *node = malloc(sizeof(struct AST_Node_t));
|
||||||
|
|
||||||
if (node == NULL) {
|
if (node == NULL) {
|
||||||
|
@ -15,10 +16,36 @@ struct AST_Node_t *AST_new_node(void) {
|
||||||
node->parent = NULL;
|
node->parent = NULL;
|
||||||
node->children = NULL;
|
node->children = NULL;
|
||||||
node->child_count = 0;
|
node->child_count = 0;
|
||||||
|
node->kind = kind;
|
||||||
|
node->value = value;
|
||||||
|
|
||||||
return node;
|
return node;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const char* AST_node_to_string(struct AST_Node_t* node) {
|
||||||
|
const char* string = "unknown";
|
||||||
|
|
||||||
|
switch (node->kind) {
|
||||||
|
case AST_Expression:
|
||||||
|
string = "expression";
|
||||||
|
break;
|
||||||
|
case AST_Statement:
|
||||||
|
string = "statement";
|
||||||
|
break;
|
||||||
|
case AST_Branch:
|
||||||
|
string = "if";
|
||||||
|
break;
|
||||||
|
case AST_IntegerLiteral:
|
||||||
|
string = node->value;
|
||||||
|
break;
|
||||||
|
case AST_OperatorAdd:
|
||||||
|
string = "+";
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return string;
|
||||||
|
}
|
||||||
|
|
||||||
void AST_push_node(struct AST_Node_t *owner, struct AST_Node_t *child) {
|
void AST_push_node(struct AST_Node_t *owner, struct AST_Node_t *child) {
|
||||||
// if there are no children for now
|
// if there are no children for now
|
||||||
if (owner->child_count == 0) {
|
if (owner->child_count == 0) {
|
||||||
|
@ -54,8 +81,16 @@ struct AST_Node_t *AST_get_node(struct AST_Node_t *owner, size_t idx) {
|
||||||
return child;
|
return child;
|
||||||
}
|
}
|
||||||
|
|
||||||
void AST_delete_node(struct AST_Node_t *_) {
|
void AST_delete_node(struct AST_Node_t *node) {
|
||||||
#warning "FIXME: not implemented"
|
if (node == NULL) {
|
||||||
|
PANIC("Node to free is NULL");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (node->children != NULL) {
|
||||||
|
for (size_t i = 0; i < node->child_count; i++) {
|
||||||
|
AST_delete_node(node->children[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void __AST_visit_nodes_recurse2(struct AST_Node_t *root,
|
static void __AST_visit_nodes_recurse2(struct AST_Node_t *root,
|
||||||
|
@ -74,3 +109,33 @@ void AST_visit_nodes_recurse(struct AST_Node_t *root,
|
||||||
size_t depth)) {
|
size_t depth)) {
|
||||||
__AST_visit_nodes_recurse2(root, for_each, 0);
|
__AST_visit_nodes_recurse2(root, for_each, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void AST_fprint_graphviz_node_definition(FILE* stream, struct AST_Node_t* node) {
|
||||||
|
|
||||||
|
fprintf(stream, "\tnode%p [label=\"%s\"]\n", (void*) node, AST_node_to_string(node));
|
||||||
|
|
||||||
|
if (node->children != NULL) {
|
||||||
|
for (size_t i = 0; i < node->child_count; i++) {
|
||||||
|
AST_fprint_graphviz_node_definition(stream, node->children[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void AST_fprint_graphviz_node_connection(FILE* stream, struct AST_Node_t* node) {
|
||||||
|
|
||||||
|
if (node->children != NULL) {
|
||||||
|
for (size_t i = 0; i < node->child_count; i++) {
|
||||||
|
fprintf(stream, "\tnode%p -- node%p\n", (void*) node, (void*) node->children[i]);
|
||||||
|
AST_fprint_graphviz_node_connection(stream, node->children[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void AST_fprint_graphviz(FILE* stream, struct AST_Node_t* root) {
|
||||||
|
fprintf(stream, "graph {\n");
|
||||||
|
|
||||||
|
AST_fprint_graphviz_node_definition(stream, root);
|
||||||
|
AST_fprint_graphviz_node_connection(stream, root);
|
||||||
|
|
||||||
|
fprintf(stream, "}\n");
|
||||||
|
}
|
||||||
|
|
|
@ -4,10 +4,24 @@
|
||||||
|
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
|
|
||||||
|
// Syntax elements which are stored in a syntax tree
|
||||||
|
enum AST_SyntaxElement_t {
|
||||||
|
AST_Statement,
|
||||||
|
AST_Expression,
|
||||||
|
AST_Branch,
|
||||||
|
AST_OperatorAdd,
|
||||||
|
AST_IntegerLiteral
|
||||||
|
};
|
||||||
|
|
||||||
struct AST_Node_t {
|
struct AST_Node_t {
|
||||||
// parent node that owns this node
|
// parent node that owns this node
|
||||||
struct AST_Node_t *parent;
|
struct AST_Node_t *parent;
|
||||||
|
|
||||||
|
// type of AST node: if, declration, ...
|
||||||
|
enum AST_SyntaxElement_t kind;
|
||||||
|
// optional value: integer literal, string literal, ...
|
||||||
|
const char* value;
|
||||||
|
|
||||||
// number of child nodes ownd by this node
|
// number of child nodes ownd by this node
|
||||||
// length of children array
|
// length of children array
|
||||||
size_t child_count;
|
size_t child_count;
|
||||||
|
@ -15,8 +29,12 @@ struct AST_Node_t {
|
||||||
struct AST_Node_t **children;
|
struct AST_Node_t **children;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// return a string representation of the nodes type and its value
|
||||||
|
// does not take into account its children or parent
|
||||||
|
const char* AST_node_to_string(struct AST_Node_t* node);
|
||||||
|
|
||||||
// create a new initialized (empty) node
|
// create a new initialized (empty) node
|
||||||
struct AST_Node_t *AST_new_node(void);
|
struct AST_Node_t *AST_new_node(enum AST_SyntaxElement_t kind, const char* value);
|
||||||
|
|
||||||
void AST_delete_node(struct AST_Node_t *);
|
void AST_delete_node(struct AST_Node_t *);
|
||||||
|
|
||||||
|
@ -32,4 +50,7 @@ void AST_visit_nodes_recurse(struct AST_Node_t *root,
|
||||||
void (*for_each)(struct AST_Node_t *node,
|
void (*for_each)(struct AST_Node_t *node,
|
||||||
size_t depth));
|
size_t depth));
|
||||||
|
|
||||||
|
// print a graphviz diagram of the supplied node (as root node) into stream
|
||||||
|
void AST_fprint_graphviz(FILE* stream, struct AST_Node_t* node);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
24
src/main.c
24
src/main.c
|
@ -1,3 +1,5 @@
|
||||||
|
#include <ast/ast.h>
|
||||||
|
#include <stdio.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <sys/log.h>
|
#include <sys/log.h>
|
||||||
#include <yacc/parser.tab.h>
|
#include <yacc/parser.tab.h>
|
||||||
|
@ -36,6 +38,26 @@ void setup(void)
|
||||||
int main(void) {
|
int main(void) {
|
||||||
setup();
|
setup();
|
||||||
|
|
||||||
yyparse();
|
struct AST_Node_t* node = AST_new_node(AST_Branch, NULL);
|
||||||
|
|
||||||
|
struct AST_Node_t* child = AST_new_node(AST_OperatorAdd, NULL);
|
||||||
|
AST_push_node(child, AST_new_node(AST_IntegerLiteral, "43"));
|
||||||
|
AST_push_node(child, AST_new_node(AST_IntegerLiteral, "9"));
|
||||||
|
|
||||||
|
AST_push_node(node, child);
|
||||||
|
AST_push_node(node, AST_new_node(AST_Expression, NULL));
|
||||||
|
AST_push_node(node, AST_new_node(AST_Expression, NULL));
|
||||||
|
|
||||||
|
FILE* out = fopen("ast.gv", "w+");
|
||||||
|
// convert this file ^^^^^^
|
||||||
|
// to an svg with: `dot -Tsvg ast.gv > graph.svg`
|
||||||
|
|
||||||
|
AST_fprint_graphviz(out, node);
|
||||||
|
|
||||||
|
AST_delete_node(node);
|
||||||
|
|
||||||
|
fflush(out);
|
||||||
|
fclose(out);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue