Compare commits

..

1 Commits

Author SHA1 Message Date
b4301ed650 Add a parser grammar
All checks were successful
Validate the build / validate-build (push) Successful in 24s
Currently this is a subset of the grammar, enough to get reasonable work
going.
2025-03-31 14:47:58 +02:00
9 changed files with 22 additions and 304 deletions

View File

@ -27,9 +27,9 @@
<memory_expression> ::= <label_reference> | <register_expression>
<register_expression> ::= <register> <register_index>? <register_offset>?
<register_expression> ::= <register> ( <plus> <register> <asterisk> <number> )? ( <plus_or_minus> <number> )?
<register_index> ::= <plus> <register> <asterisk> <number>
<register_displacement> ::= <plus> <register> <asterisk> <number>
<register_offset> ::= <plus_or_minus> <number>

View File

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

View File

@ -1,72 +0,0 @@
#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_

View File

@ -10,9 +10,6 @@ error_t *const err_errorf_length = &(error_t){
.message =
"Formatting of another error failed to determine the error length"};
error_t *err_allocation_failed =
&(error_t){.message = "Memory allocation failed"};
error_t *errorf(const char *fmt, ...) {
error_t *err = calloc(1, sizeof(error_t));
if (err == nullptr)

View File

@ -18,7 +18,4 @@ static inline void error_free(error_t *err) {
free(err);
}
/* Some global errors */
extern error_t *err_allocation_failed;
#endif // INCLUDE_SRC_ERROR_H_

View File

@ -20,6 +20,9 @@ error_t *err_eof =
error_t *err_unknown_read = &(error_t){.message = "Unknown read error"};
error_t *err_allocation_failed =
&(error_t){.message = "Memory allocation failed"};
typedef bool (*char_predicate_t)(char);
const char *lexer_token_id_to_cstr(lexer_token_id_t id) {

View File

@ -1,6 +1,5 @@
#include "error.h"
#include "lexer.h"
#include "tokenlist.h"
#include <limits.h>
#include <stdio.h>
@ -40,33 +39,24 @@ int main(int argc, char *argv[]) {
print_fn = print_value;
}
lexer_t *lex = &(lexer_t){};
error_t *err = lexer_open(lex, filename);
if (err)
goto cleanup_error;
tokenlist_t *list;
err = tokenlist_alloc(&list);
if (err)
goto cleanup_lexer;
err = tokenlist_fill(list, lex);
if (err)
goto cleanup_tokens;
for (auto entry = list->head; entry; entry = entry->next) {
print_fn(&entry->token);
lexer_t lex = {0};
lexer_token_t token;
error_t *err = lexer_open(&lex, filename);
if (err) {
puts(err->message);
error_free(err);
return 1;
}
bool keep_going = true;
while (keep_going && (err = lexer_next(&lex, &token)) == nullptr) {
keep_going = print_fn(&token);
free(token.value);
}
if (err && err != err_eof) {
puts(err->message);
}
tokenlist_free(list);
error_free(err);
return 0;
cleanup_tokens:
tokenlist_free(list);
cleanup_lexer:
lexer_close(lex);
cleanup_error:
puts(err->message);
error_free(err);
return 1;
}

View File

@ -1,83 +0,0 @@
#include "tokenlist.h"
#include "error.h"
#include "lexer.h"
#include <stdlib.h>
error_t *tokenlist_alloc(tokenlist_t **output) {
*output = nullptr;
tokenlist_t *list = calloc(1, sizeof(tokenlist_t));
if (list == nullptr)
return err_allocation_failed;
list->head = nullptr;
list->tail = nullptr;
*output = list;
return nullptr;
}
error_t *tokenlist_entry_alloc(tokenlist_entry_t **output) {
*output = nullptr;
tokenlist_entry_t *entry = calloc(1, sizeof(tokenlist_entry_t));
if (entry == nullptr)
return err_allocation_failed;
entry->next = nullptr;
entry->prev = nullptr;
*output = entry;
return nullptr;
}
void tokenlist_append(tokenlist_t *list, tokenlist_entry_t *entry) {
if (list->head == nullptr) {
list->head = entry;
list->tail = entry;
entry->next = nullptr;
entry->prev = nullptr;
} else {
entry->prev = list->tail;
entry->next = nullptr;
list->tail->next = entry;
list->tail = entry;
}
}
void tokenlist_entry_free(tokenlist_entry_t *entry) {
lexer_token_cleanup(&entry->token);
free(entry);
}
void tokenlist_free(tokenlist_t *list) {
if (list == nullptr)
return;
tokenlist_entry_t *current = list->head;
while (current) {
tokenlist_entry_t *next = current->next;
tokenlist_entry_free(current);
current = next;
}
free(list);
}
error_t *tokenlist_fill(tokenlist_t *list, lexer_t *lex) {
error_t *err = nullptr;
lexer_token_t token = {};
while ((err = lexer_next(lex, &token)) == nullptr) {
tokenlist_entry_t *entry;
err = tokenlist_entry_alloc(&entry);
if (err) {
lexer_token_cleanup(&token);
return err;
}
entry->token = token;
tokenlist_append(list, entry);
}
if (err != err_eof)
return err;
return nullptr;
}

View File

@ -1,30 +0,0 @@
#ifndef INCLUDE_SRC_TOKENLIST_H_
#define INCLUDE_SRC_TOKENLIST_H_
#include "lexer.h"
typedef struct tokenlist_entry tokenlist_entry_t;
struct tokenlist_entry {
lexer_token_t token;
tokenlist_entry_t *next;
tokenlist_entry_t *prev;
};
typedef struct tokenlist {
tokenlist_entry_t *head;
tokenlist_entry_t *tail;
} tokenlist_t;
/**
* @brief Allocate a new doubly linked list of lexer tokens
*/
error_t *tokenlist_alloc(tokenlist_t **list);
/**
* Consume all tokens from the lexer and add them to the list
*/
error_t *tokenlist_fill(tokenlist_t *list, lexer_t *lex);
void tokenlist_free(tokenlist_t *list);
#endif // INCLUDE_SRC_TOKENLIST_H_