From bed8e60da8d8ebc3d367872bacd64137414e7ae9 Mon Sep 17 00:00:00 2001 From: Mel Date: Tue, 11 Mar 2025 22:34:40 +0100 Subject: Add common library for basic types, functions and macros Signed-off-by: Mel --- boot/common.c | 146 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 146 insertions(+) create mode 100644 boot/common.c (limited to 'boot/common.c') diff --git a/boot/common.c b/boot/common.c new file mode 100644 index 0000000..67e13eb --- /dev/null +++ b/boot/common.c @@ -0,0 +1,146 @@ +/* + * a small library of types, functions and macros that + * are used throughout the bootstrap compiler. + * allocation done purely statically. + */ + +#include +#include +#include +#include +#include + +#define uint8 uint8_t +#define uint16 uint16_t +#define uint32 uint32_t +#define uint64 uint64_t + +#define int8 int8_t +#define int16 int16_t +#define int32 int32_t +#define int64 int64_t + +#define float32 float +#define float64 double +#define real float64 + +#define uint uint64 +#define integer int64 +#define flags int32 + +#define ascii char +#define byte char + +#define bool _Bool +#define true 1 +#define false 0 +#define nil NULL +#define unknown void + +// call on irrecoverable failure. +// prints a very sad, apologetic message for +// the user and aborts program with failure status. +void +failure(const ascii* message) +{ + const ascii* format = + "\\e[0;31m" + ";( sorry, a failure has occurred...\n" + "-> %s!\n" + "\\e[0m"; + fprintf(stderr, format, message); + + exit(EXIT_FAILURE); +} + +// check a condition, triggering a failure if it's false. +void +check(bool condition, const ascii* message) +{ + if (!condition) failure(message); +} + +// the common size of region memory blocks. +#define REGION_SIZE 65536 + +// statically allocates a region of memory of a given size +// for a single type. +#define REGION_OF_SIZE(type, of, size) \ + type region_##of[size]; \ + uint region_##of##_cursor = 0; + +// statically allocates a region of memory for a type. +#define REGION(type, of) REGION_OF_SIZE(type, of, REGION_SIZE) + +// the global string region. +REGION(ascii, string) + +// a string. +struct String +{ + ascii* data; + uint length; +}; + +#define STRING_ITERATE(index, c, str) \ + ascii c = string_at(str, 0); \ + for (uint index = 0; index < str.length; c = string_at(str, ++index)) + +// allocates a new string in the global string region. +struct String +string_new(const ascii* data, uint length) +{ + // for compatibility, we include an additional null byte at the end. + uint allocation_length = length + 1; + check(region_string_cursor + allocation_length < REGION_SIZE, "out of string memory"); + + ascii* at = region_string + region_string_cursor; + region_string_cursor += allocation_length; + + for (uint i = 0; i < length; ++i) at[i] = data[i]; + at[length] = '\0'; + + return { + .data = at, + .length = length, + }; +} + +// allocates a new string in the global string region, +// taking the data from a null-terminated C string. +struct String +string_from_c_string(const char* c_string) +{ + uint length = strlen(c_string); + return string_new(c_string, length); +} + +// allocates a new string in the global string region, +// taking the data from a static null-terminated C string. +// +// NOTE: The string is not copied, so it MUST have a lifetime +// spanning the entire program. +struct String +string_from_static_c_string(const char* c_string) +{ + uint length = strlen(c_string); + return { + .data = (ascii*)c_string, + .length = length, + }; +} + +// returns the character at a given index. +// does bounds-checking. +ascii +string_at(struct String s, uint index) +{ + check(index < s.length, "index out of bounds"); + return s.data[index]; +} + +uint +string_length(struct String s) +{ + return s.length; +} -- cgit 1.4.1