required C standard is C23

refactored logger function names to remove underscores
added function attributes
This commit is contained in:
Sven Vogel 2024-05-10 15:09:52 +02:00
parent 12a522b0e6
commit 23968f7acc
5 changed files with 102 additions and 41 deletions

View File

@ -21,6 +21,9 @@ project(gemstone
DESCRIPTION "programming language compiler" DESCRIPTION "programming language compiler"
LANGUAGES C) LANGUAGES C)
set(CMAKE_C_STANDARD 23)
set(CMAKE_C_STANDARD_REQUIRED TRUE)
set(GEMSTONE_TEST_DIR ${PROJECT_SOURCE_DIR}/tests) set(GEMSTONE_TEST_DIR ${PROJECT_SOURCE_DIR}/tests)
set(GEMSTONE_BINARY_DIR ${PROJECT_SOURCE_DIR}/bin) set(GEMSTONE_BINARY_DIR ${PROJECT_SOURCE_DIR}/bin)

View File

@ -1,12 +1,13 @@
#include <ast/ast.h> #include <ast/ast.h>
#include <stdio.h> #include <stdio.h>
#include <string.h>
#include <stdlib.h> #include <stdlib.h>
#include <sys/log.h> #include <sys/log.h>
#include <assert.h>
struct AST_Node_t *AST_new_node(enum AST_SyntaxElement_t kind, const char* value) { struct AST_Node_t *AST_new_node(enum AST_SyntaxElement_t kind, const char* value) {
DEBUG("creating new AST node: %d \"%s\"", kind, value); DEBUG("creating new AST node: %d \"%s\"", kind, value);
assert(kind < AST_ELEMENT_COUNT);
struct AST_Node_t *node = malloc(sizeof(struct AST_Node_t)); struct AST_Node_t *node = malloc(sizeof(struct AST_Node_t));
@ -14,6 +15,8 @@ struct AST_Node_t *AST_new_node(enum AST_SyntaxElement_t kind, const char* value
PANIC("failed to allocate AST node"); PANIC("failed to allocate AST node");
} }
assert(node != NULL);
// init to discrete state // init to discrete state
node->parent = NULL; node->parent = NULL;
node->children = NULL; node->children = NULL;
@ -71,10 +74,11 @@ void AST_init() {
lookup_table[AST_Condition] = "condition"; lookup_table[AST_Condition] = "condition";
} }
const char* AST_node_to_string(struct AST_Node_t* node) { const char* AST_node_to_string(const struct AST_Node_t* node) {
DEBUG("converting AST node to string: %p", node); DEBUG("converting AST node to string: %p", node);
assert(node != NULL);
const char* string = "unknown"; const char* string;
switch(node->kind) { switch(node->kind) {
case AST_Int: case AST_Int:
@ -90,11 +94,15 @@ const char* AST_node_to_string(struct AST_Node_t* node) {
string = lookup_table[node->kind]; string = lookup_table[node->kind];
} }
assert(string != NULL);
return string; return string;
} }
void AST_push_node(struct AST_Node_t *owner, struct AST_Node_t *child) { void AST_push_node(struct AST_Node_t *owner, struct AST_Node_t *child) {
DEBUG("Adding new node %p to %p", child, owner); DEBUG("Adding new node %p to %p", child, owner);
assert(owner != NULL);
assert(child != NULL);
// if there are no children for now // if there are no children for now
if (owner->child_count == 0) { if (owner->child_count == 0) {
@ -111,15 +119,16 @@ void AST_push_node(struct AST_Node_t *owner, struct AST_Node_t *child) {
PANIC("failed to allocate children array of AST node"); PANIC("failed to allocate children array of AST node");
} }
assert(owner->children != NULL);
owner->children[owner->child_count++] = child; owner->children[owner->child_count++] = child;
} }
struct AST_Node_t *AST_get_node(struct AST_Node_t *owner, size_t idx) { struct AST_Node_t *AST_get_node(struct AST_Node_t *owner, const size_t idx) {
DEBUG("retrvieng node %d from %p", idx, owner); DEBUG("retrvieng node %d from %p", idx, owner);
assert(owner != NULL);
if (owner == NULL) { assert(owner->children != NULL);
PANIC("AST owner node is NULL"); assert(idx < owner->child_count);
}
if (owner->children == NULL) { if (owner->children == NULL) {
PANIC("AST owner node has no children"); PANIC("AST owner node has no children");
@ -135,6 +144,9 @@ struct AST_Node_t *AST_get_node(struct AST_Node_t *owner, size_t idx) {
} }
struct AST_Node_t* AST_remove_child(struct AST_Node_t* owner, const size_t idx) { struct AST_Node_t* AST_remove_child(struct AST_Node_t* owner, const size_t idx) {
assert(owner != NULL);
assert(owner->children != NULL);
assert(idx < owner->child_count);
struct AST_Node_t* child = owner->children[idx]; struct AST_Node_t* child = owner->children[idx];
@ -151,6 +163,10 @@ struct AST_Node_t* AST_remove_child(struct AST_Node_t* owner, const size_t idx)
} }
struct AST_Node_t* AST_detach_child(struct AST_Node_t* owner, const struct AST_Node_t* child) { struct AST_Node_t* AST_detach_child(struct AST_Node_t* owner, const struct AST_Node_t* child) {
assert(owner != NULL);
assert(child != NULL);
assert(owner->children != NULL);
for (size_t i = 0; i < owner->child_count; i++) { for (size_t i = 0; i < owner->child_count; i++) {
if (owner->children[i] == child) { if (owner->children[i] == child) {
return AST_remove_child(owner, i); return AST_remove_child(owner, i);
@ -158,22 +174,20 @@ struct AST_Node_t* AST_detach_child(struct AST_Node_t* owner, const struct AST_N
} }
PANIC("Child to detach not a child of parent"); PANIC("Child to detach not a child of parent");
return NULL;
} }
void AST_delete_node(struct AST_Node_t *node) { void AST_delete_node(struct AST_Node_t *node) {
DEBUG("Deleting AST node: %p", node); assert(node != NULL);
if (node == NULL) { DEBUG("Deleting AST node: %p", node);
PANIC("Node to free is NULL");
}
if (node->children == NULL) { if (node->children == NULL) {
return; return;
} }
if (node->parent != NULL) { if (node->parent != NULL) {
AST_detach_child(node->parent, node); const struct AST_Node_t* child = AST_detach_child(node->parent, node);
assert(child == node);
} }
for (size_t i = 0; i < node->child_count; i++) { for (size_t i = 0; i < node->child_count; i++) {
@ -186,16 +200,18 @@ void AST_delete_node(struct AST_Node_t *node) {
free(node); free(node);
} }
static void __AST_visit_nodes_recurse2(struct AST_Node_t *root, static void AST_visit_nodes_recurse2(struct AST_Node_t *root,
void (*for_each)(struct AST_Node_t *node, void (*for_each)(struct AST_Node_t *node,
size_t depth), size_t depth),
size_t depth) { const size_t depth) {
DEBUG("Recursive visit of %p at %d with %p", root, depth, for_each); DEBUG("Recursive visit of %p at %d with %p", root, depth, for_each);
assert(root != NULL);
(for_each)(root, depth); (for_each)(root, depth);
for (size_t i = 0; i < root->child_count; i++) { for (size_t i = 0; i < root->child_count; i++) {
__AST_visit_nodes_recurse2(root->children[i], for_each, depth + 1); AST_visit_nodes_recurse2(root->children[i], for_each, depth + 1);
} }
} }
@ -203,12 +219,19 @@ void AST_visit_nodes_recurse(struct AST_Node_t *root,
void (*for_each)(struct AST_Node_t *node, void (*for_each)(struct AST_Node_t *node,
size_t depth)) { size_t depth)) {
DEBUG("Starting recursive visit of %p with %p", root, for_each); DEBUG("Starting recursive visit of %p with %p", root, for_each);
__AST_visit_nodes_recurse2(root, for_each, 0);
assert(root != NULL);
assert(for_each != NULL);
AST_visit_nodes_recurse2(root, for_each, 0);
} }
static void __AST_fprint_graphviz_node_definition(FILE* stream, struct AST_Node_t* node) { static void AST_fprint_graphviz_node_definition(FILE* stream, const struct AST_Node_t* node) {
DEBUG("Printing graphviz definition of %p", node); DEBUG("Printing graphviz definition of %p", node);
assert(stream != NULL);
assert(node != NULL);
fprintf(stream, "\tnode%p [label=\"%s\"]\n", (void*) node, AST_node_to_string(node)); fprintf(stream, "\tnode%p [label=\"%s\"]\n", (void*) node, AST_node_to_string(node));
if (node->children == NULL) { if (node->children == NULL) {
@ -216,30 +239,36 @@ static void __AST_fprint_graphviz_node_definition(FILE* stream, struct AST_Node_
} }
for (size_t i = 0; i < node->child_count; i++) { for (size_t i = 0; i < node->child_count; i++) {
__AST_fprint_graphviz_node_definition(stream, node->children[i]); AST_fprint_graphviz_node_definition(stream, node->children[i]);
} }
} }
static void __AST_fprint_graphviz_node_connection(FILE* stream, struct AST_Node_t* node) { static void AST_fprint_graphviz_node_connection(FILE* stream, const struct AST_Node_t* node) {
DEBUG("Printing graphviz connection of %p", node); DEBUG("Printing graphviz connection of %p", node);
assert(stream != NULL);
assert(node != NULL);
if (node->children == NULL) { if (node->children == NULL) {
return; return;
} }
for (size_t i = 0; i < node->child_count; i++) { for (size_t i = 0; i < node->child_count; i++) {
fprintf(stream, "\tnode%p -- node%p\n", (void*) node, (void*) node->children[i]); fprintf(stream, "\tnode%p -- node%p\n", (void*) node, (void*) node->children[i]);
__AST_fprint_graphviz_node_connection(stream, node->children[i]); AST_fprint_graphviz_node_connection(stream, node->children[i]);
} }
} }
void AST_fprint_graphviz(FILE* stream, struct AST_Node_t* root) { void AST_fprint_graphviz(FILE* stream, const struct AST_Node_t* root) {
DEBUG("Starting print of graphviz graph of %p", root); DEBUG("Starting print of graphviz graph of %p", root);
assert(stream != NULL);
assert(root != NULL);
fprintf(stream, "graph {\n"); fprintf(stream, "graph {\n");
__AST_fprint_graphviz_node_definition(stream, root); AST_fprint_graphviz_node_definition(stream, root);
__AST_fprint_graphviz_node_connection(stream, root); AST_fprint_graphviz_node_connection(stream, root);
fprintf(stream, "}\n"); fprintf(stream, "}\n");
} }

View File

@ -102,7 +102,9 @@ void AST_init(void);
* @param node to return string representation of * @param node to return string representation of
* @return string represenation of the node * @return string represenation of the node
*/ */
const char* AST_node_to_string(struct AST_Node_t* node); [[maybe_unused]]
[[gnu::nonnull(1)]]
const char* AST_node_to_string(const struct AST_Node_t* node);
/** /**
* @brief Create a new node struct on the system heap. Initializes the struct with the given values. * @brief Create a new node struct on the system heap. Initializes the struct with the given values.
@ -112,6 +114,9 @@ const char* AST_node_to_string(struct AST_Node_t* node);
* @param value an optional value for this node * @param value an optional value for this node
* @return * @return
*/ */
[[maybe_unused]]
[[nodiscard("pointer must be freed")]]
[[gnu::returns_nonnull]]
struct AST_Node_t *AST_new_node(enum AST_SyntaxElement_t kind, const char* value); struct AST_Node_t *AST_new_node(enum AST_SyntaxElement_t kind, const char* value);
/** /**
@ -120,6 +125,8 @@ struct AST_Node_t *AST_new_node(enum AST_SyntaxElement_t kind, const char* value
* Use of the supplied node after this call is undefined behavior * Use of the supplied node after this call is undefined behavior
* @param node The node to deallocate * @param node The node to deallocate
*/ */
[[maybe_unused]]
[[gnu::nonnull(1)]]
void AST_delete_node(struct AST_Node_t * node); void AST_delete_node(struct AST_Node_t * node);
/** /**
@ -128,6 +135,8 @@ void AST_delete_node(struct AST_Node_t * node);
* @param owner node to add a child to * @param owner node to add a child to
* @param child node to be added as a child * @param child node to be added as a child
*/ */
[[maybe_unused]]
[[gnu::nonnull(1), gnu::nonnull(2)]]
void AST_push_node(struct AST_Node_t *owner, struct AST_Node_t *child); void AST_push_node(struct AST_Node_t *owner, struct AST_Node_t *child);
/** /**
@ -138,6 +147,9 @@ void AST_push_node(struct AST_Node_t *owner, struct AST_Node_t *child);
* @param idx the index of the child to remove * @param idx the index of the child to remove
* @return a pointer to the child which was removed * @return a pointer to the child which was removed
*/ */
[[maybe_unused]]
[[nodiscard("pointer must be freed")]]
[[gnu::nonnull(1)]]
struct AST_Node_t* AST_remove_child(struct AST_Node_t* owner, size_t idx); struct AST_Node_t* AST_remove_child(struct AST_Node_t* owner, size_t idx);
/** /**
@ -148,6 +160,8 @@ struct AST_Node_t* AST_remove_child(struct AST_Node_t* owner, size_t idx);
* @param child the child to detach * @param child the child to detach
* @return a pointer to child detached * @return a pointer to child detached
*/ */
[[nodiscard("pointer must be freed")]]
[[gnu::nonnull(1), gnu::nonnull(1)]]
struct AST_Node_t* AST_detach_child(struct AST_Node_t* owner, const struct AST_Node_t* child); struct AST_Node_t* AST_detach_child(struct AST_Node_t* owner, const struct AST_Node_t* child);
/** /**
@ -159,6 +173,8 @@ struct AST_Node_t* AST_detach_child(struct AST_Node_t* owner, const struct AST_N
* @param idx the index of the child to get a pointer to * @param idx the index of the child to get a pointer to
* @return a pointer to the n-th child of the owner node * @return a pointer to the n-th child of the owner node
*/ */
[[maybe_unused]]
[[gnu::nonnull(1)]]
struct AST_Node_t *AST_get_node(struct AST_Node_t *owner, size_t idx); struct AST_Node_t *AST_get_node(struct AST_Node_t *owner, size_t idx);
/** /**
@ -166,6 +182,8 @@ struct AST_Node_t *AST_get_node(struct AST_Node_t *owner, size_t idx);
* @param root the root to recursively execute a function for * @param root the root to recursively execute a function for
* @param for_each the function to execute * @param for_each the function to execute
*/ */
[[maybe_unused]]
[[gnu::nonnull(1), gnu::nonnull(2)]]
void AST_visit_nodes_recurse(struct AST_Node_t *root, void AST_visit_nodes_recurse(struct AST_Node_t *root,
void (*for_each)(struct AST_Node_t *node, void (*for_each)(struct AST_Node_t *node,
size_t depth)); size_t depth));
@ -175,6 +193,8 @@ void AST_visit_nodes_recurse(struct AST_Node_t *root,
* @param stream The stream to print to. Can be a file, stdout, ... * @param stream The stream to print to. Can be a file, stdout, ...
* @param node the topmost ancestor * @param node the topmost ancestor
*/ */
void AST_fprint_graphviz(FILE* stream, struct AST_Node_t* node); [[maybe_unused]]
[[gnu::nonnull(1), gnu::nonnull(2)]]
void AST_fprint_graphviz(FILE* stream, const struct AST_Node_t* node);
#endif #endif

View File

@ -3,6 +3,7 @@
#include <stdio.h> #include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
#include <sys/log.h> #include <sys/log.h>
#include <assert.h>
static struct Logger_t { static struct Logger_t {
FILE** streams; FILE** streams;
@ -11,13 +12,15 @@ static struct Logger_t {
void log_init(void) void log_init(void)
{ {
assert(LOG_DEFAULT_STREAM != NULL);
log_register_stream(LOG_DEFAULT_STREAM); log_register_stream(LOG_DEFAULT_STREAM);
} }
void log_register_stream(FILE* restrict stream) void log_register_stream(FILE* restrict stream)
{ {
if (stream == NULL) // replace runtime check with assertion
PANIC("stream to register is NULL"); // only to be used in debug target
assert(stream != NULL);
if (GlobalLogger.stream_count == 0) if (GlobalLogger.stream_count == 0)
{ {
@ -57,7 +60,7 @@ static void vflogf(
vfprintf(stream, format, args); vfprintf(stream, format, args);
} }
void __logf( void syslog_logf(
const char* restrict level, const char* restrict level,
const char* restrict file, const char* restrict file,
const unsigned long line, const unsigned long line,
@ -78,7 +81,7 @@ void __logf(
va_end(args); va_end(args);
} }
void __panicf( void syslog_panicf(
const char* restrict file, const char* restrict file,
const unsigned long line, const unsigned long line,
const char* restrict func, const char* restrict func,
@ -95,7 +98,7 @@ void __panicf(
exit(EXIT_FAILURE); exit(EXIT_FAILURE);
} }
void __fatalf( void syslog_fatalf(
const char* restrict file, const char* restrict file,
const unsigned long line, const unsigned long line,
const char* restrict func, const char* restrict func,

View File

@ -34,14 +34,14 @@
* This macro will print debug information to stderr and call abort() to * This macro will print debug information to stderr and call abort() to
* performa a ungracefull exit. No clean up possible. * performa a ungracefull exit. No clean up possible.
*/ */
#define PANIC(format, ...) __panicf(__FILE_NAME__, __LINE__, __func__, format"\n", ##__VA_ARGS__) #define PANIC(format, ...) syslog_panicf(__FILE_NAME__, __LINE__, __func__, format"\n", ##__VA_ARGS__)
/** /**
* @brief Panic is used in cases where the process is in an invalid or undefined state. * @brief Panic is used in cases where the process is in an invalid or undefined state.
* This macro will print debug information to stderr and call exit() to * This macro will print debug information to stderr and call exit() to
* initiate a gracefull exit, giving the process the opportunity to clean up. * initiate a gracefull exit, giving the process the opportunity to clean up.
*/ */
#define FATAL(format, ...) __fatalf(__FILE_NAME__, __LINE__, __func__, format"\n", ##__VA_ARGS__) #define FATAL(format, ...) syslog_fatalf(__FILE_NAME__, __LINE__, __func__, format"\n", ##__VA_ARGS__)
/* /*
Standard log macros. These will not terminate the application. Standard log macros. These will not terminate the application.
@ -56,7 +56,7 @@ will not print.
#define __LOG(level, priority, format, ...) \ #define __LOG(level, priority, format, ...) \
do { \ do { \
if (LOG_LEVEL <= priority) \ if (LOG_LEVEL <= priority) \
__logf(level, __FILE_NAME__, __LINE__, __func__, format, ##__VA_ARGS__); \ syslog_logf(level, __FILE_NAME__, __LINE__, __func__, format, ##__VA_ARGS__); \
} while(0) } while(0)
/** /**
@ -69,10 +69,11 @@ will not print.
* @param format the format to print following args in * @param format the format to print following args in
* @param ... * @param ...
*/ */
void __logf( [[gnu::nonnull(1), gnu::nonnull(2), gnu::nonnull(4)]]
void syslog_logf(
const char* restrict level, const char* restrict level,
const char* restrict file, const char* restrict file,
const unsigned long line, unsigned long line,
const char* restrict func, const char* restrict func,
const char* restrict format, const char* restrict format,
...); ...);
@ -86,9 +87,11 @@ void __logf(
* @param format the format to print following args in * @param format the format to print following args in
* @param ... * @param ...
*/ */
void __panicf( [[noreturn]]
[[gnu::nonnull(1), gnu::nonnull(3), gnu::nonnull(4)]]
void syslog_panicf(
const char* restrict file, const char* restrict file,
const unsigned long line, unsigned long line,
const char* restrict func, const char* restrict func,
const char* restrict format, const char* restrict format,
...); ...);
@ -102,9 +105,11 @@ void __panicf(
* @param format the format to print following args in * @param format the format to print following args in
* @param ... * @param ...
*/ */
void __fatalf( [[noreturn]]
[[gnu::nonnull(1), gnu::nonnull(3), gnu::nonnull(4)]]
void syslog_fatalf(
const char* restrict file, const char* restrict file,
const unsigned long line, unsigned long line,
const char* restrict func, const char* restrict func,
const char* restrict format, const char* restrict format,
...); ...);
@ -120,6 +125,7 @@ void log_init(void);
* *
* @param stream * @param stream
*/ */
[[gnu::nonnull(1)]]
void log_register_stream(FILE* restrict stream); void log_register_stream(FILE* restrict stream);
#endif /* _SYS_ERR_H_ */ #endif /* _SYS_ERR_H_ */