implement parsing #3

Merged
omicron merged 15 commits from parser_start into main 2025-04-02 19:53:48 +00:00
2 changed files with 194 additions and 0 deletions
Showing only changes of commit 935da30257 - Show all commits

85
src/ast.c Normal file
View File

@ -0,0 +1,85 @@
#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]);
free(node->children);
}
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;
}

109
src/ast.h Normal file
View File

@ -0,0 +1,109 @@
#ifndef INCLUDE_SRC_AST_H_
#define INCLUDE_SRC_AST_H_
#include "error.h"
#include "lexer.h"
#include "tokenlist.h"
#include <stddef.h>
#include <stdint.h>
typedef enum node_id {
NODE_INVALID,
NODE_PROGRAM,
NODE_STATEMENT,
NODE_LABEL,
NODE_DIRECTIVE,
NODE_INSTRUCTION,
NODE_OPERANDS,
NODE_OPERAND,
NODE_IMMEDIATE,
NODE_MEMORY,
NODE_NUMBER,
NODE_LABEL_REFERENCE,
NODE_MEMORY_EXPRESSION,
NODE_REGISTER_EXPRESSION,
NODE_REGISTER_INDEX,
NODE_REGISTER_OFFSET,
NODE_PLUS_OR_MINUS,
NODE_SECTION_DIRECTIVE,
// Validated primitives
NODE_REGISTER,
NODE_SECTION,
// Primitive nodes
NODE_IDENTIFIER,
NODE_DECIMAL,
NODE_HEXADECIMAL,
NODE_OCTAL,
NODE_BINARY,
NODE_CHAR,
NODE_STRING,
NODE_COLON,
NODE_COMMA,
NODE_LBRACKET,
NODE_RBRACKET,
NODE_PLUS,
NODE_MINUS,
NODE_ASTERISK,
NODE_DOT,
} 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;
tokenlist_entry_t *token_entry;
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_