changed ast implementation to use glib

This commit is contained in:
Sven Vogel 2024-06-05 14:08:52 +02:00
parent aa5d0b0710
commit f069d04ad1
2 changed files with 248 additions and 259 deletions

View File

@ -5,117 +5,130 @@
#include <sys/log.h> #include <sys/log.h>
#include <assert.h> #include <assert.h>
struct AST_Node_t *AST_new_node(TokenLocation location, enum AST_SyntaxElement_t kind, const char* value) { struct AST_Node_t {
DEBUG("creating new AST node: %d \"%s\"", kind, value); // parent node that owns this node
assert(kind < AST_ELEMENT_COUNT); struct AST_Node_t *parent;
struct AST_Node_t *node = malloc(sizeof(struct AST_Node_t)); // type of AST node: if, declaration, ...
enum AST_SyntaxElement_t kind;
// optional value: integer literal, string literal, ...
const char *value;
if (node == NULL) { TokenLocation location;
PANIC("failed to allocate AST node");
}
assert(node != NULL); GArray *children;
};
// init to discrete state AST_NODE_PTR AST_new_node(TokenLocation location, enum AST_SyntaxElement_t kind, const char *value) {
node->parent = NULL; DEBUG("creating new AST node: %d \"%s\"", kind, value);
node->children = NULL; assert(kind < AST_ELEMENT_COUNT);
node->child_count = 0;
node->kind = kind;
node->value = value;
node->location = location;
return node; AST_NODE_PTR node = malloc(sizeof(struct AST_Node_t));
if (node == NULL) {
PANIC("failed to allocate AST node");
}
assert(node != NULL);
// init to discrete state
node->parent = NULL;
node->children = NULL;
node->kind = kind;
node->value = value;
node->location = location;
return node;
} }
static const char* lookup_table[AST_ELEMENT_COUNT] = { "__UNINIT__" }; static const char *lookup_table[AST_ELEMENT_COUNT] = {"__UNINIT__"};
void AST_init() { void AST_init() {
DEBUG("initializing global syntax tree..."); DEBUG("initializing global syntax tree...");
INFO("filling lookup table..."); INFO("filling lookup table...");
lookup_table[AST_Stmt] = "stmt"; lookup_table[AST_Stmt] = "stmt";
lookup_table[AST_Module] = "module"; lookup_table[AST_Module] = "module";
lookup_table[AST_Expr] = "expr"; lookup_table[AST_Expr] = "expr";
lookup_table[AST_Add] = "+"; lookup_table[AST_Add] = "+";
lookup_table[AST_Sub] = "-"; lookup_table[AST_Sub] = "-";
lookup_table[AST_Mul] = "*"; lookup_table[AST_Mul] = "*";
lookup_table[AST_Div] = "/"; lookup_table[AST_Div] = "/";
lookup_table[AST_BitAnd] = "&"; lookup_table[AST_BitAnd] = "&";
lookup_table[AST_BitOr] = "|"; lookup_table[AST_BitOr] = "|";
lookup_table[AST_BitXor] = "^"; lookup_table[AST_BitXor] = "^";
lookup_table[AST_BitNot] = "!"; lookup_table[AST_BitNot] = "!";
lookup_table[AST_Eq] = "=="; lookup_table[AST_Eq] = "==";
lookup_table[AST_Less] = "<"; lookup_table[AST_Less] = "<";
lookup_table[AST_Greater] = ">"; lookup_table[AST_Greater] = ">";
lookup_table[AST_BoolAnd] = "&&"; lookup_table[AST_BoolAnd] = "&&";
lookup_table[AST_BoolOr] = "||"; lookup_table[AST_BoolOr] = "||";
lookup_table[AST_BoolXor] = "^^"; lookup_table[AST_BoolXor] = "^^";
lookup_table[AST_BoolNot] = "!!"; lookup_table[AST_BoolNot] = "!!";
lookup_table[AST_While] = "while"; lookup_table[AST_While] = "while";
lookup_table[AST_If] = "if"; lookup_table[AST_If] = "if";
lookup_table[AST_IfElse] = "else if"; lookup_table[AST_IfElse] = "else if";
lookup_table[AST_Else] = "else"; lookup_table[AST_Else] = "else";
lookup_table[AST_Decl] = "decl"; lookup_table[AST_Decl] = "decl";
lookup_table[AST_Assign] = "assign"; lookup_table[AST_Assign] = "assign";
lookup_table[AST_Def] = "def"; lookup_table[AST_Def] = "def";
lookup_table[AST_Typedef] = "typedef"; lookup_table[AST_Typedef] = "typedef";
lookup_table[AST_Box] = "box"; lookup_table[AST_Box] = "box";
lookup_table[AST_Fun] = "fun"; lookup_table[AST_Fun] = "fun";
lookup_table[AST_Call] = "funcall"; lookup_table[AST_Call] = "funcall";
lookup_table[AST_Typecast] = "typecast"; lookup_table[AST_Typecast] = "typecast";
lookup_table[AST_Transmute] = "transmute"; lookup_table[AST_Transmute] = "transmute";
lookup_table[AST_Condition] = "condition"; lookup_table[AST_Condition] = "condition";
lookup_table[AST_List] = "list"; lookup_table[AST_List] = "list";
lookup_table[AST_ExprList] = "expr list"; lookup_table[AST_ExprList] = "expr list";
lookup_table[AST_ArgList] = "arg list"; lookup_table[AST_ArgList] = "arg list";
lookup_table[AST_ParamList] = "param list"; lookup_table[AST_ParamList] = "param list";
lookup_table[AST_StmtList] = "stmt list"; lookup_table[AST_StmtList] = "stmt list";
lookup_table[AST_IdentList] = "ident list"; lookup_table[AST_IdentList] = "ident list";
lookup_table[AST_Type] = "type"; lookup_table[AST_Type] = "type";
lookup_table[AST_Negate] = "-"; lookup_table[AST_Negate] = "-";
lookup_table[AST_Parameter] = "parameter"; lookup_table[AST_Parameter] = "parameter";
lookup_table[AST_ParamDecl] = "parameter-declaration"; lookup_table[AST_ParamDecl] = "parameter-declaration";
lookup_table[AST_AddressOf] = "address of"; lookup_table[AST_AddressOf] = "address of";
lookup_table[AST_Dereference] = "deref"; lookup_table[AST_Dereference] = "deref";
lookup_table[AST_Reference] = "ref"; lookup_table[AST_Reference] = "ref";
} }
const char* AST_node_to_string(const struct AST_Node_t* node) { const char *AST_node_to_string(AST_NODE_PTR node) {
DEBUG("converting AST node to string: %p", node); DEBUG("converting AST node to string: %p", node);
assert(node != NULL); assert(node != NULL);
const char* string; const char *string;
switch(node->kind) { switch (node->kind) {
case AST_Int: case AST_Int:
case AST_Float: case AST_Float:
case AST_String: case AST_String:
case AST_Ident: case AST_Ident:
case AST_Macro: case AST_Macro:
case AST_Import: case AST_Import:
case AST_Storage: case AST_Storage:
case AST_Typekind: case AST_Typekind:
case AST_Sign: case AST_Sign:
case AST_Scale: case AST_Scale:
case AST_Qualifyier: case AST_Qualifyier:
string = node->value; string = node->value;
break; break;
default: default:
string = lookup_table[node->kind]; string = lookup_table[node->kind];
} }
assert(string != NULL); assert(string != NULL);
return string; return string;
} }
static inline unsigned long int min(unsigned long int a, unsigned long int b) { static inline unsigned long int min(unsigned long int a, unsigned long int b) {
@ -126,182 +139,174 @@ static inline unsigned long int max(unsigned long int a, unsigned long int b) {
return a > b ? a : b; return a > b ? a : b;
} }
void AST_push_node(struct AST_Node_t *owner, struct AST_Node_t *child) { void AST_push_node(AST_NODE_PTR owner, AST_NODE_PTR child) {
DEBUG("Adding new node %p to %p", child, owner); DEBUG("Adding new node %p to %p", child, owner);
assert(owner != NULL); assert(owner != NULL);
assert(child != NULL); assert(child != NULL);
// if there are no children for now // if there are no children for now
if (owner->child_count == 0) { if (owner->children == NULL) {
DEBUG("Allocating new children array"); DEBUG("Allocating new children array");
owner->children = malloc(sizeof(struct AST_Node_t *)); owner->children = g_array_new(FALSE, FALSE, sizeof(AST_NODE_PTR));
} 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->location.col_end = max(owner->location.col_end, child->location.col_end);
owner->location.line_end = max(owner->location.line_end, child->location.line_end);
owner->location.col_start = min(owner->location.col_start, child->location.col_start);
owner->location.line_start = min(owner->location.line_start, child->location.line_start);
assert(owner->children != NULL);
owner->children[owner->child_count++] = child;
}
struct AST_Node_t *AST_get_node(struct AST_Node_t *owner, const size_t idx) {
DEBUG("retrvieng node %d from %p", idx, owner);
assert(owner != NULL);
assert(owner->children != NULL);
assert(idx < owner->child_count);
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;
}
struct AST_Node_t* AST_remove_child(struct AST_Node_t* owner, const size_t idx) {
assert(owner != NULL);
assert(owner->children != NULL);
assert(idx < owner->child_count);
struct AST_Node_t* child = owner->children[idx];
child->parent = NULL;
owner->child_count--;
// shift back every following element by one
for (size_t i = idx; i < owner->child_count; i++) {
owner->children[i] = owner->children[i + 1];
}
return child;
}
struct AST_Node_t* AST_detach_child(struct AST_Node_t* owner, const struct AST_Node_t* child) {
assert(owner != NULL);
assert(child != NULL);
assert(owner->children != NULL);
for (size_t i = 0; i < owner->child_count; i++) {
if (owner->children[i] == child) {
return AST_remove_child(owner, i);
} }
}
PANIC("Child to detach not a child of parent"); if (owner->children == NULL) {
PANIC("failed to allocate children array of AST node");
}
owner->location.col_end = max(owner->location.col_end, child->location.col_end);
owner->location.line_end = max(owner->location.line_end, child->location.line_end);
owner->location.col_start = min(owner->location.col_start, child->location.col_start);
owner->location.line_start = min(owner->location.line_start, child->location.line_start);
assert(owner->children != NULL);
g_array_append_val(owner->children, child);
} }
void AST_delete_node(struct AST_Node_t *node) { AST_NODE_PTR AST_get_node(AST_NODE_PTR owner, const size_t idx) {
assert(node != NULL); DEBUG("retrvieng node %d from %p", idx, owner);
assert(owner != NULL);
assert(owner->children != NULL);
assert(idx < owner->children->len);
DEBUG("Deleting AST node: %p", node); if (owner->children == NULL) {
PANIC("AST owner node has no children");
}
if (node->children == NULL) { AST_NODE_PTR child = ((AST_NODE_PTR*) owner->children->data)[idx];
return;
}
if (node->parent != NULL) { if (child == NULL) {
const struct AST_Node_t* child = AST_detach_child(node->parent, node); PANIC("child node is NULL");
assert(child == node); }
}
for (size_t i = 0; i < node->child_count; i++) { return child;
// prevent detach of children node
node->children[i]->parent = NULL;
AST_delete_node(node->children[i]);
}
free(node->children);
free(node);
} }
static void AST_visit_nodes_recurse2(struct AST_Node_t *root, AST_NODE_PTR AST_remove_child(AST_NODE_PTR owner, const size_t idx) {
void (*for_each)(struct AST_Node_t *node, assert(owner != NULL);
size_t depth), assert(owner->children != NULL);
const size_t depth) { assert(idx < owner->children->len);
DEBUG("Recursive visit of %p at %d with %p", root, depth, for_each);
assert(root != NULL); AST_NODE_PTR child = AST_get_node(owner, idx);
(for_each)(root, depth); child->parent = NULL;
for (size_t i = 0; i < root->child_count; i++) { g_array_remove_index(owner->children, idx);
AST_visit_nodes_recurse2(root->children[i], for_each, depth + 1);
} return child;
} }
void AST_visit_nodes_recurse(struct AST_Node_t *root, AST_NODE_PTR AST_detach_child(AST_NODE_PTR owner, AST_NODE_PTR child) {
void (*for_each)(struct AST_Node_t *node, assert(owner != NULL);
assert(child != NULL);
assert(owner->children != NULL);
for (size_t i = 0; i < owner->children->len; i++) {
if (AST_get_node(owner, i) == child) {
return AST_remove_child(owner, i);
}
}
PANIC("Child to detach not a child of parent");
}
void AST_delete_node(AST_NODE_PTR node) {
assert(node != NULL);
DEBUG("Deleting AST node: %p", node);
if (node->children == NULL) {
return;
}
if (node->parent != NULL) {
AST_NODE_PTR child = AST_detach_child(node->parent, node);
assert(child == node);
}
for (size_t i = 0; i < node->children->len; i++) {
// prevent detach of children node
AST_NODE_PTR child = AST_get_node(node, i);
child->parent = NULL;
AST_delete_node(child);
}
g_array_free(node->children, TRUE);
free(node);
}
static void AST_visit_nodes_recurse2(AST_NODE_PTR root,
void (*for_each)(AST_NODE_PTR node,
size_t depth),
const size_t depth) {
DEBUG("Recursive visit of %p at %d with %p", root, depth, for_each);
assert(root != NULL);
(for_each)(root, depth);
for (size_t i = 0; i < root->children->len; i++) {
AST_visit_nodes_recurse2(AST_get_node(root, i), for_each, depth + 1);
}
}
void AST_visit_nodes_recurse(AST_NODE_PTR root,
void (*for_each)(AST_NODE_PTR node,
size_t depth)) { size_t depth)) {
DEBUG("Starting recursive visit of %p with %p", root, for_each); DEBUG("Starting recursive visit of %p with %p", root, for_each);
assert(root != NULL); assert(root != NULL);
assert(for_each != NULL); assert(for_each != NULL);
AST_visit_nodes_recurse2(root, for_each, 0); AST_visit_nodes_recurse2(root, for_each, 0);
} }
static void AST_fprint_graphviz_node_definition(FILE* stream, const struct AST_Node_t* node) { static void AST_fprint_graphviz_node_definition(FILE *stream, AST_NODE_PTR node) {
DEBUG("Printing graphviz definition of %p", node); DEBUG("Printing graphviz definition of %p", node);
assert(stream != NULL); assert(stream != NULL);
assert(node != NULL); assert(node != NULL);
fprintf(stream, "\tnode%p [label=\"%s\"]\n", (void*) node, AST_node_to_string(node)); fprintf(stream, "\tnode%p [label=\"%s\"]\n", (void *) node, AST_node_to_string(node));
if (node->children == NULL) { if (node->children == NULL) {
return; return;
} }
for (size_t i = 0; i < node->child_count; i++) { for (size_t i = 0; i < node->children->len; i++) {
AST_fprint_graphviz_node_definition(stream, node->children[i]); AST_fprint_graphviz_node_definition(stream, AST_get_node(node, i));
} }
} }
static void AST_fprint_graphviz_node_connection(FILE* stream, const struct AST_Node_t* node) { static void AST_fprint_graphviz_node_connection(FILE *stream, AST_NODE_PTR node) {
DEBUG("Printing graphviz connection of %p", node); DEBUG("Printing graphviz connection of %p", node);
assert(stream != NULL); assert(stream != NULL);
assert(node != NULL); assert(node != NULL);
if (node->children == NULL) { if (node->children == NULL) {
return; return;
} }
for (size_t i = 0; i < node->child_count; i++) { for (size_t i = 0; i < node->children->len; i++) {
fprintf(stream, "\tnode%p -- node%p\n", (void*) node, (void*) node->children[i]); AST_NODE_PTR child = AST_get_node(node, i);
AST_fprint_graphviz_node_connection(stream, node->children[i]); fprintf(stream, "\tnode%p -- node%p\n", (void *) node, (void *) child);
} AST_fprint_graphviz_node_connection(stream, child);
}
} }
void AST_fprint_graphviz(FILE* stream, const struct AST_Node_t* root) { void AST_fprint_graphviz(FILE *stream, AST_NODE_PTR root) {
DEBUG("Starting print of graphviz graph of %p", root); DEBUG("Starting print of graphviz graph of %p", root);
assert(stream != NULL); assert(stream != NULL);
assert(root != NULL); assert(root != NULL);
fprintf(stream, "graph {\n"); fprintf(stream, "graph {\n");
AST_fprint_graphviz_node_definition(stream, root); AST_fprint_graphviz_node_definition(stream, root);
AST_fprint_graphviz_node_connection(stream, root); AST_fprint_graphviz_node_connection(stream, root);
fprintf(stream, "}\n"); fprintf(stream, "}\n");
} }

View File

@ -1,6 +1,6 @@
#ifndef _AST_H_ #ifndef AST_H_
#define _AST_H_ #define AST_H_
#include <stdio.h> #include <stdio.h>
#include <io/files.h> #include <io/files.h>
@ -89,23 +89,7 @@ enum AST_SyntaxElement_t {
* - kind: The type of the node. Such as AST_Expr, AST_Add, ... * - kind: The type of the node. Such as AST_Expr, AST_Add, ...
* - value: A string representing an optional value. Can be a integer literal for kind AST_int * - value: A string representing an optional value. Can be a integer literal for kind AST_int
*/ */
struct AST_Node_t { struct AST_Node_t;
// parent node that owns this node
struct AST_Node_t *parent;
// type of AST node: if, declaration, ...
enum AST_SyntaxElement_t kind;
// optional value: integer literal, string literal, ...
const char* value;
TokenLocation location;
// 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;
};
/** /**
* Shorthand type for a single AST node * Shorthand type for a single AST node
@ -126,7 +110,7 @@ void AST_init(void);
*/ */
[[maybe_unused]] [[maybe_unused]]
[[gnu::nonnull(1)]] [[gnu::nonnull(1)]]
const char* AST_node_to_string(const struct AST_Node_t* node); const char* AST_node_to_string(AST_NODE_PTR node);
/** /**
* @brief Create a new node struct on the system heap. Initializes the struct with the given values. * @brief Create a new node struct on the system heap. Initializes the struct with the given values.
@ -139,7 +123,7 @@ const char* AST_node_to_string(const struct AST_Node_t* node);
[[maybe_unused]] [[maybe_unused]]
[[nodiscard("pointer must be freed")]] [[nodiscard("pointer must be freed")]]
[[gnu::returns_nonnull]] [[gnu::returns_nonnull]]
struct AST_Node_t *AST_new_node(TokenLocation location, enum AST_SyntaxElement_t kind, const char* value); AST_NODE_PTR AST_new_node(TokenLocation location, enum AST_SyntaxElement_t kind, const char* value);
/** /**
* @brief Deallocate this node and all of its children. * @brief Deallocate this node and all of its children.
@ -149,7 +133,7 @@ struct AST_Node_t *AST_new_node(TokenLocation location, enum AST_SyntaxElement_t
*/ */
[[maybe_unused]] [[maybe_unused]]
[[gnu::nonnull(1)]] [[gnu::nonnull(1)]]
void AST_delete_node(struct AST_Node_t * node); void AST_delete_node(AST_NODE_PTR node);
/** /**
* @brief Add a new child node to a parent node * @brief Add a new child node to a parent node
@ -159,7 +143,7 @@ void AST_delete_node(struct AST_Node_t * node);
*/ */
[[maybe_unused]] [[maybe_unused]]
[[gnu::nonnull(1), gnu::nonnull(2)]] [[gnu::nonnull(1), gnu::nonnull(2)]]
void AST_push_node(struct AST_Node_t *owner, struct AST_Node_t *child); void AST_push_node(AST_NODE_PTR owner, AST_NODE_PTR child);
/** /**
* @brief Remove the specified child from the owner. * @brief Remove the specified child from the owner.
@ -172,7 +156,7 @@ void AST_push_node(struct AST_Node_t *owner, struct AST_Node_t *child);
[[maybe_unused]] [[maybe_unused]]
[[nodiscard("pointer must be freed")]] [[nodiscard("pointer must be freed")]]
[[gnu::nonnull(1)]] [[gnu::nonnull(1)]]
struct AST_Node_t* AST_remove_child(struct AST_Node_t* owner, size_t idx); AST_NODE_PTR AST_remove_child(AST_NODE_PTR owner, size_t idx);
/** /**
* @brief Detach a child from its parent. This involves removing the child from its parent * @brief Detach a child from its parent. This involves removing the child from its parent
@ -184,7 +168,7 @@ struct AST_Node_t* AST_remove_child(struct AST_Node_t* owner, size_t idx);
*/ */
[[nodiscard("pointer must be freed")]] [[nodiscard("pointer must be freed")]]
[[gnu::nonnull(1), gnu::nonnull(1)]] [[gnu::nonnull(1), gnu::nonnull(1)]]
struct AST_Node_t* AST_detach_child(struct AST_Node_t* owner, const struct AST_Node_t* child); AST_NODE_PTR AST_detach_child(AST_NODE_PTR owner, AST_NODE_PTR child);
/** /**
* @brief Return a pointer to the n-th child of a node * @brief Return a pointer to the n-th child of a node
@ -197,7 +181,7 @@ struct AST_Node_t* AST_detach_child(struct AST_Node_t* owner, const struct AST_N
*/ */
[[maybe_unused]] [[maybe_unused]]
[[gnu::nonnull(1)]] [[gnu::nonnull(1)]]
struct AST_Node_t *AST_get_node(struct AST_Node_t *owner, size_t idx); AST_NODE_PTR AST_get_node(AST_NODE_PTR owner, size_t idx);
/** /**
* @brief Execute a function for every child, grandchild, ... and the supplied node as topmost ancestor * @brief Execute a function for every child, grandchild, ... and the supplied node as topmost ancestor
@ -206,8 +190,8 @@ struct AST_Node_t *AST_get_node(struct AST_Node_t *owner, size_t idx);
*/ */
[[maybe_unused]] [[maybe_unused]]
[[gnu::nonnull(1), gnu::nonnull(2)]] [[gnu::nonnull(1), gnu::nonnull(2)]]
void AST_visit_nodes_recurse(struct AST_Node_t *root, void AST_visit_nodes_recurse(AST_NODE_PTR root,
void (*for_each)(struct AST_Node_t *node, void (*for_each)(AST_NODE_PTR node,
size_t depth)); size_t depth));
/** /**
@ -217,6 +201,6 @@ void AST_visit_nodes_recurse(struct AST_Node_t *root,
*/ */
[[maybe_unused]] [[maybe_unused]]
[[gnu::nonnull(1), gnu::nonnull(2)]] [[gnu::nonnull(1), gnu::nonnull(2)]]
void AST_fprint_graphviz(FILE* stream, const struct AST_Node_t* node); void AST_fprint_graphviz(FILE* stream, AST_NODE_PTR node);
#endif #endif // AST_H_