166 lines
4.2 KiB
C
166 lines
4.2 KiB
C
|
|
#include <ast/ast.h>
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <sys/log.h>
|
|
|
|
struct AST_Node_t *AST_new_node(enum AST_SyntaxElement_t kind, const char* value) {
|
|
DEBUG("creating new AST node: %d \"%s\"", kind, value);
|
|
|
|
struct AST_Node_t *node = malloc(sizeof(struct AST_Node_t));
|
|
|
|
if (node == NULL) {
|
|
PANIC("failed to allocate AST node");
|
|
}
|
|
|
|
// init to discrete state
|
|
node->parent = NULL;
|
|
node->children = NULL;
|
|
node->child_count = 0;
|
|
node->kind = kind;
|
|
node->value = value;
|
|
|
|
return node;
|
|
}
|
|
|
|
const char* AST_node_to_string(struct AST_Node_t* node) {
|
|
DEBUG("converting AST node to string: %p", 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) {
|
|
DEBUG("Adding new node %p to %p", child, owner);
|
|
|
|
// if there are no children for now
|
|
if (owner->child_count == 0) {
|
|
DEBUG("Allocating new children array");
|
|
owner->children = malloc(sizeof(struct AST_Node_t *));
|
|
|
|
} else {
|
|
DEBUG("Rellocating old children array");
|
|
const size_t size = sizeof(struct AST_Node_t *) * (owner->child_count + 1);
|
|
owner->children = realloc(owner->children, size);
|
|
}
|
|
|
|
if (owner->children == NULL) {
|
|
PANIC("failed to allocate children array of AST node");
|
|
}
|
|
|
|
owner->children[owner->child_count++] = child;
|
|
}
|
|
|
|
struct AST_Node_t *AST_get_node(struct AST_Node_t *owner, size_t idx) {
|
|
DEBUG("retrvieng node %d from %p", idx, owner);
|
|
|
|
if (owner == NULL) {
|
|
PANIC("AST owner node is NULL");
|
|
}
|
|
|
|
if (owner->children == NULL) {
|
|
PANIC("AST owner node has no children");
|
|
}
|
|
|
|
struct AST_Node_t *child = owner->children[idx];
|
|
|
|
if (child == NULL) {
|
|
PANIC("child node is NULL");
|
|
}
|
|
|
|
return child;
|
|
}
|
|
|
|
void AST_delete_node(struct AST_Node_t *node) {
|
|
DEBUG("Deleting AST node: %p", node);
|
|
|
|
if (node == NULL) {
|
|
PANIC("Node to free is NULL");
|
|
}
|
|
|
|
if (node->children == NULL) {
|
|
return;
|
|
}
|
|
|
|
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,
|
|
void (*for_each)(struct AST_Node_t *node,
|
|
size_t depth),
|
|
size_t depth) {
|
|
DEBUG("Recursive visit of %p at %d with %p", root, depth, for_each);
|
|
|
|
(for_each)(root, depth);
|
|
|
|
for (size_t i = 0; i < root->child_count; i++) {
|
|
__AST_visit_nodes_recurse2(root->children[i], for_each, depth + 1);
|
|
}
|
|
}
|
|
|
|
void AST_visit_nodes_recurse(struct AST_Node_t *root,
|
|
void (*for_each)(struct AST_Node_t *node,
|
|
size_t depth)) {
|
|
DEBUG("Starting recursive visit of %p with %p", root, for_each);
|
|
__AST_visit_nodes_recurse2(root, for_each, 0);
|
|
}
|
|
|
|
static void __AST_fprint_graphviz_node_definition(FILE* stream, struct AST_Node_t* node) {
|
|
DEBUG("Printing graphviz definition of %p", node);
|
|
|
|
fprintf(stream, "\tnode%p [label=\"%s\"]\n", (void*) node, AST_node_to_string(node));
|
|
|
|
if (node->children == NULL) {
|
|
return;
|
|
}
|
|
|
|
for (size_t i = 0; i < node->child_count; i++) {
|
|
__AST_fprint_graphviz_node_definition(stream, node->children[i]);
|
|
}
|
|
}
|
|
|
|
static void __AST_fprint_graphviz_node_connection(FILE* stream, struct AST_Node_t* node) {
|
|
DEBUG("Printing graphviz connection of %p", node);
|
|
|
|
if (node->children == NULL) {
|
|
return;
|
|
}
|
|
|
|
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) {
|
|
DEBUG("Starting print of graphviz graph of %p", root);
|
|
|
|
fprintf(stream, "graph {\n");
|
|
|
|
__AST_fprint_graphviz_node_definition(stream, root);
|
|
__AST_fprint_graphviz_node_connection(stream, root);
|
|
|
|
fprintf(stream, "}\n");
|
|
}
|