Merge branch 'concept/ast-design' into 47-add-tests

This commit is contained in:
servostar 2024-05-07 07:48:12 +00:00 committed by GitHub
commit 0b832bf199
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
3 changed files with 243 additions and 8 deletions

165
src/ast/ast.c Normal file
View File

@ -0,0 +1,165 @@
#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");
}

56
src/ast/ast.h Normal file
View File

@ -0,0 +1,56 @@
#ifndef _AST_H_
#define _AST_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 {
// parent node that owns this node
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
// length of children array
size_t child_count;
// variable amount of child nodes
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
struct AST_Node_t *AST_new_node(enum AST_SyntaxElement_t kind, const char* value);
void AST_delete_node(struct AST_Node_t *);
// add a new child node
void AST_push_node(struct AST_Node_t *owner, struct AST_Node_t *child);
// get a specific child node
struct AST_Node_t *AST_get_node(struct AST_Node_t *owner, size_t idx);
// visit this and all of its child nodes calling the given function
// for every node
void AST_visit_nodes_recurse(struct AST_Node_t *root,
void (*for_each)(struct AST_Node_t *node,
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

View File

@ -1,6 +1,7 @@
#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>
#define LOG_LEVEL LOG_LEVEL_DEBUG #define LOG_LEVEL LOG_LEVEL_DEBUG
@ -65,13 +66,26 @@ int main(int argc, char *argv[]) {
FILE *file = fopen(filename, "r"); FILE *file = fopen(filename, "r");
if (NULL == file) struct AST_Node_t* node = AST_new_node(AST_Branch, NULL);
{
PANIC("File couldn't be opened!"); struct AST_Node_t* child = AST_new_node(AST_OperatorAdd, NULL);
} AST_push_node(child, AST_new_node(AST_IntegerLiteral, "43"));
yyin = file; AST_push_node(child, AST_new_node(AST_IntegerLiteral, "9"));
yyparse(); 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;
} }