heh, oops:
- SHA
f31e787c6e0d4d672298fb87b6e88e1ef26be75f- Parents
-
9d83da1 - Tree
c92440b
f31e787
f31e787c6e0d4d672298fb87b6e88e1ef26be75f9d83da1
c92440bsrc/cli/completion.cdeleted@@ -1,1 +0,0 @@ | ||
| 1 | -#include "fortbite.h" | |
src/cli/display.cdeleted@@ -1,1 +0,0 @@ | ||
| 1 | -#include "fortbite.h" | |
src/cli/history.cdeleted@@ -1,1 +0,0 @@ | ||
| 1 | -#include "fortbite.h" | |
src/cli/interface.cdeleted@@ -1,1 +0,0 @@ | ||
| 1 | -#include "fortbite.h" | |
src/config/config.cdeleted@@ -1,1 +0,0 @@ | ||
| 1 | -#include "fortbite.h" | |
src/config/defaults.cdeleted@@ -1,1 +0,0 @@ | ||
| 1 | -#include "fortbite.h" | |
src/config/validation.cdeleted@@ -1,1 +0,0 @@ | ||
| 1 | -#include "fortbite.h" | |
src/core/engine.cdeleted@@ -1,1 +0,0 @@ | ||
| 1 | -#include "fortbite.h" | |
src/core/main.cdeleted@@ -1,176 +0,0 @@ | ||
| 1 | -#include "fortbite.h" | |
| 2 | -#include <stdio.h> | |
| 3 | -#include <stdlib.h> | |
| 4 | -#include <readline/readline.h> | |
| 5 | -#include <readline/history.h> | |
| 6 | - | |
| 7 | -struct fortbite_context { | |
| 8 | - fortbite_variable_t* variables; | |
| 9 | - int default_precision; | |
| 10 | - bool verbose; | |
| 11 | -}; | |
| 12 | - | |
| 13 | -fortbite_context_t* fortbite_context_new(void) { | |
| 14 | - fortbite_context_t* ctx = fortbite_malloc(sizeof(fortbite_context_t)); | |
| 15 | - ctx->variables = NULL; | |
| 16 | - ctx->default_precision = DEFAULT_PRECISION; | |
| 17 | - ctx->verbose = false; | |
| 18 | - return ctx; | |
| 19 | -} | |
| 20 | - | |
| 21 | -void fortbite_context_free(fortbite_context_t* ctx) { | |
| 22 | - if (!ctx) return; | |
| 23 | - | |
| 24 | - fortbite_variable_t* var = ctx->variables; | |
| 25 | - while (var) { | |
| 26 | - fortbite_variable_t* next = var->next; | |
| 27 | - fortbite_variable_free(var); | |
| 28 | - var = next; | |
| 29 | - } | |
| 30 | - | |
| 31 | - fortbite_free(ctx); | |
| 32 | -} | |
| 33 | - | |
| 34 | -static void print_banner(void) { | |
| 35 | - printf("FORTBITE v%s - High Precision Calculator\n", FORTBITE_VERSION); | |
| 36 | - printf("Type 'help' for commands or 'exit' to quit.\n"); | |
| 37 | - printf("Use :: for precision specification (e.g., 3.14159::100)\n"); | |
| 38 | - printf("Use := for variable assignment (e.g., x := 42)\n\n"); | |
| 39 | -} | |
| 40 | - | |
| 41 | -static void print_help(void) { | |
| 42 | - printf("FORTBITE Commands:\n"); | |
| 43 | - printf(" Basic arithmetic: +, -, *, /, ^ (power), %% (modulo)\n"); | |
| 44 | - printf(" Variables: x := value\n"); | |
| 45 | - printf(" Precision: value::digits\n"); | |
| 46 | - printf(" Complex: 3+4i, cis(angle)\n"); | |
| 47 | - printf(" Functions: sin, cos, tan, log, exp, sqrt, abs\n"); | |
| 48 | - printf(" Constants: pi, e, i\n"); | |
| 49 | - printf(" Commands: help, exit, clear\n"); | |
| 50 | - printf(" Arrow keys: command history\n\n"); | |
| 51 | -} | |
| 52 | - | |
| 53 | -static bool process_command(fortbite_context_t* ctx, const char* input) { | |
| 54 | - if (!input || strlen(input) == 0) { | |
| 55 | - return true; | |
| 56 | - } | |
| 57 | - | |
| 58 | - char* line = fortbite_strdup(input); | |
| 59 | - char* trimmed = line; | |
| 60 | - | |
| 61 | - while (*trimmed && isspace(*trimmed)) trimmed++; | |
| 62 | - | |
| 63 | - if (strcmp(trimmed, "exit") == 0 || strcmp(trimmed, "quit") == 0) { | |
| 64 | - fortbite_free(line); | |
| 65 | - return false; | |
| 66 | - } | |
| 67 | - | |
| 68 | - if (strcmp(trimmed, "help") == 0) { | |
| 69 | - print_help(); | |
| 70 | - fortbite_free(line); | |
| 71 | - return true; | |
| 72 | - } | |
| 73 | - | |
| 74 | - if (strcmp(trimmed, "clear") == 0) { | |
| 75 | - system("clear"); | |
| 76 | - fortbite_free(line); | |
| 77 | - return true; | |
| 78 | - } | |
| 79 | - | |
| 80 | - if (strncmp(trimmed, "precision", 9) == 0) { | |
| 81 | - char* precision_str = trimmed + 9; | |
| 82 | - while (*precision_str && isspace(*precision_str)) precision_str++; | |
| 83 | - if (*precision_str) { | |
| 84 | - int precision = atoi(precision_str); | |
| 85 | - if (precision > 0 && precision <= 10000) { | |
| 86 | - ctx->default_precision = precision; | |
| 87 | - printf("Default precision set to %d bits\n", precision); | |
| 88 | - } else { | |
| 89 | - printf("Invalid precision. Use 1-10000.\n"); | |
| 90 | - } | |
| 91 | - } else { | |
| 92 | - printf("Current default precision: %d bits\n", ctx->default_precision); | |
| 93 | - } | |
| 94 | - fortbite_free(line); | |
| 95 | - return true; | |
| 96 | - } | |
| 97 | - | |
| 98 | - fortbite_token_t* tokens = fortbite_tokenize(trimmed); | |
| 99 | - if (!tokens) { | |
| 100 | - printf("Error: Failed to tokenize input\n"); | |
| 101 | - fortbite_free(line); | |
| 102 | - return true; | |
| 103 | - } | |
| 104 | - | |
| 105 | - if (tokens[0].type == TOKEN_ERROR) { | |
| 106 | - printf("Error: Invalid token '%s' at position %zu\n", | |
| 107 | - tokens[0].value ? tokens[0].value : "unknown", tokens[0].position); | |
| 108 | - } else { | |
| 109 | - printf("Parsed tokens: "); | |
| 110 | - for (size_t i = 0; tokens[i].type != TOKEN_EOF; i++) { | |
| 111 | - printf("[%s:%s] ", | |
| 112 | - tokens[i].type == TOKEN_NUMBER ? "NUM" : | |
| 113 | - tokens[i].type == TOKEN_IDENTIFIER ? "ID" : | |
| 114 | - tokens[i].type == TOKEN_OPERATOR ? "OP" : | |
| 115 | - tokens[i].type == TOKEN_ASSIGN ? "ASSIGN" : | |
| 116 | - tokens[i].type == TOKEN_PRECISION ? "PREC" : "OTHER", | |
| 117 | - tokens[i].value ? tokens[i].value : ""); | |
| 118 | - } | |
| 119 | - printf("\n"); | |
| 120 | - } | |
| 121 | - | |
| 122 | - fortbite_tokens_free(tokens); | |
| 123 | - fortbite_free(line); | |
| 124 | - return true; | |
| 125 | -} | |
| 126 | - | |
| 127 | -int fortbite_init(void) { | |
| 128 | - mpfr_set_default_prec(DEFAULT_PRECISION); | |
| 129 | - return 0; | |
| 130 | -} | |
| 131 | - | |
| 132 | -void fortbite_cleanup(void) { | |
| 133 | - mpfr_free_cache(); | |
| 134 | -} | |
| 135 | - | |
| 136 | -static void setup_readline(void) { | |
| 137 | - rl_bind_key('\t', rl_complete); | |
| 138 | -} | |
| 139 | - | |
| 140 | -int main(void) { | |
| 141 | - if (fortbite_init() != 0) { | |
| 142 | - fprintf(stderr, "Failed to initialize FORTBITE\n"); | |
| 143 | - return EXIT_FAILURE; | |
| 144 | - } | |
| 145 | - | |
| 146 | - fortbite_context_t* ctx = fortbite_context_new(); | |
| 147 | - setup_readline(); | |
| 148 | - print_banner(); | |
| 149 | - | |
| 150 | - char* input; | |
| 151 | - bool running = true; | |
| 152 | - | |
| 153 | - while (running && (input = readline("fortbite> ")) != NULL) { | |
| 154 | - if (strlen(input) > 0) { | |
| 155 | - add_history(input); | |
| 156 | - } | |
| 157 | - | |
| 158 | - running = process_command(ctx, input); | |
| 159 | - free(input); | |
| 160 | - } | |
| 161 | - | |
| 162 | - if (!input) { | |
| 163 | - printf("\n"); | |
| 164 | - } | |
| 165 | - | |
| 166 | - printf("Goodbye!\n"); | |
| 167 | - | |
| 168 | - fortbite_context_free(ctx); | |
| 169 | - fortbite_cleanup(); | |
| 170 | - | |
| 171 | -#ifdef DEBUG | |
| 172 | - fortbite_memory_stats(); | |
| 173 | -#endif | |
| 174 | - | |
| 175 | - return EXIT_SUCCESS; | |
| 176 | -} | |
src/core/memory.cdeleted@@ -1,72 +0,0 @@ | ||
| 1 | -#include "fortbite.h" | |
| 2 | -#include <stdlib.h> | |
| 3 | -#include <string.h> | |
| 4 | -#include <stdio.h> | |
| 5 | - | |
| 6 | -#ifdef DEBUG | |
| 7 | -static size_t memory_allocated = 0; | |
| 8 | -static size_t memory_freed = 0; | |
| 9 | -#endif | |
| 10 | - | |
| 11 | -void* fortbite_malloc(size_t size) { | |
| 12 | - void* ptr = malloc(size); | |
| 13 | - if (!ptr) { | |
| 14 | - fprintf(stderr, "FORTBITE: Memory allocation failed for %zu bytes\n", size); | |
| 15 | - exit(EXIT_FAILURE); | |
| 16 | - } | |
| 17 | - | |
| 18 | -#ifdef DEBUG | |
| 19 | - memory_allocated += size; | |
| 20 | -#endif | |
| 21 | - | |
| 22 | - return ptr; | |
| 23 | -} | |
| 24 | - | |
| 25 | -void* fortbite_calloc(size_t count, size_t size) { | |
| 26 | - void* ptr = calloc(count, size); | |
| 27 | - if (!ptr) { | |
| 28 | - fprintf(stderr, "FORTBITE: Memory allocation failed for %zu * %zu bytes\n", count, size); | |
| 29 | - exit(EXIT_FAILURE); | |
| 30 | - } | |
| 31 | - | |
| 32 | -#ifdef DEBUG | |
| 33 | - memory_allocated += count * size; | |
| 34 | -#endif | |
| 35 | - | |
| 36 | - return ptr; | |
| 37 | -} | |
| 38 | - | |
| 39 | -void* fortbite_realloc(void* ptr, size_t size) { | |
| 40 | - void* new_ptr = realloc(ptr, size); | |
| 41 | - if (!new_ptr && size > 0) { | |
| 42 | - fprintf(stderr, "FORTBITE: Memory reallocation failed for %zu bytes\n", size); | |
| 43 | - exit(EXIT_FAILURE); | |
| 44 | - } | |
| 45 | - | |
| 46 | - return new_ptr; | |
| 47 | -} | |
| 48 | - | |
| 49 | -void fortbite_free(void* ptr) { | |
| 50 | - if (ptr) { | |
| 51 | - free(ptr); | |
| 52 | -#ifdef DEBUG | |
| 53 | - memory_freed++; | |
| 54 | -#endif | |
| 55 | - } | |
| 56 | -} | |
| 57 | - | |
| 58 | -char* fortbite_strdup(const char* str) { | |
| 59 | - if (!str) return NULL; | |
| 60 | - | |
| 61 | - size_t len = strlen(str) + 1; | |
| 62 | - char* copy = fortbite_malloc(len); | |
| 63 | - memcpy(copy, str, len); | |
| 64 | - return copy; | |
| 65 | -} | |
| 66 | - | |
| 67 | -#ifdef DEBUG | |
| 68 | -void fortbite_memory_stats(void) { | |
| 69 | - printf("Memory allocated: %zu bytes\n", memory_allocated); | |
| 70 | - printf("Memory freed: %zu objects\n", memory_freed); | |
| 71 | -} | |
| 72 | -#endif | |
src/core/types.cdeleted@@ -1,202 +0,0 @@ | ||
| 1 | -#include "fortbite.h" | |
| 2 | - | |
| 3 | -fortbite_value_t* fortbite_value_new(fortbite_type_t type) { | |
| 4 | - fortbite_value_t* value = fortbite_malloc(sizeof(fortbite_value_t)); | |
| 5 | - value->type = type; | |
| 6 | - | |
| 7 | - switch (type) { | |
| 8 | - case FORTBITE_TYPE_SCALAR: | |
| 9 | - fortbite_scalar_new_init(&value->data.scalar, DEFAULT_PRECISION); | |
| 10 | - break; | |
| 11 | - case FORTBITE_TYPE_COMPLEX: | |
| 12 | - fortbite_complex_new_init(&value->data.complex, DEFAULT_PRECISION); | |
| 13 | - break; | |
| 14 | - case FORTBITE_TYPE_MATRIX: | |
| 15 | - value->data.matrix.rows = 0; | |
| 16 | - value->data.matrix.cols = 0; | |
| 17 | - value->data.matrix.data = NULL; | |
| 18 | - value->data.matrix.is_sparse = false; | |
| 19 | - break; | |
| 20 | - case FORTBITE_TYPE_UNIT: | |
| 21 | - value->data.quantity.unit = NULL; | |
| 22 | - fortbite_complex_new_init(&value->data.quantity.value, DEFAULT_PRECISION); | |
| 23 | - break; | |
| 24 | - default: | |
| 25 | - break; | |
| 26 | - } | |
| 27 | - | |
| 28 | - return value; | |
| 29 | -} | |
| 30 | - | |
| 31 | -void fortbite_value_free(fortbite_value_t* value) { | |
| 32 | - if (!value) return; | |
| 33 | - | |
| 34 | - switch (value->type) { | |
| 35 | - case FORTBITE_TYPE_SCALAR: | |
| 36 | - fortbite_scalar_clear(&value->data.scalar); | |
| 37 | - break; | |
| 38 | - case FORTBITE_TYPE_COMPLEX: | |
| 39 | - fortbite_complex_clear(&value->data.complex); | |
| 40 | - break; | |
| 41 | - case FORTBITE_TYPE_MATRIX: | |
| 42 | - fortbite_matrix_clear(&value->data.matrix); | |
| 43 | - break; | |
| 44 | - case FORTBITE_TYPE_UNIT: | |
| 45 | - fortbite_complex_clear(&value->data.quantity.value); | |
| 46 | - break; | |
| 47 | - default: | |
| 48 | - break; | |
| 49 | - } | |
| 50 | - | |
| 51 | - fortbite_free(value); | |
| 52 | -} | |
| 53 | - | |
| 54 | -fortbite_value_t* fortbite_value_copy(const fortbite_value_t* value) { | |
| 55 | - if (!value) return NULL; | |
| 56 | - | |
| 57 | - fortbite_value_t* copy = fortbite_value_new(value->type); | |
| 58 | - | |
| 59 | - switch (value->type) { | |
| 60 | - case FORTBITE_TYPE_SCALAR: | |
| 61 | - fortbite_scalar_set(©->data.scalar, &value->data.scalar); | |
| 62 | - break; | |
| 63 | - case FORTBITE_TYPE_COMPLEX: | |
| 64 | - fortbite_complex_set(©->data.complex, &value->data.complex); | |
| 65 | - break; | |
| 66 | - case FORTBITE_TYPE_MATRIX: | |
| 67 | - if (value->data.matrix.data) { | |
| 68 | - copy->data.matrix = fortbite_matrix_copy(&value->data.matrix); | |
| 69 | - } | |
| 70 | - break; | |
| 71 | - case FORTBITE_TYPE_UNIT: | |
| 72 | - fortbite_complex_set(©->data.quantity.value, &value->data.quantity.value); | |
| 73 | - copy->data.quantity.unit = value->data.quantity.unit; | |
| 74 | - break; | |
| 75 | - default: | |
| 76 | - break; | |
| 77 | - } | |
| 78 | - | |
| 79 | - return copy; | |
| 80 | -} | |
| 81 | - | |
| 82 | -void fortbite_scalar_new_init(fortbite_scalar_t* scalar, int precision) { | |
| 83 | - mpfr_init2(scalar->value, precision); | |
| 84 | - scalar->precision = precision; | |
| 85 | -} | |
| 86 | - | |
| 87 | -void fortbite_scalar_clear(fortbite_scalar_t* scalar) { | |
| 88 | - mpfr_clear(scalar->value); | |
| 89 | -} | |
| 90 | - | |
| 91 | -void fortbite_scalar_set_d(fortbite_scalar_t* scalar, double value) { | |
| 92 | - mpfr_set_d(scalar->value, value, MPFR_RNDN); | |
| 93 | -} | |
| 94 | - | |
| 95 | -void fortbite_scalar_set_str(fortbite_scalar_t* scalar, const char* str, int base) { | |
| 96 | - mpfr_set_str(scalar->value, str, base, MPFR_RNDN); | |
| 97 | -} | |
| 98 | - | |
| 99 | -void fortbite_scalar_set(fortbite_scalar_t* dest, const fortbite_scalar_t* src) { | |
| 100 | - mpfr_set(dest->value, src->value, MPFR_RNDN); | |
| 101 | - dest->precision = src->precision; | |
| 102 | -} | |
| 103 | - | |
| 104 | -void fortbite_complex_new_init(fortbite_complex_t* complex, int precision) { | |
| 105 | - fortbite_scalar_new_init(&complex->real, precision); | |
| 106 | - fortbite_scalar_new_init(&complex->imag, precision); | |
| 107 | -} | |
| 108 | - | |
| 109 | -void fortbite_complex_clear(fortbite_complex_t* complex) { | |
| 110 | - fortbite_scalar_clear(&complex->real); | |
| 111 | - fortbite_scalar_clear(&complex->imag); | |
| 112 | -} | |
| 113 | - | |
| 114 | -void fortbite_complex_set(fortbite_complex_t* dest, const fortbite_complex_t* src) { | |
| 115 | - fortbite_scalar_set(&dest->real, &src->real); | |
| 116 | - fortbite_scalar_set(&dest->imag, &src->imag); | |
| 117 | -} | |
| 118 | - | |
| 119 | -fortbite_matrix_t fortbite_matrix_new(size_t rows, size_t cols, int precision) { | |
| 120 | - fortbite_matrix_t matrix; | |
| 121 | - matrix.rows = rows; | |
| 122 | - matrix.cols = cols; | |
| 123 | - matrix.is_sparse = false; | |
| 124 | - | |
| 125 | - if (rows > 0 && cols > 0) { | |
| 126 | - matrix.data = fortbite_malloc(rows * sizeof(fortbite_complex_t*)); | |
| 127 | - for (size_t i = 0; i < rows; i++) { | |
| 128 | - matrix.data[i] = fortbite_malloc(cols * sizeof(fortbite_complex_t)); | |
| 129 | - for (size_t j = 0; j < cols; j++) { | |
| 130 | - fortbite_complex_new_init(&matrix.data[i][j], precision); | |
| 131 | - } | |
| 132 | - } | |
| 133 | - } else { | |
| 134 | - matrix.data = NULL; | |
| 135 | - } | |
| 136 | - | |
| 137 | - return matrix; | |
| 138 | -} | |
| 139 | - | |
| 140 | -void fortbite_matrix_clear(fortbite_matrix_t* matrix) { | |
| 141 | - if (matrix->data) { | |
| 142 | - for (size_t i = 0; i < matrix->rows; i++) { | |
| 143 | - for (size_t j = 0; j < matrix->cols; j++) { | |
| 144 | - fortbite_complex_clear(&matrix->data[i][j]); | |
| 145 | - } | |
| 146 | - fortbite_free(matrix->data[i]); | |
| 147 | - } | |
| 148 | - fortbite_free(matrix->data); | |
| 149 | - matrix->data = NULL; | |
| 150 | - } | |
| 151 | - matrix->rows = 0; | |
| 152 | - matrix->cols = 0; | |
| 153 | -} | |
| 154 | - | |
| 155 | -fortbite_matrix_t fortbite_matrix_copy(const fortbite_matrix_t* src) { | |
| 156 | - fortbite_matrix_t copy = fortbite_matrix_new(src->rows, src->cols, DEFAULT_PRECISION); | |
| 157 | - copy.is_sparse = src->is_sparse; | |
| 158 | - | |
| 159 | - if (src->data) { | |
| 160 | - for (size_t i = 0; i < src->rows; i++) { | |
| 161 | - for (size_t j = 0; j < src->cols; j++) { | |
| 162 | - fortbite_complex_set(©.data[i][j], &src->data[i][j]); | |
| 163 | - } | |
| 164 | - } | |
| 165 | - } | |
| 166 | - | |
| 167 | - return copy; | |
| 168 | -} | |
| 169 | - | |
| 170 | -fortbite_complex_t* fortbite_matrix_get(const fortbite_matrix_t* matrix, size_t row, size_t col) { | |
| 171 | - if (!matrix->data || row >= matrix->rows || col >= matrix->cols) { | |
| 172 | - return NULL; | |
| 173 | - } | |
| 174 | - return &matrix->data[row][col]; | |
| 175 | -} | |
| 176 | - | |
| 177 | -void fortbite_matrix_set(fortbite_matrix_t* matrix, size_t row, size_t col, const fortbite_complex_t* value) { | |
| 178 | - if (!matrix->data || row >= matrix->rows || col >= matrix->cols) { | |
| 179 | - return; | |
| 180 | - } | |
| 181 | - fortbite_complex_set(&matrix->data[row][col], value); | |
| 182 | -} | |
| 183 | - | |
| 184 | -fortbite_variable_t* fortbite_variable_new(const char* name, const fortbite_value_t* value) { | |
| 185 | - fortbite_variable_t* var = fortbite_malloc(sizeof(fortbite_variable_t)); | |
| 186 | - var->name = fortbite_strdup(name); | |
| 187 | - if (value) { | |
| 188 | - var->value = *fortbite_value_copy(value); | |
| 189 | - } else { | |
| 190 | - var->value.type = FORTBITE_TYPE_UNDEFINED; | |
| 191 | - } | |
| 192 | - var->next = NULL; | |
| 193 | - return var; | |
| 194 | -} | |
| 195 | - | |
| 196 | -void fortbite_variable_free(fortbite_variable_t* var) { | |
| 197 | - if (!var) return; | |
| 198 | - | |
| 199 | - fortbite_free(var->name); | |
| 200 | - fortbite_value_free(&var->value); | |
| 201 | - fortbite_free(var); | |
| 202 | -} | |
src/export/csv.cdeleted@@ -1,1 +0,0 @@ | ||
| 1 | -#include "fortbite.h" | |
src/export/formats.cdeleted@@ -1,1 +0,0 @@ | ||
| 1 | -#include "fortbite.h" | |
src/export/json.cdeleted@@ -1,1 +0,0 @@ | ||
| 1 | -#include "fortbite.h" | |
src/export/latex.cdeleted@@ -1,1 +0,0 @@ | ||
| 1 | -#include "fortbite.h" | |
src/fortbite.f90added@@ -0,0 +1,21 @@ | ||
| 1 | +!> FORTBITE - High-Precision Calculator in Modern Fortran | |
| 2 | +!> | |
| 3 | +!> A powerful mathematical calculator leveraging Fortran's strengths in | |
| 4 | +!> scientific computing, with arbitrary precision arithmetic, complex numbers, | |
| 5 | +!> matrix operations, and extensive mathematical functions. | |
| 6 | +!> | |
| 7 | +!> Author: espadonne (mfw) | |
| 8 | +!> License: MIT | |
| 9 | +program fortbite | |
| 10 | + use fortbite_precision_m, only: set_default_precision | |
| 11 | + use fortbite_types_m, only: value_t | |
| 12 | + use fortbite_io_m, only: repl_loop | |
| 13 | + implicit none | |
| 14 | + | |
| 15 | + ! Initialize default precision | |
| 16 | + call set_default_precision(15) ! Start with ~double precision | |
| 17 | + | |
| 18 | + ! Start the main REPL loop | |
| 19 | + call repl_loop() | |
| 20 | + | |
| 21 | +end program fortbite | |
src/fortbite_arithmetic_m.f90added@@ -0,0 +1,227 @@ | ||
| 1 | +!> Basic arithmetic operations module for FORTBITE | |
| 2 | +!> | |
| 3 | +!> Provides arithmetic operations for scalars, complex numbers, and matrices | |
| 4 | +!> with proper precision handling and type promotion. | |
| 5 | +module fortbite_arithmetic_m | |
| 6 | + use iso_fortran_env, only: real64 | |
| 7 | + use fortbite_types_m, only: value_t, VALUE_SCALAR, VALUE_COMPLEX, VALUE_MATRIX, & | |
| 8 | + create_scalar, create_complex, is_real | |
| 9 | + implicit none | |
| 10 | + private | |
| 11 | + | |
| 12 | + public :: add_values, subtract_values, multiply_values, divide_values, power_values | |
| 13 | + public :: negate_value, abs_value | |
| 14 | + | |
| 15 | +contains | |
| 16 | + | |
| 17 | + !> Add two values | |
| 18 | + function add_values(a, b) result(c) | |
| 19 | + type(value_t), intent(in) :: a, b | |
| 20 | + type(value_t) :: c | |
| 21 | + | |
| 22 | + ! Handle scalar + scalar | |
| 23 | + if (a%value_type == VALUE_SCALAR .and. b%value_type == VALUE_SCALAR) then | |
| 24 | + c = create_scalar(a%scalar_val + b%scalar_val) | |
| 25 | + return | |
| 26 | + end if | |
| 27 | + | |
| 28 | + ! Handle mixed scalar/complex operations | |
| 29 | + if ((a%value_type == VALUE_SCALAR .and. b%value_type == VALUE_COMPLEX) .or. & | |
| 30 | + (a%value_type == VALUE_COMPLEX .and. b%value_type == VALUE_SCALAR)) then | |
| 31 | + | |
| 32 | + if (a%value_type == VALUE_SCALAR) then | |
| 33 | + c = create_complex(a%scalar_val + real(b%complex_val), aimag(b%complex_val)) | |
| 34 | + else | |
| 35 | + c = create_complex(real(a%complex_val) + b%scalar_val, aimag(a%complex_val)) | |
| 36 | + end if | |
| 37 | + return | |
| 38 | + end if | |
| 39 | + | |
| 40 | + ! Handle complex + complex | |
| 41 | + if (a%value_type == VALUE_COMPLEX .and. b%value_type == VALUE_COMPLEX) then | |
| 42 | + c = create_complex(real(a%complex_val) + real(b%complex_val), & | |
| 43 | + aimag(a%complex_val) + aimag(b%complex_val)) | |
| 44 | + return | |
| 45 | + end if | |
| 46 | + | |
| 47 | + ! TODO: Handle matrix operations in Phase 3 | |
| 48 | + ! For now, return undefined for unsupported operations | |
| 49 | + c%value_type = 0 ! VALUE_UNDEFINED | |
| 50 | + end function add_values | |
| 51 | + | |
| 52 | + !> Subtract two values | |
| 53 | + function subtract_values(a, b) result(c) | |
| 54 | + type(value_t), intent(in) :: a, b | |
| 55 | + type(value_t) :: c | |
| 56 | + | |
| 57 | + ! Handle scalar - scalar | |
| 58 | + if (a%value_type == VALUE_SCALAR .and. b%value_type == VALUE_SCALAR) then | |
| 59 | + c = create_scalar(a%scalar_val - b%scalar_val) | |
| 60 | + return | |
| 61 | + end if | |
| 62 | + | |
| 63 | + ! Handle mixed scalar/complex operations | |
| 64 | + if ((a%value_type == VALUE_SCALAR .and. b%value_type == VALUE_COMPLEX) .or. & | |
| 65 | + (a%value_type == VALUE_COMPLEX .and. b%value_type == VALUE_SCALAR)) then | |
| 66 | + | |
| 67 | + if (a%value_type == VALUE_SCALAR) then | |
| 68 | + c = create_complex(a%scalar_val - real(b%complex_val), -aimag(b%complex_val)) | |
| 69 | + else | |
| 70 | + c = create_complex(real(a%complex_val) - b%scalar_val, aimag(a%complex_val)) | |
| 71 | + end if | |
| 72 | + return | |
| 73 | + end if | |
| 74 | + | |
| 75 | + ! Handle complex - complex | |
| 76 | + if (a%value_type == VALUE_COMPLEX .and. b%value_type == VALUE_COMPLEX) then | |
| 77 | + c = create_complex(real(a%complex_val) - real(b%complex_val), & | |
| 78 | + aimag(a%complex_val) - aimag(b%complex_val)) | |
| 79 | + return | |
| 80 | + end if | |
| 81 | + | |
| 82 | + c%value_type = 0 ! VALUE_UNDEFINED | |
| 83 | + end function subtract_values | |
| 84 | + | |
| 85 | + !> Multiply two values | |
| 86 | + function multiply_values(a, b) result(c) | |
| 87 | + type(value_t), intent(in) :: a, b | |
| 88 | + type(value_t) :: c | |
| 89 | + | |
| 90 | + ! Handle scalar * scalar | |
| 91 | + if (a%value_type == VALUE_SCALAR .and. b%value_type == VALUE_SCALAR) then | |
| 92 | + c = create_scalar(a%scalar_val * b%scalar_val) | |
| 93 | + return | |
| 94 | + end if | |
| 95 | + | |
| 96 | + ! Handle mixed scalar/complex operations | |
| 97 | + if ((a%value_type == VALUE_SCALAR .and. b%value_type == VALUE_COMPLEX) .or. & | |
| 98 | + (a%value_type == VALUE_COMPLEX .and. b%value_type == VALUE_SCALAR)) then | |
| 99 | + | |
| 100 | + if (a%value_type == VALUE_SCALAR) then | |
| 101 | + c = create_complex(a%scalar_val * real(b%complex_val), & | |
| 102 | + a%scalar_val * aimag(b%complex_val)) | |
| 103 | + else | |
| 104 | + c = create_complex(real(a%complex_val) * b%scalar_val, & | |
| 105 | + aimag(a%complex_val) * b%scalar_val) | |
| 106 | + end if | |
| 107 | + return | |
| 108 | + end if | |
| 109 | + | |
| 110 | + ! Handle complex * complex | |
| 111 | + if (a%value_type == VALUE_COMPLEX .and. b%value_type == VALUE_COMPLEX) then | |
| 112 | + c%complex_val = a%complex_val * b%complex_val | |
| 113 | + c%value_type = VALUE_COMPLEX | |
| 114 | + return | |
| 115 | + end if | |
| 116 | + | |
| 117 | + c%value_type = 0 ! VALUE_UNDEFINED | |
| 118 | + end function multiply_values | |
| 119 | + | |
| 120 | + !> Divide two values | |
| 121 | + function divide_values(a, b) result(c) | |
| 122 | + type(value_t), intent(in) :: a, b | |
| 123 | + type(value_t) :: c | |
| 124 | + | |
| 125 | + ! Handle scalar / scalar | |
| 126 | + if (a%value_type == VALUE_SCALAR .and. b%value_type == VALUE_SCALAR) then | |
| 127 | + if (abs(b%scalar_val) < epsilon(b%scalar_val)) then | |
| 128 | + write(*, '(A)') 'Error: Division by zero' | |
| 129 | + c%value_type = 0 ! VALUE_UNDEFINED | |
| 130 | + return | |
| 131 | + end if | |
| 132 | + c = create_scalar(a%scalar_val / b%scalar_val) | |
| 133 | + return | |
| 134 | + end if | |
| 135 | + | |
| 136 | + ! Handle mixed scalar/complex operations | |
| 137 | + if ((a%value_type == VALUE_SCALAR .and. b%value_type == VALUE_COMPLEX) .or. & | |
| 138 | + (a%value_type == VALUE_COMPLEX .and. b%value_type == VALUE_SCALAR)) then | |
| 139 | + | |
| 140 | + if (a%value_type == VALUE_SCALAR) then | |
| 141 | + if (abs(b%complex_val) < epsilon(real(b%complex_val))) then | |
| 142 | + write(*, '(A)') 'Error: Division by zero' | |
| 143 | + c%value_type = 0 | |
| 144 | + return | |
| 145 | + end if | |
| 146 | + c%complex_val = a%scalar_val / b%complex_val | |
| 147 | + c%value_type = VALUE_COMPLEX | |
| 148 | + else | |
| 149 | + if (abs(b%scalar_val) < epsilon(b%scalar_val)) then | |
| 150 | + write(*, '(A)') 'Error: Division by zero' | |
| 151 | + c%value_type = 0 | |
| 152 | + return | |
| 153 | + end if | |
| 154 | + c = create_complex(real(a%complex_val) / b%scalar_val, & | |
| 155 | + aimag(a%complex_val) / b%scalar_val) | |
| 156 | + end if | |
| 157 | + return | |
| 158 | + end if | |
| 159 | + | |
| 160 | + ! Handle complex / complex | |
| 161 | + if (a%value_type == VALUE_COMPLEX .and. b%value_type == VALUE_COMPLEX) then | |
| 162 | + if (abs(b%complex_val) < epsilon(real(b%complex_val))) then | |
| 163 | + write(*, '(A)') 'Error: Division by zero' | |
| 164 | + c%value_type = 0 | |
| 165 | + return | |
| 166 | + end if | |
| 167 | + c%complex_val = a%complex_val / b%complex_val | |
| 168 | + c%value_type = VALUE_COMPLEX | |
| 169 | + return | |
| 170 | + end if | |
| 171 | + | |
| 172 | + c%value_type = 0 ! VALUE_UNDEFINED | |
| 173 | + end function divide_values | |
| 174 | + | |
| 175 | + !> Raise a value to a power | |
| 176 | + function power_values(a, b) result(c) | |
| 177 | + type(value_t), intent(in) :: a, b | |
| 178 | + type(value_t) :: c | |
| 179 | + | |
| 180 | + ! Handle scalar ** scalar | |
| 181 | + if (a%value_type == VALUE_SCALAR .and. b%value_type == VALUE_SCALAR) then | |
| 182 | + c = create_scalar(a%scalar_val ** b%scalar_val) | |
| 183 | + return | |
| 184 | + end if | |
| 185 | + | |
| 186 | + ! Handle complex exponentiation (more complex, implement later) | |
| 187 | + ! For now, convert to complex and use Fortran's intrinsic | |
| 188 | + if (a%value_type == VALUE_COMPLEX .or. b%value_type == VALUE_COMPLEX) then | |
| 189 | + write(*, '(A)') 'Complex exponentiation not yet fully implemented' | |
| 190 | + c%value_type = 0 | |
| 191 | + return | |
| 192 | + end if | |
| 193 | + | |
| 194 | + c%value_type = 0 ! VALUE_UNDEFINED | |
| 195 | + end function power_values | |
| 196 | + | |
| 197 | + !> Negate a value | |
| 198 | + function negate_value(a) result(c) | |
| 199 | + type(value_t), intent(in) :: a | |
| 200 | + type(value_t) :: c | |
| 201 | + | |
| 202 | + select case (a%value_type) | |
| 203 | + case (VALUE_SCALAR) | |
| 204 | + c = create_scalar(-a%scalar_val) | |
| 205 | + case (VALUE_COMPLEX) | |
| 206 | + c = create_complex(-real(a%complex_val), -aimag(a%complex_val)) | |
| 207 | + case default | |
| 208 | + c%value_type = 0 ! VALUE_UNDEFINED | |
| 209 | + end select | |
| 210 | + end function negate_value | |
| 211 | + | |
| 212 | + !> Absolute value of a value | |
| 213 | + function abs_value(a) result(c) | |
| 214 | + type(value_t), intent(in) :: a | |
| 215 | + type(value_t) :: c | |
| 216 | + | |
| 217 | + select case (a%value_type) | |
| 218 | + case (VALUE_SCALAR) | |
| 219 | + c = create_scalar(abs(a%scalar_val)) | |
| 220 | + case (VALUE_COMPLEX) | |
| 221 | + c = create_scalar(abs(a%complex_val)) | |
| 222 | + case default | |
| 223 | + c%value_type = 0 ! VALUE_UNDEFINED | |
| 224 | + end select | |
| 225 | + end function abs_value | |
| 226 | + | |
| 227 | +end module fortbite_arithmetic_m | |
src/fortbite_io_m.f90added@@ -0,0 +1,267 @@ | ||
| 1 | +!> I/O and REPL interface module for FORTBITE | |
| 2 | +!> | |
| 3 | +!> Handles user input/output, command processing, and the main REPL loop. | |
| 4 | +module fortbite_io_m | |
| 5 | + use fortbite_precision_m, only: get_precision_info, precision_info_t | |
| 6 | + use iso_fortran_env, only: real32, real64, real128 | |
| 7 | + use fortbite_types_m, only: value_t, variable_t, print_value | |
| 8 | + implicit none | |
| 9 | + private | |
| 10 | + | |
| 11 | + public :: repl_loop, print_banner, print_help | |
| 12 | + public :: parse_command, is_command | |
| 13 | + | |
| 14 | + ! Maximum input line length | |
| 15 | + integer, parameter :: MAX_LINE_LENGTH = 1000 | |
| 16 | + | |
| 17 | +contains | |
| 18 | + | |
| 19 | + !> Print the FORTBITE banner | |
| 20 | + subroutine print_banner() | |
| 21 | + write(*, '(A)') '' | |
| 22 | + write(*, '(A)') '======================================' | |
| 23 | + write(*, '(A)') ' FORTBITE ' | |
| 24 | + write(*, '(A)') ' High-Precision Calculator ' | |
| 25 | + write(*, '(A)') ' Modern Fortran Edition ' | |
| 26 | + write(*, '(A)') '======================================' | |
| 27 | + write(*, '(A)') '' | |
| 28 | + write(*, '(A)') 'Type "help" for commands or "exit" to quit.' | |
| 29 | + write(*, '(A)') 'Use :: for precision (e.g., 3.14159::100)' | |
| 30 | + write(*, '(A)') 'Use := for assignment (e.g., x := 42)' | |
| 31 | + write(*, '(A)') '' | |
| 32 | + end subroutine print_banner | |
| 33 | + | |
| 34 | + !> Print help information | |
| 35 | + subroutine print_help() | |
| 36 | + type(precision_info_t) :: info | |
| 37 | + | |
| 38 | + write(*, '(A)') 'FORTBITE Commands:' | |
| 39 | + write(*, '(A)') ' Basic arithmetic: +, -, *, /, ** (power)' | |
| 40 | + write(*, '(A)') ' Variables: x := value' | |
| 41 | + write(*, '(A)') ' Precision: value::digits (e.g., pi::50)' | |
| 42 | + write(*, '(A)') ' Complex: 3+4i, (3,4), cmplx(3,4)' | |
| 43 | + write(*, '(A)') ' Functions: sin, cos, tan, log, exp, sqrt, abs' | |
| 44 | + write(*, '(A)') ' Constants: pi, e, i' | |
| 45 | + write(*, '(A)') ' Matrices: [1,2;3,4], zeros(3,3), ones(2,2)' | |
| 46 | + write(*, '(A)') ' Commands: help, exit, clear, precision, info' | |
| 47 | + write(*, '(A)') '' | |
| 48 | + | |
| 49 | + ! Show current precision info | |
| 50 | + info = get_precision_info(real64) | |
| 51 | + write(*, '(A,A)') 'Current precision: ', trim(info%name) | |
| 52 | + write(*, '(A,I0,A)') 'Decimal digits: ', info%decimal_digits, '' | |
| 53 | + write(*, '(A,I0,A)') 'Exponent range: ±', info%exponent_range, '' | |
| 54 | + write(*, '(A)') '' | |
| 55 | + end subroutine print_help | |
| 56 | + | |
| 57 | + !> Check if input is a command (starts with a letter) | |
| 58 | + logical function is_command(input) | |
| 59 | + character(len=*), intent(in) :: input | |
| 60 | + character(len=len_trim(input)) :: trimmed_input | |
| 61 | + | |
| 62 | + trimmed_input = trim(adjustl(input)) | |
| 63 | + | |
| 64 | + if (len_trim(trimmed_input) == 0) then | |
| 65 | + is_command = .false. | |
| 66 | + return | |
| 67 | + end if | |
| 68 | + | |
| 69 | + ! Check if it starts with a letter (command) or digit/operator (expression) | |
| 70 | + is_command = (trimmed_input(1:1) >= 'a' .and. trimmed_input(1:1) <= 'z') .or. & | |
| 71 | + (trimmed_input(1:1) >= 'A' .and. trimmed_input(1:1) <= 'Z') | |
| 72 | + | |
| 73 | + ! Special case: check for assignment (contains :=) | |
| 74 | + if (index(trimmed_input, ':=') > 0) then | |
| 75 | + is_command = .false. | |
| 76 | + end if | |
| 77 | + end function is_command | |
| 78 | + | |
| 79 | + !> Parse and execute a command | |
| 80 | + logical function parse_command(input, variables) result(continue_repl) | |
| 81 | + character(len=*), intent(in) :: input | |
| 82 | + type(variable_t), pointer, intent(inout) :: variables | |
| 83 | + | |
| 84 | + character(len=len_trim(input)) :: command | |
| 85 | + character(len=100) :: arg | |
| 86 | + integer :: space_pos | |
| 87 | + | |
| 88 | + continue_repl = .true. | |
| 89 | + command = trim(adjustl(input)) | |
| 90 | + | |
| 91 | + ! Split command and arguments | |
| 92 | + space_pos = index(command, ' ') | |
| 93 | + if (space_pos > 0) then | |
| 94 | + arg = command(space_pos+1:) | |
| 95 | + command = command(1:space_pos-1) | |
| 96 | + else | |
| 97 | + arg = '' | |
| 98 | + end if | |
| 99 | + | |
| 100 | + ! Convert to lowercase for case-insensitive commands | |
| 101 | + call to_lowercase(command) | |
| 102 | + | |
| 103 | + select case (trim(command)) | |
| 104 | + case ('help', 'h', '?') | |
| 105 | + call print_help() | |
| 106 | + | |
| 107 | + case ('exit', 'quit', 'q') | |
| 108 | + write(*, '(A)') 'Goodbye!' | |
| 109 | + continue_repl = .false. | |
| 110 | + | |
| 111 | + case ('clear', 'cls') | |
| 112 | + call clear_screen() | |
| 113 | + | |
| 114 | + case ('precision') | |
| 115 | + call handle_precision_command(arg) | |
| 116 | + | |
| 117 | + case ('info') | |
| 118 | + call show_system_info() | |
| 119 | + | |
| 120 | + case ('vars', 'variables') | |
| 121 | + call show_variables(variables) | |
| 122 | + | |
| 123 | + case default | |
| 124 | + write(*, '(A,A,A)') 'Unknown command: "', trim(command), '"' | |
| 125 | + write(*, '(A)') 'Type "help" for available commands.' | |
| 126 | + end select | |
| 127 | + end function parse_command | |
| 128 | + | |
| 129 | + !> Main REPL (Read-Eval-Print Loop) | |
| 130 | + subroutine repl_loop() | |
| 131 | + character(len=MAX_LINE_LENGTH) :: input | |
| 132 | + type(variable_t), pointer :: variables => null() | |
| 133 | + logical :: continue_loop | |
| 134 | + integer :: ios | |
| 135 | + | |
| 136 | + call print_banner() | |
| 137 | + continue_loop = .true. | |
| 138 | + | |
| 139 | + do while (continue_loop) | |
| 140 | + write(*, '(A)', advance='no') 'fortbite> ' | |
| 141 | + read(*, '(A)', iostat=ios) input | |
| 142 | + | |
| 143 | + if (ios /= 0) then | |
| 144 | + ! Handle end of file (Ctrl+D) | |
| 145 | + write(*, *) | |
| 146 | + write(*, '(A)') 'Goodbye!' | |
| 147 | + exit | |
| 148 | + end if | |
| 149 | + | |
| 150 | + ! Skip empty lines | |
| 151 | + if (len_trim(input) == 0) cycle | |
| 152 | + | |
| 153 | + if (is_command(input)) then | |
| 154 | + continue_loop = parse_command(input, variables) | |
| 155 | + else | |
| 156 | + ! Handle mathematical expression (placeholder for now) | |
| 157 | + write(*, '(A)') 'Mathematical expression parsing not yet implemented.' | |
| 158 | + write(*, '(A,A,A)') 'You entered: "', trim(input), '"' | |
| 159 | + end if | |
| 160 | + end do | |
| 161 | + | |
| 162 | + ! Clean up variables | |
| 163 | + call cleanup_variables(variables) | |
| 164 | + end subroutine repl_loop | |
| 165 | + | |
| 166 | + !> Convert string to lowercase | |
| 167 | + subroutine to_lowercase(str) | |
| 168 | + character(len=*), intent(inout) :: str | |
| 169 | + integer :: i | |
| 170 | + | |
| 171 | + do i = 1, len(str) | |
| 172 | + if (str(i:i) >= 'A' .and. str(i:i) <= 'Z') then | |
| 173 | + str(i:i) = achar(iachar(str(i:i)) + 32) | |
| 174 | + end if | |
| 175 | + end do | |
| 176 | + end subroutine to_lowercase | |
| 177 | + | |
| 178 | + !> Clear the screen (ANSI escape codes) | |
| 179 | + subroutine clear_screen() | |
| 180 | + write(*, '(A)') achar(27) // '[2J' // achar(27) // '[H' | |
| 181 | + end subroutine clear_screen | |
| 182 | + | |
| 183 | + !> Handle precision command | |
| 184 | + subroutine handle_precision_command(arg) | |
| 185 | + character(len=*), intent(in) :: arg | |
| 186 | + type(precision_info_t) :: info | |
| 187 | + integer :: precision_digits, ios | |
| 188 | + | |
| 189 | + if (len_trim(arg) == 0) then | |
| 190 | + ! Show current precision | |
| 191 | + info = get_precision_info(real64) | |
| 192 | + write(*, '(A,A)') 'Current precision: ', trim(info%name) | |
| 193 | + write(*, '(A,I0)') 'Decimal digits: ', info%decimal_digits | |
| 194 | + write(*, '(A,I0)') 'Exponent range: ±', info%exponent_range | |
| 195 | + else | |
| 196 | + ! Set new precision | |
| 197 | + read(arg, *, iostat=ios) precision_digits | |
| 198 | + if (ios == 0 .and. precision_digits > 0) then | |
| 199 | + write(*, '(A,I0,A)') 'Setting precision to ', precision_digits, ' decimal digits...' | |
| 200 | + write(*, '(A)') '(Note: Precision changes will be implemented in Phase 2)' | |
| 201 | + else | |
| 202 | + write(*, '(A)') 'Invalid precision specification. Use: precision <digits>' | |
| 203 | + end if | |
| 204 | + end if | |
| 205 | + end subroutine handle_precision_command | |
| 206 | + | |
| 207 | + !> Show system information | |
| 208 | + subroutine show_system_info() | |
| 209 | + type(precision_info_t) :: info | |
| 210 | + | |
| 211 | + write(*, '(A)') 'FORTBITE System Information:' | |
| 212 | + write(*, '(A)') ' Version: 1.0.0' | |
| 213 | + write(*, '(A)') ' Language: Modern Fortran' | |
| 214 | + write(*, '(A)') '' | |
| 215 | + | |
| 216 | + write(*, '(A)') 'Available Precisions:' | |
| 217 | + | |
| 218 | + info = get_precision_info(real32) | |
| 219 | + write(*, '(A,I0,A)') ' Single: ', precision(1.0_real32), ' digits' | |
| 220 | + | |
| 221 | + info = get_precision_info(real64) | |
| 222 | + write(*, '(A,I0,A)') ' Double: ', precision(1.0_real64), ' digits' | |
| 223 | + | |
| 224 | + ! Only show quad if available | |
| 225 | + if (real128 > 0) then | |
| 226 | + info = get_precision_info(real128) | |
| 227 | + write(*, '(A,I0,A)') ' Quad: ', precision(1.0_real128), ' digits' | |
| 228 | + end if | |
| 229 | + | |
| 230 | + write(*, '(A)') '' | |
| 231 | + end subroutine show_system_info | |
| 232 | + | |
| 233 | + !> Show current variables | |
| 234 | + subroutine show_variables(variables) | |
| 235 | + type(variable_t), pointer, intent(in) :: variables | |
| 236 | + type(variable_t), pointer :: current | |
| 237 | + | |
| 238 | + current => variables | |
| 239 | + | |
| 240 | + if (.not. associated(current)) then | |
| 241 | + write(*, '(A)') 'No variables defined.' | |
| 242 | + return | |
| 243 | + end if | |
| 244 | + | |
| 245 | + write(*, '(A)') 'Current variables:' | |
| 246 | + do while (associated(current)) | |
| 247 | + write(*, '(A,A,A)', advance='no') ' ', current%name, ' = ' | |
| 248 | + call print_value(current%value) | |
| 249 | + current => current%next | |
| 250 | + end do | |
| 251 | + end subroutine show_variables | |
| 252 | + | |
| 253 | + !> Clean up variable linked list | |
| 254 | + subroutine cleanup_variables(variables) | |
| 255 | + type(variable_t), pointer, intent(inout) :: variables | |
| 256 | + type(variable_t), pointer :: current, next | |
| 257 | + | |
| 258 | + current => variables | |
| 259 | + do while (associated(current)) | |
| 260 | + next => current%next | |
| 261 | + deallocate(current) | |
| 262 | + current => next | |
| 263 | + end do | |
| 264 | + nullify(variables) | |
| 265 | + end subroutine cleanup_variables | |
| 266 | + | |
| 267 | +end module fortbite_io_m | |
src/fortbite_precision_m.f90added@@ -0,0 +1,116 @@ | ||
| 1 | +!> Precision management module for FORTBITE | |
| 2 | +!> | |
| 3 | +!> This module provides precision control using Fortran's selected_real_kind | |
| 4 | +!> system, allowing arbitrary precision arithmetic with user control. | |
| 5 | +module fortbite_precision_m | |
| 6 | + use iso_fortran_env, only: int32, int64, real32, real64, real128 | |
| 7 | + implicit none | |
| 8 | + private | |
| 9 | + | |
| 10 | + ! Public precision parameters | |
| 11 | + public :: wp, dp, qp, sp | |
| 12 | + public :: default_precision, max_precision | |
| 13 | + public :: set_default_precision, get_precision_kind | |
| 14 | + public :: precision_info_t, get_precision_info | |
| 15 | + | |
| 16 | + ! Standard precision kinds | |
| 17 | + integer, parameter :: sp = real32 ! Single precision | |
| 18 | + integer, parameter :: dp = real64 ! Double precision | |
| 19 | + integer, parameter :: qp = real128 ! Quad precision (if available) | |
| 20 | + | |
| 21 | + ! Default working precision (can be changed by user) | |
| 22 | + integer, parameter :: default_precision = dp | |
| 23 | + integer :: wp = default_precision ! Working precision | |
| 24 | + | |
| 25 | + ! Maximum available precision on this system | |
| 26 | + integer, parameter :: max_precision = selected_real_kind(33, 4931) | |
| 27 | + | |
| 28 | + !> Precision information type | |
| 29 | + type :: precision_info_t | |
| 30 | + integer :: kind_param !< Kind parameter | |
| 31 | + integer :: decimal_digits !< Decimal precision | |
| 32 | + integer :: exponent_range !< Exponent range | |
| 33 | + character(len=20) :: name !< Human-readable name | |
| 34 | + logical :: available !< Available on this system | |
| 35 | + end type precision_info_t | |
| 36 | + | |
| 37 | +contains | |
| 38 | + | |
| 39 | + !> Set the default working precision | |
| 40 | + subroutine set_default_precision(precision_digits) | |
| 41 | + integer, intent(in) :: precision_digits | |
| 42 | + | |
| 43 | + integer :: new_kind | |
| 44 | + | |
| 45 | + ! Get the appropriate kind for requested precision | |
| 46 | + new_kind = selected_real_kind(precision_digits) | |
| 47 | + | |
| 48 | + if (new_kind > 0) then | |
| 49 | + wp = new_kind | |
| 50 | + else | |
| 51 | + write(*, '(A,I0,A)') 'Warning: Precision with ', precision_digits, & | |
| 52 | + ' digits not available. Using maximum available precision.' | |
| 53 | + wp = max_precision | |
| 54 | + end if | |
| 55 | + end subroutine set_default_precision | |
| 56 | + | |
| 57 | + !> Get kind parameter for specified decimal precision | |
| 58 | + function get_precision_kind(decimal_digits, exponent_range) result(kind_param) | |
| 59 | + integer, intent(in) :: decimal_digits | |
| 60 | + integer, intent(in), optional :: exponent_range | |
| 61 | + integer :: kind_param | |
| 62 | + | |
| 63 | + integer :: exp_range | |
| 64 | + | |
| 65 | + exp_range = 37 ! Default exponent range | |
| 66 | + if (present(exponent_range)) exp_range = exponent_range | |
| 67 | + | |
| 68 | + kind_param = selected_real_kind(decimal_digits, exp_range) | |
| 69 | + | |
| 70 | + ! Fall back to maximum precision if requested precision unavailable | |
| 71 | + if (kind_param < 0) then | |
| 72 | + kind_param = max_precision | |
| 73 | + end if | |
| 74 | + end function get_precision_kind | |
| 75 | + | |
| 76 | + !> Get information about a precision kind | |
| 77 | + function get_precision_info(kind_param) result(info) | |
| 78 | + integer, intent(in) :: kind_param | |
| 79 | + type(precision_info_t) :: info | |
| 80 | + | |
| 81 | + info%kind_param = kind_param | |
| 82 | + select case (kind_param) | |
| 83 | + case (real32) | |
| 84 | + info%decimal_digits = precision(1.0_real32) | |
| 85 | + info%exponent_range = range(1.0_real32) | |
| 86 | + case (real64) | |
| 87 | + info%decimal_digits = precision(1.0_real64) | |
| 88 | + info%exponent_range = range(1.0_real64) | |
| 89 | + case (real128) | |
| 90 | + info%decimal_digits = precision(1.0_real128) | |
| 91 | + info%exponent_range = range(1.0_real128) | |
| 92 | + case default | |
| 93 | + ! For unknown kinds, try to get info using the kind parameter | |
| 94 | + info%decimal_digits = 15 ! reasonable default | |
| 95 | + info%exponent_range = 307 ! reasonable default | |
| 96 | + end select | |
| 97 | + info%available = (kind_param > 0) | |
| 98 | + | |
| 99 | + ! Set human-readable name | |
| 100 | + select case (kind_param) | |
| 101 | + case (real32) | |
| 102 | + info%name = 'Single Precision' | |
| 103 | + case (real64) | |
| 104 | + info%name = 'Double Precision' | |
| 105 | + case (real128) | |
| 106 | + info%name = 'Quad Precision' | |
| 107 | + case default | |
| 108 | + if (kind_param == max_precision) then | |
| 109 | + info%name = 'Maximum Precision' | |
| 110 | + else | |
| 111 | + info%name = 'Custom Precision' | |
| 112 | + end if | |
| 113 | + end select | |
| 114 | + end function get_precision_info | |
| 115 | + | |
| 116 | +end module fortbite_precision_m | |
src/fortbite_types_m.f90added@@ -0,0 +1,293 @@ | ||
| 1 | +!> Core data types module for FORTBITE | |
| 2 | +!> | |
| 3 | +!> Defines the fundamental data types used throughout FORTBITE: | |
| 4 | +!> scalars, complex numbers, matrices, and variables. | |
| 5 | +module fortbite_types_m | |
| 6 | + use fortbite_precision_m, only: dp, sp, qp | |
| 7 | + use iso_fortran_env, only: real64 | |
| 8 | + use iso_fortran_env, only: int32, int64 | |
| 9 | + implicit none | |
| 10 | + private | |
| 11 | + | |
| 12 | + ! Public types | |
| 13 | + public :: value_t, variable_t, token_t | |
| 14 | + public :: value_type_enum, token_type_enum | |
| 15 | + public :: VALUE_UNDEFINED, VALUE_SCALAR, VALUE_COMPLEX, VALUE_MATRIX, VALUE_UNIT | |
| 16 | + public :: TOKEN_EOF, TOKEN_NUMBER, TOKEN_IDENTIFIER, TOKEN_OPERATOR | |
| 17 | + public :: TOKEN_LPAREN, TOKEN_RPAREN, TOKEN_LBRACKET, TOKEN_RBRACKET | |
| 18 | + public :: TOKEN_SEMICOLON, TOKEN_COMMA, TOKEN_ASSIGN, TOKEN_PRECISION | |
| 19 | + public :: assignment(=) | |
| 20 | + | |
| 21 | + ! Public procedures | |
| 22 | + public :: create_scalar, create_complex, create_matrix | |
| 23 | + public :: destroy_value, copy_value, print_value | |
| 24 | + public :: is_zero, is_real, get_real_part, get_imag_part | |
| 25 | + | |
| 26 | + !> Enumeration for value types | |
| 27 | + enum, bind(c) | |
| 28 | + enumerator :: VALUE_UNDEFINED = 0 | |
| 29 | + enumerator :: VALUE_SCALAR = 1 | |
| 30 | + enumerator :: VALUE_COMPLEX = 2 | |
| 31 | + enumerator :: VALUE_MATRIX = 3 | |
| 32 | + enumerator :: VALUE_UNIT = 4 | |
| 33 | + end enum | |
| 34 | + integer, parameter :: value_type_enum = kind(VALUE_UNDEFINED) | |
| 35 | + | |
| 36 | + !> Enumeration for token types | |
| 37 | + enum, bind(c) | |
| 38 | + enumerator :: TOKEN_EOF = 0 | |
| 39 | + enumerator :: TOKEN_NUMBER = 1 | |
| 40 | + enumerator :: TOKEN_IDENTIFIER = 2 | |
| 41 | + enumerator :: TOKEN_OPERATOR = 3 | |
| 42 | + enumerator :: TOKEN_LPAREN = 4 | |
| 43 | + enumerator :: TOKEN_RPAREN = 5 | |
| 44 | + enumerator :: TOKEN_LBRACKET = 6 | |
| 45 | + enumerator :: TOKEN_RBRACKET = 7 | |
| 46 | + enumerator :: TOKEN_SEMICOLON = 8 | |
| 47 | + enumerator :: TOKEN_COMMA = 9 | |
| 48 | + enumerator :: TOKEN_ASSIGN = 10 | |
| 49 | + enumerator :: TOKEN_PRECISION = 11 | |
| 50 | + end enum | |
| 51 | + integer, parameter :: token_type_enum = kind(TOKEN_EOF) | |
| 52 | + | |
| 53 | + !> Core value type - can represent scalars, complex numbers, matrices | |
| 54 | + type :: value_t | |
| 55 | + integer(value_type_enum) :: value_type = VALUE_UNDEFINED | |
| 56 | + integer :: precision_kind = real64 | |
| 57 | + | |
| 58 | + ! Union-like storage for different value types | |
| 59 | + real(real64) :: scalar_val = 0.0_real64 | |
| 60 | + complex(real64) :: complex_val = (0.0_real64, 0.0_real64) | |
| 61 | + real(real64), allocatable :: matrix_val(:,:) | |
| 62 | + complex(real64), allocatable :: complex_matrix_val(:,:) | |
| 63 | + | |
| 64 | + ! Matrix dimensions | |
| 65 | + integer :: rows = 0 | |
| 66 | + integer :: cols = 0 | |
| 67 | + logical :: is_complex_matrix = .false. | |
| 68 | + end type value_t | |
| 69 | + | |
| 70 | + !> Variable storage type | |
| 71 | + type :: variable_t | |
| 72 | + character(len=:), allocatable :: name | |
| 73 | + type(value_t) :: value | |
| 74 | + type(variable_t), pointer :: next => null() | |
| 75 | + end type variable_t | |
| 76 | + | |
| 77 | + !> Token for lexical analysis | |
| 78 | + type :: token_t | |
| 79 | + integer(token_type_enum) :: token_type = TOKEN_EOF | |
| 80 | + character(len=:), allocatable :: text | |
| 81 | + integer :: position = 0 | |
| 82 | + end type token_t | |
| 83 | + | |
| 84 | + ! Generic interface for assignment | |
| 85 | + interface assignment(=) | |
| 86 | + module procedure assign_value | |
| 87 | + end interface | |
| 88 | + | |
| 89 | +contains | |
| 90 | + | |
| 91 | + !> Create a scalar value | |
| 92 | + function create_scalar(val, precision_kind) result(value) | |
| 93 | + real(real64), intent(in) :: val | |
| 94 | + integer, intent(in), optional :: precision_kind | |
| 95 | + type(value_t) :: value | |
| 96 | + | |
| 97 | + value%value_type = VALUE_SCALAR | |
| 98 | + value%precision_kind = real64 | |
| 99 | + if (present(precision_kind)) value%precision_kind = precision_kind | |
| 100 | + value%scalar_val = val | |
| 101 | + end function create_scalar | |
| 102 | + | |
| 103 | + !> Create a complex value | |
| 104 | + function create_complex(real_part, imag_part, precision_kind) result(value) | |
| 105 | + real(real64), intent(in) :: real_part, imag_part | |
| 106 | + integer, intent(in), optional :: precision_kind | |
| 107 | + type(value_t) :: value | |
| 108 | + | |
| 109 | + value%value_type = VALUE_COMPLEX | |
| 110 | + value%precision_kind = real64 | |
| 111 | + if (present(precision_kind)) value%precision_kind = precision_kind | |
| 112 | + value%complex_val = cmplx(real_part, imag_part, kind=real64) | |
| 113 | + end function create_complex | |
| 114 | + | |
| 115 | + !> Create a matrix value | |
| 116 | + function create_matrix(matrix_data, precision_kind) result(value) | |
| 117 | + real(real64), intent(in) :: matrix_data(:,:) | |
| 118 | + integer, intent(in), optional :: precision_kind | |
| 119 | + type(value_t) :: value | |
| 120 | + | |
| 121 | + value%value_type = VALUE_MATRIX | |
| 122 | + value%precision_kind = real64 | |
| 123 | + if (present(precision_kind)) value%precision_kind = precision_kind | |
| 124 | + | |
| 125 | + value%rows = size(matrix_data, 1) | |
| 126 | + value%cols = size(matrix_data, 2) | |
| 127 | + value%is_complex_matrix = .false. | |
| 128 | + | |
| 129 | + allocate(value%matrix_val(value%rows, value%cols)) | |
| 130 | + value%matrix_val = matrix_data | |
| 131 | + end function create_matrix | |
| 132 | + | |
| 133 | + !> Destroy/deallocate a value | |
| 134 | + subroutine destroy_value(value) | |
| 135 | + type(value_t), intent(inout) :: value | |
| 136 | + | |
| 137 | + if (allocated(value%matrix_val)) deallocate(value%matrix_val) | |
| 138 | + if (allocated(value%complex_matrix_val)) deallocate(value%complex_matrix_val) | |
| 139 | + | |
| 140 | + value%value_type = VALUE_UNDEFINED | |
| 141 | + value%rows = 0 | |
| 142 | + value%cols = 0 | |
| 143 | + end subroutine destroy_value | |
| 144 | + | |
| 145 | + !> Copy a value (deep copy) | |
| 146 | + function copy_value(source) result(dest) | |
| 147 | + type(value_t), intent(in) :: source | |
| 148 | + type(value_t) :: dest | |
| 149 | + | |
| 150 | + dest%value_type = source%value_type | |
| 151 | + dest%precision_kind = source%precision_kind | |
| 152 | + dest%rows = source%rows | |
| 153 | + dest%cols = source%cols | |
| 154 | + dest%is_complex_matrix = source%is_complex_matrix | |
| 155 | + | |
| 156 | + select case (source%value_type) | |
| 157 | + case (VALUE_SCALAR) | |
| 158 | + dest%scalar_val = source%scalar_val | |
| 159 | + case (VALUE_COMPLEX) | |
| 160 | + dest%complex_val = source%complex_val | |
| 161 | + case (VALUE_MATRIX) | |
| 162 | + if (allocated(source%matrix_val)) then | |
| 163 | + allocate(dest%matrix_val(dest%rows, dest%cols)) | |
| 164 | + dest%matrix_val = source%matrix_val | |
| 165 | + end if | |
| 166 | + if (allocated(source%complex_matrix_val)) then | |
| 167 | + allocate(dest%complex_matrix_val(dest%rows, dest%cols)) | |
| 168 | + dest%complex_matrix_val = source%complex_matrix_val | |
| 169 | + end if | |
| 170 | + end select | |
| 171 | + end function copy_value | |
| 172 | + | |
| 173 | + !> Print a value to standard output | |
| 174 | + subroutine print_value(value) | |
| 175 | + type(value_t), intent(in) :: value | |
| 176 | + | |
| 177 | + select case (value%value_type) | |
| 178 | + case (VALUE_SCALAR) | |
| 179 | + write(*, '(G0)') value%scalar_val | |
| 180 | + case (VALUE_COMPLEX) | |
| 181 | + if (aimag(value%complex_val) >= 0.0_real64) then | |
| 182 | + write(*, '(G0,"+",G0,"i")') real(value%complex_val), aimag(value%complex_val) | |
| 183 | + else | |
| 184 | + write(*, '(G0,G0,"i")') real(value%complex_val), aimag(value%complex_val) | |
| 185 | + end if | |
| 186 | + case (VALUE_MATRIX) | |
| 187 | + call print_matrix(value) | |
| 188 | + case default | |
| 189 | + write(*, '(A)') 'Undefined value' | |
| 190 | + end select | |
| 191 | + end subroutine print_value | |
| 192 | + | |
| 193 | + !> Print a matrix value | |
| 194 | + subroutine print_matrix(value) | |
| 195 | + type(value_t), intent(in) :: value | |
| 196 | + integer :: i, j | |
| 197 | + | |
| 198 | + write(*, '(A,I0,"x",I0,A)') '[', value%rows, value%cols, ' matrix]' | |
| 199 | + | |
| 200 | + if (value%rows <= 10 .and. value%cols <= 10) then | |
| 201 | + do i = 1, value%rows | |
| 202 | + write(*, '(A)', advance='no') ' ' | |
| 203 | + do j = 1, value%cols | |
| 204 | + if (value%is_complex_matrix) then | |
| 205 | + write(*, '(SP,G0,G0,"i")', advance='no') & | |
| 206 | + real(value%complex_matrix_val(i,j)), & | |
| 207 | + aimag(value%complex_matrix_val(i,j)) | |
| 208 | + else | |
| 209 | + write(*, '(G0)', advance='no') value%matrix_val(i,j) | |
| 210 | + end if | |
| 211 | + if (j < value%cols) write(*, '(A)', advance='no') ' ' | |
| 212 | + end do | |
| 213 | + write(*, *) ! New line | |
| 214 | + end do | |
| 215 | + end if | |
| 216 | + end subroutine print_matrix | |
| 217 | + | |
| 218 | + !> Check if a value is zero | |
| 219 | + logical function is_zero(value) | |
| 220 | + type(value_t), intent(in) :: value | |
| 221 | + | |
| 222 | + select case (value%value_type) | |
| 223 | + case (VALUE_SCALAR) | |
| 224 | + is_zero = (abs(value%scalar_val) < epsilon(value%scalar_val)) | |
| 225 | + case (VALUE_COMPLEX) | |
| 226 | + is_zero = (abs(value%complex_val) < epsilon(real(value%complex_val))) | |
| 227 | + case default | |
| 228 | + is_zero = .false. | |
| 229 | + end select | |
| 230 | + end function is_zero | |
| 231 | + | |
| 232 | + !> Check if a value is purely real | |
| 233 | + logical function is_real(value) | |
| 234 | + type(value_t), intent(in) :: value | |
| 235 | + | |
| 236 | + select case (value%value_type) | |
| 237 | + case (VALUE_SCALAR) | |
| 238 | + is_real = .true. | |
| 239 | + case (VALUE_COMPLEX) | |
| 240 | + is_real = (abs(aimag(value%complex_val)) < epsilon(real(value%complex_val))) | |
| 241 | + case default | |
| 242 | + is_real = .false. | |
| 243 | + end select | |
| 244 | + end function is_real | |
| 245 | + | |
| 246 | + !> Get real part of a value | |
| 247 | + function get_real_part(value) result(real_val) | |
| 248 | + type(value_t), intent(in) :: value | |
| 249 | + real(real64) :: real_val | |
| 250 | + | |
| 251 | + select case (value%value_type) | |
| 252 | + case (VALUE_SCALAR) | |
| 253 | + real_val = value%scalar_val | |
| 254 | + case (VALUE_COMPLEX) | |
| 255 | + real_val = real(value%complex_val) | |
| 256 | + case default | |
| 257 | + real_val = 0.0_real64 | |
| 258 | + end select | |
| 259 | + end function get_real_part | |
| 260 | + | |
| 261 | + !> Get imaginary part of a value | |
| 262 | + function get_imag_part(value) result(imag_val) | |
| 263 | + type(value_t), intent(in) :: value | |
| 264 | + real(real64) :: imag_val | |
| 265 | + | |
| 266 | + select case (value%value_type) | |
| 267 | + case (VALUE_SCALAR) | |
| 268 | + imag_val = 0.0_real64 | |
| 269 | + case (VALUE_COMPLEX) | |
| 270 | + imag_val = aimag(value%complex_val) | |
| 271 | + case default | |
| 272 | + imag_val = 0.0_real64 | |
| 273 | + end select | |
| 274 | + end function get_imag_part | |
| 275 | + | |
| 276 | + !> Assignment operator for values | |
| 277 | + subroutine assign_value(lhs, rhs) | |
| 278 | + type(value_t), intent(out) :: lhs | |
| 279 | + type(value_t), intent(in) :: rhs | |
| 280 | + | |
| 281 | + ! Simple assignment - let Fortran handle the copying | |
| 282 | + lhs%value_type = rhs%value_type | |
| 283 | + lhs%precision_kind = rhs%precision_kind | |
| 284 | + lhs%scalar_val = rhs%scalar_val | |
| 285 | + lhs%complex_val = rhs%complex_val | |
| 286 | + lhs%rows = rhs%rows | |
| 287 | + lhs%cols = rhs%cols | |
| 288 | + lhs%is_complex_matrix = rhs%is_complex_matrix | |
| 289 | + | |
| 290 | + ! For now, we'll handle matrix copying manually when needed | |
| 291 | + end subroutine assign_value | |
| 292 | + | |
| 293 | +end module fortbite_types_m | |
src/math/arithmetic.cdeleted@@ -1,1 +0,0 @@ | ||
| 1 | -#include "fortbite.h" | |
src/math/complex.cdeleted@@ -1,1 +0,0 @@ | ||
| 1 | -#include "fortbite.h" | |
src/math/functions.cdeleted@@ -1,1 +0,0 @@ | ||
| 1 | -#include "fortbite.h" | |
src/math/matrix.cdeleted@@ -1,1 +0,0 @@ | ||
| 1 | -#include "fortbite.h" | |
src/math/precision.cdeleted@@ -1,1 +0,0 @@ | ||
| 1 | -#include "fortbite.h" | |
src/parser/ast.cdeleted@@ -1,1 +0,0 @@ | ||
| 1 | -#include "fortbite.h" | |
src/parser/lexer.cdeleted@@ -1,258 +0,0 @@ | ||
| 1 | -#include "fortbite.h" | |
| 2 | -#include <ctype.h> | |
| 3 | -#include <string.h> | |
| 4 | - | |
| 5 | -typedef struct { | |
| 6 | - const char* input; | |
| 7 | - size_t position; | |
| 8 | - size_t length; | |
| 9 | - char current_char; | |
| 10 | -} fortbite_lexer_t; | |
| 11 | - | |
| 12 | -static void lexer_advance(fortbite_lexer_t* lexer) { | |
| 13 | - if (lexer->position < lexer->length) { | |
| 14 | - lexer->position++; | |
| 15 | - lexer->current_char = (lexer->position < lexer->length) | |
| 16 | - ? lexer->input[lexer->position] | |
| 17 | - : '\0'; | |
| 18 | - } | |
| 19 | -} | |
| 20 | - | |
| 21 | -static void lexer_skip_whitespace(fortbite_lexer_t* lexer) { | |
| 22 | - while (lexer->current_char != '\0' && isspace(lexer->current_char)) { | |
| 23 | - lexer_advance(lexer); | |
| 24 | - } | |
| 25 | -} | |
| 26 | - | |
| 27 | -static fortbite_token_t lexer_number(fortbite_lexer_t* lexer) { | |
| 28 | - fortbite_token_t token; | |
| 29 | - size_t start = lexer->position; | |
| 30 | - bool has_dot = false; | |
| 31 | - bool has_exp = false; | |
| 32 | - | |
| 33 | - while (lexer->current_char != '\0' && | |
| 34 | - (isdigit(lexer->current_char) || | |
| 35 | - lexer->current_char == '.' || | |
| 36 | - lexer->current_char == 'e' || | |
| 37 | - lexer->current_char == 'E' || | |
| 38 | - lexer->current_char == '+' || | |
| 39 | - lexer->current_char == '-')) { | |
| 40 | - | |
| 41 | - if (lexer->current_char == '.') { | |
| 42 | - if (has_dot || has_exp) break; | |
| 43 | - has_dot = true; | |
| 44 | - } else if (lexer->current_char == 'e' || lexer->current_char == 'E') { | |
| 45 | - if (has_exp) break; | |
| 46 | - has_exp = true; | |
| 47 | - lexer_advance(lexer); | |
| 48 | - if (lexer->current_char == '+' || lexer->current_char == '-') { | |
| 49 | - lexer_advance(lexer); | |
| 50 | - } | |
| 51 | - continue; | |
| 52 | - } else if (lexer->current_char == '+' || lexer->current_char == '-') { | |
| 53 | - if (!has_exp) break; | |
| 54 | - } | |
| 55 | - | |
| 56 | - lexer_advance(lexer); | |
| 57 | - } | |
| 58 | - | |
| 59 | - size_t length = lexer->position - start; | |
| 60 | - token.type = TOKEN_NUMBER; | |
| 61 | - token.value = fortbite_malloc(length + 1); | |
| 62 | - strncpy(token.value, &lexer->input[start], length); | |
| 63 | - token.value[length] = '\0'; | |
| 64 | - token.length = length; | |
| 65 | - token.position = start; | |
| 66 | - | |
| 67 | - return token; | |
| 68 | -} | |
| 69 | - | |
| 70 | -static fortbite_token_t lexer_identifier(fortbite_lexer_t* lexer) { | |
| 71 | - fortbite_token_t token; | |
| 72 | - size_t start = lexer->position; | |
| 73 | - | |
| 74 | - while (lexer->current_char != '\0' && | |
| 75 | - (isalnum(lexer->current_char) || lexer->current_char == '_')) { | |
| 76 | - lexer_advance(lexer); | |
| 77 | - } | |
| 78 | - | |
| 79 | - size_t length = lexer->position - start; | |
| 80 | - token.type = TOKEN_IDENTIFIER; | |
| 81 | - token.value = fortbite_malloc(length + 1); | |
| 82 | - strncpy(token.value, &lexer->input[start], length); | |
| 83 | - token.value[length] = '\0'; | |
| 84 | - token.length = length; | |
| 85 | - token.position = start; | |
| 86 | - | |
| 87 | - return token; | |
| 88 | -} | |
| 89 | - | |
| 90 | -static fortbite_token_t lexer_operator(fortbite_lexer_t* lexer) { | |
| 91 | - fortbite_token_t token; | |
| 92 | - size_t start = lexer->position; | |
| 93 | - | |
| 94 | - switch (lexer->current_char) { | |
| 95 | - case '+': | |
| 96 | - case '-': | |
| 97 | - case '*': | |
| 98 | - case '/': | |
| 99 | - case '^': | |
| 100 | - case '%': | |
| 101 | - lexer_advance(lexer); | |
| 102 | - break; | |
| 103 | - case ':': | |
| 104 | - lexer_advance(lexer); | |
| 105 | - if (lexer->current_char == '=') { | |
| 106 | - lexer_advance(lexer); | |
| 107 | - token.type = TOKEN_ASSIGN; | |
| 108 | - } else if (lexer->current_char == ':') { | |
| 109 | - lexer_advance(lexer); | |
| 110 | - token.type = TOKEN_PRECISION; | |
| 111 | - } else { | |
| 112 | - token.type = TOKEN_ERROR; | |
| 113 | - } | |
| 114 | - break; | |
| 115 | - case '=': | |
| 116 | - lexer_advance(lexer); | |
| 117 | - if (lexer->current_char == '=') { | |
| 118 | - lexer_advance(lexer); | |
| 119 | - } | |
| 120 | - break; | |
| 121 | - case '<': | |
| 122 | - case '>': | |
| 123 | - case '!': | |
| 124 | - lexer_advance(lexer); | |
| 125 | - if (lexer->current_char == '=') { | |
| 126 | - lexer_advance(lexer); | |
| 127 | - } | |
| 128 | - break; | |
| 129 | - default: | |
| 130 | - token.type = TOKEN_ERROR; | |
| 131 | - lexer_advance(lexer); | |
| 132 | - break; | |
| 133 | - } | |
| 134 | - | |
| 135 | - if (token.type != TOKEN_ASSIGN && token.type != TOKEN_PRECISION && token.type != TOKEN_ERROR) { | |
| 136 | - token.type = TOKEN_OPERATOR; | |
| 137 | - } | |
| 138 | - | |
| 139 | - size_t length = lexer->position - start; | |
| 140 | - token.value = fortbite_malloc(length + 1); | |
| 141 | - strncpy(token.value, &lexer->input[start], length); | |
| 142 | - token.value[length] = '\0'; | |
| 143 | - token.length = length; | |
| 144 | - token.position = start; | |
| 145 | - | |
| 146 | - return token; | |
| 147 | -} | |
| 148 | - | |
| 149 | -static fortbite_token_t lexer_next_token(fortbite_lexer_t* lexer) { | |
| 150 | - fortbite_token_t token; | |
| 151 | - | |
| 152 | - lexer_skip_whitespace(lexer); | |
| 153 | - | |
| 154 | - if (lexer->current_char == '\0') { | |
| 155 | - token.type = TOKEN_EOF; | |
| 156 | - token.value = NULL; | |
| 157 | - token.length = 0; | |
| 158 | - token.position = lexer->position; | |
| 159 | - return token; | |
| 160 | - } | |
| 161 | - | |
| 162 | - if (isdigit(lexer->current_char)) { | |
| 163 | - return lexer_number(lexer); | |
| 164 | - } | |
| 165 | - | |
| 166 | - if (isalpha(lexer->current_char) || lexer->current_char == '_') { | |
| 167 | - return lexer_identifier(lexer); | |
| 168 | - } | |
| 169 | - | |
| 170 | - token.position = lexer->position; | |
| 171 | - | |
| 172 | - switch (lexer->current_char) { | |
| 173 | - case '(': | |
| 174 | - token.type = TOKEN_LPAREN; | |
| 175 | - lexer_advance(lexer); | |
| 176 | - break; | |
| 177 | - case ')': | |
| 178 | - token.type = TOKEN_RPAREN; | |
| 179 | - lexer_advance(lexer); | |
| 180 | - break; | |
| 181 | - case '[': | |
| 182 | - token.type = TOKEN_LBRACKET; | |
| 183 | - lexer_advance(lexer); | |
| 184 | - break; | |
| 185 | - case ']': | |
| 186 | - token.type = TOKEN_RBRACKET; | |
| 187 | - lexer_advance(lexer); | |
| 188 | - break; | |
| 189 | - case ';': | |
| 190 | - token.type = TOKEN_SEMICOLON; | |
| 191 | - lexer_advance(lexer); | |
| 192 | - break; | |
| 193 | - case ',': | |
| 194 | - token.type = TOKEN_COMMA; | |
| 195 | - lexer_advance(lexer); | |
| 196 | - break; | |
| 197 | - case 'i': | |
| 198 | - if (lexer->position + 1 < lexer->length && | |
| 199 | - !isalnum(lexer->input[lexer->position + 1])) { | |
| 200 | - token.type = TOKEN_IDENTIFIER; | |
| 201 | - lexer_advance(lexer); | |
| 202 | - } else { | |
| 203 | - return lexer_identifier(lexer); | |
| 204 | - } | |
| 205 | - break; | |
| 206 | - default: | |
| 207 | - return lexer_operator(lexer); | |
| 208 | - } | |
| 209 | - | |
| 210 | - if (token.type != TOKEN_IDENTIFIER) { | |
| 211 | - token.value = fortbite_malloc(2); | |
| 212 | - token.value[0] = lexer->input[token.position]; | |
| 213 | - token.value[1] = '\0'; | |
| 214 | - token.length = 1; | |
| 215 | - } | |
| 216 | - | |
| 217 | - return token; | |
| 218 | -} | |
| 219 | - | |
| 220 | -fortbite_token_t* fortbite_tokenize(const char* input) { | |
| 221 | - if (!input) return NULL; | |
| 222 | - | |
| 223 | - fortbite_lexer_t lexer; | |
| 224 | - lexer.input = input; | |
| 225 | - lexer.position = 0; | |
| 226 | - lexer.length = strlen(input); | |
| 227 | - lexer.current_char = (lexer.length > 0) ? input[0] : '\0'; | |
| 228 | - | |
| 229 | - size_t token_capacity = 16; | |
| 230 | - size_t token_count = 0; | |
| 231 | - fortbite_token_t* tokens = fortbite_malloc(token_capacity * sizeof(fortbite_token_t)); | |
| 232 | - | |
| 233 | - fortbite_token_t token; | |
| 234 | - do { | |
| 235 | - token = lexer_next_token(&lexer); | |
| 236 | - | |
| 237 | - if (token_count >= token_capacity) { | |
| 238 | - token_capacity *= 2; | |
| 239 | - tokens = fortbite_realloc(tokens, token_capacity * sizeof(fortbite_token_t)); | |
| 240 | - } | |
| 241 | - | |
| 242 | - tokens[token_count++] = token; | |
| 243 | - } while (token.type != TOKEN_EOF && token.type != TOKEN_ERROR); | |
| 244 | - | |
| 245 | - return tokens; | |
| 246 | -} | |
| 247 | - | |
| 248 | -void fortbite_tokens_free(fortbite_token_t* tokens) { | |
| 249 | - if (!tokens) return; | |
| 250 | - | |
| 251 | - for (size_t i = 0; tokens[i].type != TOKEN_EOF; i++) { | |
| 252 | - if (tokens[i].value) { | |
| 253 | - fortbite_free(tokens[i].value); | |
| 254 | - } | |
| 255 | - } | |
| 256 | - | |
| 257 | - fortbite_free(tokens); | |
| 258 | -} | |
src/parser/parser.cdeleted@@ -1,1 +0,0 @@ | ||
| 1 | -#include "fortbite.h" | |
src/parser/syntax.cdeleted@@ -1,1 +0,0 @@ | ||
| 1 | -#include "fortbite.h" | |
src/plotting/ascii_plot.cdeleted@@ -1,1 +0,0 @@ | ||
| 1 | -#include "fortbite.h" | |
src/plotting/data.cdeleted@@ -1,1 +0,0 @@ | ||
| 1 | -#include "fortbite.h" | |
src/plotting/export.cdeleted@@ -1,1 +0,0 @@ | ||
| 1 | -#include "fortbite.h" | |
src/plugins/api.cdeleted@@ -1,1 +0,0 @@ | ||
| 1 | -#include "fortbite.h" | |
src/plugins/loader.cdeleted@@ -1,1 +0,0 @@ | ||
| 1 | -#include "fortbite.h" | |
src/plugins/registry.cdeleted@@ -1,1 +0,0 @@ | ||
| 1 | -#include "fortbite.h" | |
src/units/converter.cdeleted@@ -1,1 +0,0 @@ | ||
| 1 | -#include "fortbite.h" | |
src/units/database.cdeleted@@ -1,1 +0,0 @@ | ||
| 1 | -#include "fortbite.h" | |
src/units/parser.cdeleted@@ -1,1 +0,0 @@ | ||
| 1 | -#include "fortbite.h" | |
src/utils/debug.cdeleted@@ -1,1 +0,0 @@ | ||
| 1 | -#include "fortbite.h" | |
src/utils/file.cdeleted@@ -1,1 +0,0 @@ | ||
| 1 | -#include "fortbite.h" | |
src/utils/string.cdeleted@@ -1,1 +0,0 @@ | ||
| 1 | -#include "fortbite.h" | |