Compare commits
	
		
			2 Commits
		
	
	
		
			object_for
			...
			0f6efa8050
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
| 0f6efa8050 | |||
| 36af377ba0 | 
							
								
								
									
										36
									
								
								doc/parser_grammar.txt
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										36
									
								
								doc/parser_grammar.txt
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,36 @@ | |||||||
|  | /* string literals are lexer identifier tokens with that particular value */ | ||||||
|  | <program>   ::= <statement>* | ||||||
|  | <statement> ::= ( <label> | <directive> | <instruction> ) <newline> | ||||||
|  |  | ||||||
|  | <label> ::= <identifier> <colon> | ||||||
|  |  | ||||||
|  | <directive> ::= <dot> <section> | ||||||
|  |  | ||||||
|  | <section>   ::= "section" <identifier> | ||||||
|  |  | ||||||
|  | <instruction> ::= <identifier> <operands> | ||||||
|  |  | ||||||
|  | <operands> ::= <operand> ( <comma> <operands> )* | ||||||
|  |  | ||||||
|  | <operand>  ::= <register> | <immediate> | <memory> | ||||||
|  |  | ||||||
|  | <register> ::= <register_base> | <register_extra> | ||||||
|  | <register_base> ::= "rax" | "rbx" | "rcx" | "rdx" | "rsi" | "rdi" | "rbp" | "rsp" | ||||||
|  | <register_extra> ::= "r8" | "r9" | "r10" | "r11" | "r12" | "r13" | "r14" | "r15"  | ||||||
|  |  | ||||||
|  | <immediate> ::= <number> | <label_reference> | ||||||
|  | <number> ::= <octal> | <binary> | <decimal> | <hexadecimal> | ||||||
|  |  | ||||||
|  | <label_reference> ::= <identifier> | ||||||
|  |  | ||||||
|  | <memory> ::= <lbracket> <memory_expression> <rbracket> | ||||||
|  |  | ||||||
|  | <memory_expression> ::= <label_reference> | <register_expression> | ||||||
|  |  | ||||||
|  | <register_expression> ::= <register> <register_index>? <register_offset>? | ||||||
|  |  | ||||||
|  | <register_index> ::= <plus> <register> <asterisk> <number> | ||||||
|  |  | ||||||
|  | <register_offset> ::= <plus_or_minus> <number> | ||||||
|  |  | ||||||
|  | <plus_or_minus> ::= <plus> | <minus> | ||||||
							
								
								
									
										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