- Add a instruction value that contains the encoding, the address and a flag to indicate if this instruction contains label references - Add label value that contains an address - Add reference value that contains offset, an absolute address and an operand size - define types for all value options in the union - define accessor functions for all the values in the union
199 lines
4.8 KiB
C++
199 lines
4.8 KiB
C++
#ifndef INCLUDE_SRC_AST_H_
|
|
#define INCLUDE_SRC_AST_H_
|
|
|
|
#include "data/registers.h"
|
|
#include "error.h"
|
|
#include "lexer.h"
|
|
#include "tokenlist.h"
|
|
#include <assert.h>
|
|
#include <stddef.h>
|
|
#include <stdint.h>
|
|
|
|
extern error_t *const err_ast_children_cap;
|
|
|
|
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,
|
|
NODE_IMPORT_DIRECTIVE,
|
|
NODE_EXPORT_DIRECTIVE,
|
|
|
|
// Validated primitives
|
|
NODE_REGISTER,
|
|
NODE_SECTION,
|
|
NODE_IMPORT,
|
|
NODE_EXPORT,
|
|
|
|
// 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_NEWLINE,
|
|
} 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;
|
|
|
|
typedef struct number {
|
|
uint64_t value;
|
|
operand_size_t size;
|
|
} number_t;
|
|
|
|
typedef struct register_ {
|
|
register_id_t id;
|
|
operand_size_t size;
|
|
} register_t;
|
|
|
|
typedef struct opcode_encoding {
|
|
uint8_t buffer[32];
|
|
size_t len;
|
|
} opcode_encoding_t;
|
|
|
|
typedef struct instruction {
|
|
bool has_reference;
|
|
opcode_encoding_t encoding;
|
|
int64_t address;
|
|
} instruction_t;
|
|
|
|
typedef struct reference {
|
|
int64_t offset;
|
|
int64_t address;
|
|
operand_size_t size;
|
|
} reference_t;
|
|
|
|
typedef struct {
|
|
int64_t address;
|
|
} label_t;
|
|
|
|
struct ast_node {
|
|
node_id_t id;
|
|
tokenlist_entry_t *token_entry;
|
|
size_t len;
|
|
size_t cap;
|
|
ast_node_t **children;
|
|
|
|
union {
|
|
register_t reg;
|
|
number_t number;
|
|
instruction_t instruction;
|
|
reference_t reference;
|
|
label_t label;
|
|
} value;
|
|
};
|
|
|
|
static inline register_t *ast_node_register_value(ast_node_t *node) {
|
|
assert(node->id == NODE_REGISTER);
|
|
return &node->value.reg;
|
|
}
|
|
|
|
static inline number_t *ast_node_number_value(ast_node_t *node) {
|
|
assert(node->id == NODE_NUMBER);
|
|
return &node->value.number;
|
|
}
|
|
|
|
static inline instruction_t *ast_node_instruction_value(ast_node_t *node) {
|
|
assert(node->id == NODE_INSTRUCTION);
|
|
return &node->value.instruction;
|
|
}
|
|
|
|
static inline reference_t *ast_node_reference_value(ast_node_t *node) {
|
|
assert(node->id == NODE_LABEL_REFERENCE);
|
|
return &node->value.reference;
|
|
}
|
|
|
|
static inline label_t *ast_node_label_value(ast_node_t *node) {
|
|
assert(node->id == NODE_LABEL);
|
|
return &node->value.label;
|
|
}
|
|
|
|
/**
|
|
* @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);
|
|
|
|
/**
|
|
* @brief Prints an AST starting from the given node
|
|
*
|
|
* Prints a representation of the AST with indentation to show structure.
|
|
* Each node's type is shown, and if a node has an associated token value,
|
|
* that value is printed in quotes.
|
|
*
|
|
* @param node The root node of the AST to print
|
|
*/
|
|
void ast_node_print(ast_node_t *node);
|
|
|
|
/**
|
|
* Prune the children with a given id
|
|
*
|
|
* The tree is recursively visited and all child nodes of a given ID are pruned
|
|
* completely. If a node has the giver id, it will get removed along wih all its
|
|
* children, even if some of those children have different ids. The root node id
|
|
* is never checked so the tree is guaranteed to remain and allocated valid.
|
|
*
|
|
* @param node The root of the tree you want to prune
|
|
* @param id The id of the nodes you want to prune
|
|
*/
|
|
void ast_node_prune(ast_node_t *node, node_id_t id);
|
|
|
|
#endif // INCLUDE_SRC_AST_H_
|