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"
LANGUAGES C)
set(CMAKE_C_STANDARD 23)
set(CMAKE_C_STANDARD_REQUIRED TRUE)
set(GEMSTONE_TEST_DIR ${PROJECT_SOURCE_DIR}/tests)
set(GEMSTONE_BINARY_DIR ${PROJECT_SOURCE_DIR}/bin)

View File

@ -1,12 +1,13 @@
#include <ast/ast.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <sys/log.h>
#include <assert.h>
struct AST_Node_t *AST_new_node(enum AST_SyntaxElement_t kind, const char* 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));
@ -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");
}
assert(node != NULL);
// init to discrete state
node->parent = NULL;
node->children = NULL;
@ -71,10 +74,11 @@ void AST_init() {
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);
assert(node != NULL);
const char* string = "unknown";
const char* string;
switch(node->kind) {
case AST_Int:
@ -90,11 +94,15 @@ const char* AST_node_to_string(struct AST_Node_t* node) {
string = lookup_table[node->kind];
}
assert(string != NULL);
return string;
}
void AST_push_node(struct AST_Node_t *owner, struct AST_Node_t *child) {
DEBUG("Adding new node %p to %p", child, owner);
assert(owner != NULL);
assert(child != NULL);
// if there are no children for now
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");
}
assert(owner->children != NULL);
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);
if (owner == NULL) {
PANIC("AST owner node is NULL");
}
assert(owner != NULL);
assert(owner->children != NULL);
assert(idx < owner->child_count);
if (owner->children == NULL) {
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) {
assert(owner != NULL);
assert(owner->children != NULL);
assert(idx < owner->child_count);
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) {
assert(owner != NULL);
assert(child != NULL);
assert(owner->children != NULL);
for (size_t i = 0; i < owner->child_count; i++) {
if (owner->children[i] == child) {
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");
return NULL;
}
void AST_delete_node(struct AST_Node_t *node) {
DEBUG("Deleting AST node: %p", node);
assert(node != NULL);
if (node == NULL) {
PANIC("Node to free is NULL");
}
DEBUG("Deleting AST node: %p", node);
if (node->children == NULL) {
return;
}
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++) {
@ -186,16 +200,18 @@ void AST_delete_node(struct AST_Node_t *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,
size_t depth),
size_t depth) {
const size_t depth) {
DEBUG("Recursive visit of %p at %d with %p", root, depth, for_each);
assert(root != NULL);
(for_each)(root, depth);
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,
size_t depth)) {
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);
assert(stream != NULL);
assert(node != NULL);
fprintf(stream, "\tnode%p [label=\"%s\"]\n", (void*) node, AST_node_to_string(node));
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++) {
__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);
assert(stream != NULL);
assert(node != NULL);
if (node->children == NULL) {
return;
}
for (size_t i = 0; i < node->child_count; 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);
assert(stream != NULL);
assert(root != NULL);
fprintf(stream, "graph {\n");
__AST_fprint_graphviz_node_definition(stream, root);
__AST_fprint_graphviz_node_connection(stream, root);
AST_fprint_graphviz_node_definition(stream, root);
AST_fprint_graphviz_node_connection(stream, root);
fprintf(stream, "}\n");
}

View File

@ -102,7 +102,9 @@ void AST_init(void);
* @param node to return string representation of
* @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.
@ -112,6 +114,9 @@ const char* AST_node_to_string(struct AST_Node_t* node);
* @param value an optional value for this node
* @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);
/**
@ -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
* @param node The node to deallocate
*/
[[maybe_unused]]
[[gnu::nonnull(1)]]
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 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);
/**
@ -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
* @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);
/**
@ -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
* @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);
/**
@ -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
* @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);
/**
@ -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 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 (*for_each)(struct AST_Node_t *node,
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 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

View File

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

View File

@ -34,14 +34,14 @@
* This macro will print debug information to stderr and call abort() to
* 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.
* This macro will print debug information to stderr and call exit() to
* 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.
@ -56,7 +56,7 @@ will not print.
#define __LOG(level, priority, format, ...) \
do { \
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)
/**
@ -69,10 +69,11 @@ will not print.
* @param format the format to print following args in
* @param ...
*/
void __logf(
[[gnu::nonnull(1), gnu::nonnull(2), gnu::nonnull(4)]]
void syslog_logf(
const char* restrict level,
const char* restrict file,
const unsigned long line,
unsigned long line,
const char* restrict func,
const char* restrict format,
...);
@ -86,9 +87,11 @@ void __logf(
* @param format the format to print following args in
* @param ...
*/
void __panicf(
[[noreturn]]
[[gnu::nonnull(1), gnu::nonnull(3), gnu::nonnull(4)]]
void syslog_panicf(
const char* restrict file,
const unsigned long line,
unsigned long line,
const char* restrict func,
const char* restrict format,
...);
@ -102,9 +105,11 @@ void __panicf(
* @param format the format to print following args in
* @param ...
*/
void __fatalf(
[[noreturn]]
[[gnu::nonnull(1), gnu::nonnull(3), gnu::nonnull(4)]]
void syslog_fatalf(
const char* restrict file,
const unsigned long line,
unsigned long line,
const char* restrict func,
const char* restrict format,
...);
@ -120,6 +125,7 @@ void log_init(void);
*
* @param stream
*/
[[gnu::nonnull(1)]]
void log_register_stream(FILE* restrict stream);
#endif /* _SYS_ERR_H_ */