Add basic AST functionality
This commit is contained in:
		
							
								
								
									
										84
									
								
								src/ast.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										84
									
								
								src/ast.c
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,84 @@ | ||||
| #include "ast.h" | ||||
| #include "error.h" | ||||
| #include <string.h> | ||||
|  | ||||
| error_t *err_node_children_cap = &(error_t){ | ||||
|     .message = "Failed to increase ast node children, max capacity reached"}; | ||||
|  | ||||
| error_t *ast_node_alloc(ast_node_t **output) { | ||||
|     *output = nullptr; | ||||
|  | ||||
|     ast_node_t *node = calloc(1, sizeof(ast_node_t)); | ||||
|     if (node == nullptr) | ||||
|         return err_allocation_failed; | ||||
|  | ||||
|     *output = node; | ||||
|     return nullptr; | ||||
| } | ||||
|  | ||||
| void ast_node_free_value(ast_node_t *node) { | ||||
|     // TODO: decide how value ownership will work and clean it up here | ||||
| } | ||||
|  | ||||
| void ast_node_free(ast_node_t *node) { | ||||
|     if (node == nullptr) | ||||
|         return; | ||||
|     if (node->children) { | ||||
|         for (size_t i = 0; i < node->len; ++i) | ||||
|             ast_node_free(node->children[i]); | ||||
|     } | ||||
|  | ||||
|     ast_node_free_value(node); | ||||
|  | ||||
|     memset(node, 0, sizeof(ast_node_t)); | ||||
|     free(node); | ||||
| } | ||||
|  | ||||
| /** | ||||
|  * @pre node->children must be nullptr | ||||
|  */ | ||||
| error_t *ast_node_alloc_children(ast_node_t *node) { | ||||
|     node->children = calloc(node_default_children_cap, sizeof(ast_node_t *)); | ||||
|     if (node->children == nullptr) | ||||
|         return err_allocation_failed; | ||||
|  | ||||
|     node->cap = node_default_children_cap; | ||||
|     return nullptr; | ||||
| } | ||||
|  | ||||
| error_t *ast_node_grow_cap(ast_node_t *node) { | ||||
|     if (node->cap >= node_max_children_cap) { | ||||
|         return err_node_children_cap; | ||||
|     } | ||||
|  | ||||
|     size_t new_cap = node->cap * 2; | ||||
|     if (new_cap > node_max_children_cap) { | ||||
|         new_cap = node_max_children_cap; | ||||
|     } | ||||
|  | ||||
|     ast_node_t **new_children = | ||||
|         realloc(node->children, new_cap * sizeof(ast_node_t *)); | ||||
|     if (new_children == nullptr) { | ||||
|         return err_allocation_failed; | ||||
|     } | ||||
|  | ||||
|     node->children = new_children; | ||||
|     node->cap = new_cap; | ||||
|  | ||||
|     return nullptr; | ||||
| } | ||||
|  | ||||
| error_t *ast_node_add_child(ast_node_t *node, ast_node_t *child) { | ||||
|     error_t *err = nullptr; | ||||
|     if (node->children == nullptr) | ||||
|         err = ast_node_alloc_children(node); | ||||
|     else if (node->len >= node->cap) | ||||
|         err = ast_node_grow_cap(node); | ||||
|     if (err) | ||||
|         return err; | ||||
|  | ||||
|     node->children[node->len] = child; | ||||
|     node->len += 1; | ||||
|  | ||||
|     return nullptr; | ||||
| } | ||||
							
								
								
									
										72
									
								
								src/ast.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										72
									
								
								src/ast.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,72 @@ | ||||
| #ifndef INCLUDE_SRC_AST_H_ | ||||
| #define INCLUDE_SRC_AST_H_ | ||||
|  | ||||
| #include "error.h" | ||||
| #include "lexer.h" | ||||
| #include <stddef.h> | ||||
| #include <stdint.h> | ||||
|  | ||||
| typedef enum node_id { | ||||
|     NODE_PROGRAM, | ||||
|     NODE_DIRECTIVE, | ||||
|     NODE_LABEL, | ||||
|     NODE_INSTRUCTION | ||||
| } node_id_t; | ||||
|  | ||||
| typedef struct ast_node ast_node_t; | ||||
|  | ||||
| constexpr size_t node_default_children_cap = 8; | ||||
| /* 65K ought to be enough for anybody */ | ||||
| constexpr size_t node_max_children_cap = 1 << 16; | ||||
|  | ||||
| struct ast_node { | ||||
|     node_id_t id; | ||||
|     lexer_token_t *token; | ||||
|     size_t len; | ||||
|     size_t cap; | ||||
|     ast_node_t **children; | ||||
|  | ||||
|     union { | ||||
|         struct { | ||||
|             uint64_t value; | ||||
|             int size; | ||||
|         } integer; | ||||
|         char *name; | ||||
|     } value; | ||||
| }; | ||||
|  | ||||
| /** | ||||
|  * @brief Allocates a new AST node | ||||
|  * | ||||
|  * Creates and initializes a new AST node with default (zero) values. | ||||
|  * | ||||
|  * @param[out] output Pointer to store the allocated node | ||||
|  * @return error_t* nullptr on success, allocation error on failure | ||||
|  */ | ||||
| error_t *ast_node_alloc(ast_node_t **node); | ||||
|  | ||||
| /** | ||||
|  * @brief Frees an AST node and all its children recursively | ||||
|  * | ||||
|  * Recursively frees all children of the node, then frees the node itself. | ||||
|  * If node is nullptr, the function returns without doing anything. | ||||
|  * | ||||
|  * @param node The node to free | ||||
|  */ | ||||
| void ast_node_free(ast_node_t *node); | ||||
|  | ||||
| /** | ||||
|  * @brief Adds a child node to a parent node | ||||
|  * | ||||
|  * Adds the specified child node to the parent's children array. | ||||
|  * If this is the first child, the function allocates the children array. | ||||
|  * If the children array is full, the function increases its capacity. | ||||
|  * | ||||
|  * @param node The parent node to add the child to | ||||
|  * @param child The child node to add | ||||
|  * @return error_t* nullptr on success, allocation error on failure, | ||||
|  *                  or err_node_children_cap if maximum capacity is reached | ||||
|  */ | ||||
| error_t *ast_node_add_child(ast_node_t *node, ast_node_t *child); | ||||
|  | ||||
| #endif // INCLUDE_SRC_AST_H_ | ||||
		Reference in New Issue
	
	Block a user