add BASIC interpreter

Signed-off-by: Avinal Kumar <avinal.xlvii@gmail.com>
This commit is contained in:
2021-08-03 22:27:49 +05:30
parent 886ed106e7
commit 5a5a37e3f8
23 changed files with 3770 additions and 0 deletions

View File

@@ -0,0 +1,28 @@
/**
* SPDX-License-Identifier: MIT
* SPDX-FileCopyrightText: 2015-2016 Johan Van den Brande
*
* @file arch.h
*/
#ifndef BASIC_ARCH_H_
#define BASIC_ARCH_H_
#include <stdbool.h>
#include <stdint.h>
#include <stdlib.h>
int arch_init(void);
typedef void (*arch_load_out_cb)(char* line, void* context);
int arch_load(char* filename, arch_load_out_cb cb, void* context);
typedef uint16_t (*arch_save_cb)(char** line, void* context);
int arch_save(char* filename, arch_save_cb cb, void* context);
typedef void (*arch_dir_out_cb)(char* name, size_t size, bool label, void* context);
int arch_dir(arch_dir_out_cb cb, void* context);
int arch_delete(char* filename);
#endif // BASIC_ARCH_H_

View File

@@ -0,0 +1,28 @@
/**
* SPDX-License-Identifier: MIT
* SPDX-FileCopyrightText: 2015-2016 Johan Van den Brande
*
* @file array.h
*/
#ifndef BASIC_ARRAY_H_
#define BASIC_ARRAY_H_
#include <stddef.h>
typedef struct array array;
array* array_new(size_t element_size);
array* array_alloc(array* array, size_t size);
void array_destroy(array* array);
void* array_push(array* array, void* value);
void* array_get(array* array, size_t index);
void* array_set(array* array, size_t index, void* value);
size_t array_size(array* array);
#endif // BASIC_ARRAY_H_

View File

@@ -0,0 +1,19 @@
/**
* SPDX-License-Identifier: MIT
* SPDX-FileCopyrightText: 2015-2016 Johan Van den Brande
*
* @file callback.h
*/
#ifndef BASIC_CALLBACK_H_
#define BASIC_CALLBACK_H_
#include <stdbool.h>
typedef struct error {
int error;
};
typedef bool (*callback)(error err, void* data);
#endif // BASIC_CALLBACK_H_

View File

@@ -0,0 +1,25 @@
/**
* SPDX-License-Identifier: MIT
* SPDX-FileCopyrightText: 2015-2016 Johan Van den Brande
*
* @file dictionary.h
*/
#ifndef BASIC_DICTIONARY_H_
#define BASIC_DICTIONARY_H_
#include <stdbool.h>
typedef struct dictionary dictionary;
typedef void (*dictionary_each_cb)(char* name, void* value, void* context);
dictionary* dictionary_new(void);
void dictionary_destroy(dictionary* d, dictionary_each_cb cb);
void dictionary_put(dictionary* d, char* name, void* value);
bool dictionary_has(dictionary* d, char* name);
void* dictionary_get(dictionary* d, char* name);
void dictionary_each(dictionary* d, dictionary_each_cb cb, void* context);
void* dictionary_del(dictionary* d, char* name);
#endif // BASIC_DICTIONARY_H_

View File

@@ -0,0 +1,14 @@
/**
* SPDX-License-Identifier: MIT
* SPDX-FileCopyrightText: 2015-2016 Johan Van den Brande
*
* @file error.h
*/
#ifndef BASIC_ERROR_H_
#define BASIC_ERROR_H_
extern char *last_error;
void error(const char *error_msg);
#endif // BASIC_ERROR_H_

View File

@@ -0,0 +1,13 @@
/**
* SPDX-License-Identifier: MIT
* SPDX-FileCopyrightText: 2015-2016 Johan Van den Brande
*
* @file hexdump.h
*/
#ifndef BASIC_HEXDUMP_H_
#define BASIC_HEXDUMP_H_
void hexdump(char *desc, void *addr, int len);
#endif // BASIC_HEXDUMP_H_

View File

@@ -0,0 +1,18 @@
/**
* SPDX-License-Identifier: MIT
* SPDX-FileCopyrightText: 2015-2016 Johan Van den Brande
*
* @file io.h
*/
#ifndef BASIC_IO_H_
#define BASIC_IO_H_
#include <stdlib.h>
typedef int (*basic_putchar)(int ch);
typedef int (*basic_getchar)(void);
void basic_io_print(char* buffer);
char* basic_io_readline(char* prompt, char* buffer, size_t buffer_size);
#endif // BASIC_IO_H_

View File

@@ -0,0 +1,13 @@
/**
* SPDX-License-Identifier: MIT
* SPDX-FileCopyrightText: 2015-2016 Johan Van den Brande
*
* @file kbhit.h
*/
#ifndef BASIC_KBHIT_H_
#define BASIC_KBHIT_H_
int kbhit(void);
#endif // BASIC_KBHIT_H_

View File

@@ -0,0 +1,42 @@
/**
* SPDX-License-Identifier: MIT
* SPDX-FileCopyrightText: 2015-2016 Johan Van den Brande
*
* @file lines.h
*/
#ifndef BASIC_LINES_H_
#define BASIC_LINES_H_
#include <stdbool.h>
#include <stddef.h>
#include <stdint.h>
typedef struct line line;
struct line {
uint16_t number;
uint8_t length;
char contents;
};
void lines_init(char* memory, size_t memory_size);
size_t lines_memory_used(void);
size_t lines_memory_available(void);
bool lines_delete(uint16_t number);
bool lines_store(uint16_t number, char* contents);
typedef void (*lines_list_cb)(uint16_t number, char* contents);
void lines_list(uint16_t start, uint16_t end, lines_list_cb out);
void lines_clear(void);
char* lines_get_contents(uint16_t number);
uint16_t lines_first(void);
uint16_t lines_next(uint16_t number);
#endif // BASIC_LINES_H_

View File

@@ -0,0 +1,87 @@
/**
* SPDX-License-Identifier: MIT
* SPDX-FileCopyrightText: 2015-2016 Johan Van den Brande
*
* @file parser.h
*/
#ifndef BASIC_PARSER_H_
#define BASIC_PARSER_H_
#include <io.h>
#include <stdbool.h>
#include <tokenizer.h>
float evaluate(char* expression_string);
void evaluate_print(char* line);
void evaluate_print_func_param(char* func, float param);
const char* evaluate_last_error(void);
void clear_last_error(void);
void basic_init(size_t memory_size, size_t stack_size);
void basic_destroy(void);
void basic_register_io(basic_putchar putch, basic_getchar getch);
char* basic_readline(char* prompt, char* buffer, size_t buffer_size);
void basic_eval(char* line);
void basic_run(void);
// For extensions
typedef float (*function)(float number);
typedef struct {
token _token;
function _function;
} token_to_function;
typedef enum {
basic_function_type_keyword,
basic_function_type_op,
basic_function_type_numeric,
basic_function_type_string,
basic_function_type_print
} basic_function_type;
typedef enum { kind_numeric, kind_string } kind;
typedef union {
float number;
char* string;
} value;
typedef struct {
kind kind;
bool empty;
bool mallocd;
value value;
} basic_type;
typedef int (*function_0)(basic_type* rv);
typedef int (*function_1)(basic_type* v1, basic_type* rv);
typedef int (*function_2)(basic_type* v1, basic_type* v2, basic_type* rv);
typedef int (*function_3)(basic_type* v1, basic_type* v2, basic_type* v3, basic_type* rv);
typedef int (*function_4)(basic_type* v1, basic_type* v2, basic_type* v3, basic_type* v4,
basic_type* rv);
typedef int (*function_5)(basic_type* v1, basic_type* v2, basic_type* v3, basic_type* v4,
basic_type* v5, basic_type* rv);
token register_token(char* token_name);
token register_function_0(basic_function_type type, char* keyword, function_0 function);
token register_function_1(basic_function_type type, char* keyword, function_1 function, kind v1);
token register_function_2(basic_function_type type, char* keyword, function_2 function, kind v1,
kind v2);
token register_function_3(basic_function_type type, char* keyword, function_3 function, kind v1,
kind v2, kind v3);
token register_function_4(basic_function_type type, char* keyword, function_4 function, kind v1,
kind v2, kind v3, kind v4);
token register_function_5(basic_function_type type, char* keyword, function_5 function, kind v1,
kind v2, kind v3, kind v4, kind v5);
#endif // BASIC_PARSER_H_

View File

@@ -0,0 +1,70 @@
/**
* SPDX-License-Identifier: MIT
* SPDX-FileCopyrightText: 2015-2016 Johan Van den Brande
*
* @file tokenizer.h
*/
#ifndef BASIC_TOKENIZER_H_
#define BASIC_TOKENIZER_H_
#include <stdlib.h>
#define tokenizer_string_length 64
#define tokenizer_variable_length 8
typedef unsigned int token;
typedef char* token_name;
typedef char* token_keyword;
typedef struct {
token token;
token_name name;
} token_entry;
#define add_token(t, k) static token_entry _##t = {t, k};
typedef enum {
// Standard token types needed by the tokenizer
T_THE_END,
T_ERROR,
T_EOF,
T_NUMBER,
T_STRING,
T_VARIABLE_STRING,
T_VARIABLE_NUMBER,
// Some tokens that are standard as well
T_PLUS,
T_MINUS,
T_MULTIPLY,
T_DIVIDE,
T_LEFT_BANANA,
T_RIGHT_BANANA,
T_COLON,
T_SEMICOLON,
T_EQUALS,
T_LESS,
T_GREATER,
T_COMMA,
TOKEN_TYPE_END
} token_type;
void tokenizer_setup(void);
void tokenizer_init(char* input);
token tokenizer_get_next_token(void);
float tokenizer_get_number(void);
char* tokenizer_get_string(void);
void tokenizer_get_variable_name(char* name);
char* tokenizer_token_name(token);
char* tokenizer_char_pointer(char* set);
void tokenizer_add_tokens(token_entry* tokens);
void tokenizer_register_token(token_entry* entry);
void tokenizer_free_registered_tokens(void);
#endif // BASIC_TOKENIZER_H_

View File

@@ -0,0 +1,41 @@
/**
* SPDX-License-Identifier: MIT
* SPDX-FileCopyrightText: 2015-2016 Johan Van den Brande
*
* @file variable.h
*/
#ifndef BASIC_VARIABLES_H_
#define BASIC_VARIABLES_H_
#include <stdbool.h>
typedef enum { variable_type_unknown, variable_type_numeric, variable_type_string } variable_type;
typedef struct variable variable;
bool variables_init(void);
void variables_destroy(void);
variable* variable_get(char* name);
char* variable_get_string(char* name);
float variable_get_numeric(char* name);
variable* variable_set_string(char* name, char* value);
variable* variable_set_numeric(char* name, float value);
variable_type variable_get_type(char* name);
variable* variable_array_init(char* name, variable_type type, size_t dimensions, size_t* vector);
variable* variable_array_set_string(char* name, char* value, size_t* vector);
char* variable_array_get_string(char* name, size_t* vector);
variable* variable_array_set_numeric(char* name, float value, size_t* vector);
float variable_array_get_numeric(char* name, size_t* vector);
typedef void (*variables_each_cb)(variable* var, void* context);
void variables_each(variables_each_cb each, void* context);
void variable_dump(variable* var);
#endif // BASIC_VARIABLES_H_

102
libs/basic/src/arch.c Normal file
View File

@@ -0,0 +1,102 @@
/**
* SPDX-License-Identifier: MIT
* SPDX-FileCopyrightText: 2015-2016 Johan Van den Brande
*
* @file arch.c
*/
#define _GNU_SOURCE
#include "arch.h"
#include <dirent.h>
#include <stdbool.h>
#include <stdio.h>
#include <string.h>
#include <sys/stat.h>
int arch_init(void) { return 0; }
static char* _get_path(void) {
static char* _path = NULL;
_path = getenv("BASIC_PATH");
if (_path == NULL) {
_path = ".";
}
if (_path[strlen(_path) - 1] == '/') {
_path[strlen(_path) - 1] = '\0';
}
return _path;
}
int arch_load(char* name, arch_load_out_cb cb, void* context) {
char* filename;
asprintf(&filename, "%s/%s.bas", _get_path(), name);
FILE* fp = fopen(filename, "r");
if (!fp) {
return 1;
}
char line[256];
while (fgets(line, 256, fp) != NULL) {
cb(line, context);
}
fclose(fp);
free(filename);
return 0;
}
int arch_save(char* name, arch_save_cb cb, void* context) {
char* line;
char* filename;
asprintf(&filename, "%s/%s.bas", _get_path(), name);
FILE* fp = fopen(filename, "w");
if (!fp) {
return 1;
}
for (;;) {
uint16_t number = cb(&line, context);
if (line == NULL) {
break;
}
fprintf(fp, "%d %s\n", number, line);
}
fclose(fp);
free(filename);
return 0;
}
int arch_dir(arch_dir_out_cb cb, void* context) {
char out[256];
snprintf(out, sizeof(out), "dir: %s", _get_path());
cb(out, 0, true, context);
struct stat stats;
struct dirent* ent;
DIR* dir;
dir = opendir(_get_path());
while ((ent = readdir(dir)) != NULL) {
char* name = ent->d_name;
if (strlen(name) > 4) {
char* ext = name + strlen(name) - 4;
if (strncmp(ext, ".bas", 4) == 0) {
snprintf(out, sizeof(out), "%s/%s", _get_path(), name);
stat(out, &stats);
name[strlen(name) - 4] = '\0';
cb(name, stats.st_size, false, context);
}
}
}
closedir(dir);
return 0;
}
int arch_delete(char* name) {
char* filename;
asprintf(&filename, "%s/%s.bas", _get_path(), name);
remove(filename);
free(filename);
return 0;
}

56
libs/basic/src/array.c Normal file
View File

@@ -0,0 +1,56 @@
/**
* SPDX-License-Identifier: MIT
* SPDX-FileCopyrightText: 2015-2016 Johan Van den Brande
*
* @file array.c
*/
#include "array.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
struct array {
size_t element_size;
size_t size;
char* ptr;
};
array* array_new(size_t element_size) {
array* a = malloc(sizeof(array));
a->element_size = element_size;
a->size = 0;
a->ptr = NULL;
return a;
}
array* array_alloc(array* array, size_t size) {
array->size = size;
array->ptr = realloc(array->ptr, array->element_size * array->size);
memset(array->ptr, 0, array->element_size * array->size);
return array;
}
void array_destroy(array* array) {
free(array->ptr);
free(array);
}
void* array_push(array* array, void* value) {
array->size++;
array->ptr = realloc(array->ptr, array->element_size * array->size);
void* element = array->ptr + array->element_size * (array->size - 1);
memcpy(element, value, array->element_size);
return element;
}
void* array_get(array* array, size_t index) { return array->ptr + index * array->element_size; }
void* array_set(array* array, size_t index, void* value) {
void* element = array_get(array, index);
memcpy(element, value, array->element_size);
return element;
}
size_t array_size(array* array) { return array->size; }

163
libs/basic/src/dictionary.c Normal file
View File

@@ -0,0 +1,163 @@
/**
* SPDX-License-Identifier: MIT
* SPDX-FileCopyrightText: 2015-2016 Johan Van den Brande
*
* @file dictionary.c
*/
#define _GNU_SOURCE
#include <dictionary.h>
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
typedef struct entry entry;
struct entry {
entry* next;
char* name;
void* value;
};
#define HASHSIZE 13
struct dictionary {
entry* hashtab[HASHSIZE];
};
static unsigned int hash(char* name) {
unsigned int hashval;
for (hashval = 0; *name != '\0'; name++) {
hashval = *name + 31 * hashval;
}
return hashval % HASHSIZE;
}
static entry* _get(dictionary* d, char* name) {
entry* entry;
for (entry = d->hashtab[hash(name)]; entry != NULL; entry = entry->next) {
if (strcmp(name, entry->name) == 0) {
return entry;
}
}
return NULL;
}
void* dictionary_get(dictionary* d, char* name) {
entry* entry = _get(d, name);
if (entry) {
return entry->value;
}
return NULL;
}
bool dictionary_has(dictionary* d, char* name) {
entry* entry = _get(d, name);
if (entry) {
return true;
}
return false;
}
void dictionary_put(dictionary* d, char* name, void* value) {
entry* element;
unsigned int hashval;
element = _get(d, name);
if (element == NULL) {
element = (entry*)malloc(sizeof(*element));
if (element == NULL || (element->name = strdup(name)) == NULL) {
return;
}
hashval = hash(name);
element->next = d->hashtab[hashval];
d->hashtab[hashval] = element;
}
element->value = value;
}
void* dictionary_del(dictionary* d, char* name) {
entry* root = d->hashtab[hash(name)];
if (root == NULL) {
return NULL;
}
if (strcmp(name, root->name) == 0) {
d->hashtab[hash(name)] = root->next;
void* value = root->value;
free(root->name);
free(root);
return value;
}
entry* element = root;
while (element->next) {
entry* next = element->next;
if (strcmp(name, next->name) == 0) {
element->next = next->next;
void* value = next->value;
free(next->name);
free(next);
return value;
}
}
return NULL;
}
void dictionary_each(dictionary* d, dictionary_each_cb cb, void* context) {
entry* next_entry = NULL;
if (!cb) {
return;
}
for (size_t i = 0; i < HASHSIZE; i++) {
entry* entry = d->hashtab[i];
while (entry) {
next_entry = entry->next;
cb(entry->name, entry->value, context);
entry = next_entry;
}
}
}
dictionary* dictionary_new() {
dictionary* d = malloc(sizeof(dictionary));
if (d == NULL) {
return NULL;
}
for (size_t i = 0; i < HASHSIZE; i++) {
d->hashtab[i] = NULL;
}
return d;
}
typedef struct {
dictionary* d;
dictionary_each_cb cb;
} _free_s;
static void destroy_cb_pass_1(char* name, void* value, void* context) {
_free_s* ctx = (_free_s*)context;
dictionary_each_cb free_cb = ctx->cb;
free_cb(name, value, NULL);
}
static void destroy_cb_pass_2(char* name, void* value, void* context) {
_free_s* ctx = (_free_s*)context;
dictionary* d = ctx->d;
dictionary_del(d, name);
}
void dictionary_destroy(dictionary* d, dictionary_each_cb free_cb) {
_free_s ctx = {.d = d, .cb = free_cb};
dictionary_each(d, destroy_cb_pass_1, &ctx);
dictionary_each(d, destroy_cb_pass_2, &ctx);
free(d);
}

37
libs/basic/src/error.c Normal file
View File

@@ -0,0 +1,37 @@
/**
* SPDX-License-Identifier: MIT
* SPDX-FileCopyrightText: 2015-2016 Johan Van den Brande
*
* @file error.c
*/
#include <execinfo.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
extern uint16_t __line;
const char *last_error = NULL;
void error(const char *error_msg) {
void *array[10];
size_t size;
char **strings;
size_t i;
last_error = error_msg;
printf("--- ERROR: %d %s\n", __line, error_msg);
size = backtrace(array, 10);
strings = backtrace_symbols(array, size);
printf("SHOW %zd STACK FRAMES:\n", size);
for (i = 0; i < size; i++) {
printf(" %s\n", strings[i]);
}
free(strings);
}

42
libs/basic/src/hexdump.c Normal file
View File

@@ -0,0 +1,42 @@
/**
* SPDX-License-Identifier: MIT
* SPDX-FileCopyrightText: 2015-2016 Johan Van den Brande
*
* @file hexdump.c
*/
#include <stdio.h>
void hexdump(char *desc, void *addr, int len) {
int i;
unsigned char buff[17];
unsigned char *pc = (unsigned char *)addr;
if (desc != NULL) {
printf("%s:\n", desc);
}
for (i = 0; i < len; i++) {
if ((i % 16) == 0) {
if (i != 0) {
printf(" %s\n", buff);
}
printf(" %04x ", i);
}
printf(" %02x", pc[i]);
if ((pc[i] < 0x20) || (pc[i] > 0x7e)) {
buff[i % 16] = '.';
} else {
buff[i % 16] = pc[i];
}
buff[(i % 16) + 1] = '\0';
}
while ((i % 16) != 0) {
printf(" ");
i++;
}
printf(" %s\n", buff);
}

49
libs/basic/src/io.c Normal file
View File

@@ -0,0 +1,49 @@
/**
* SPDX-License-Identifier: MIT
* SPDX-FileCopyrightText: 2015-2016 Johan Van den Brande
*
* @file io.c
*/
#include <ctype.h>
#include <io.h>
#include <stdlib.h>
#include <string.h>
extern basic_putchar __putch;
extern basic_getchar __getch;
void basic_io_print(char* buffer) {
for (size_t i = 0; i < strlen(buffer); ++i) {
__putch(buffer[i]);
}
}
char* basic_io_readline(char* prompt, char* buffer, size_t buffer_size) {
size_t len = 0;
char ch;
basic_io_print(prompt);
while ((ch = __getch()) != '\n' && len < buffer_size - 1) {
#ifdef BASIC_READLINE_ECHO
__putch(ch);
#endif
switch (ch) {
case '\b':
if (len > 0) {
buffer[--len] = '\0';
#ifdef BASIC_READLINE_ECHO
__putch(' ');
__putch('\b');
#endif
}
break;
default:
buffer[len++] = ch;
}
}
#ifdef BASIC_READLINE_ECHO
__putch('\n');
#endif
buffer[len] = '\0';
return buffer;
}

30
libs/basic/src/kbhit.c Normal file
View File

@@ -0,0 +1,30 @@
/**
* SPDX-License-Identifier: MIT
* SPDX-FileCopyrightText: 2015-2016 Johan Van den Brande
*
* @file kbhit.c
*/
#include <stdbool.h>
#include <stdio.h>
#include <sys/ioctl.h>
#include <sys/select.h>
#include <termios.h>
int kbhit(void) {
static const int STDIN = 0;
static bool initialized = false;
if (!initialized) {
struct termios term;
tcgetattr(STDIN, &term);
term.c_lflag &= ~ICANON;
tcsetattr(STDIN, TCSANOW, &term);
setbuf(stdin, NULL);
initialized = true;
}
int bytesWaiting;
ioctl(STDIN, FIONREAD, &bytesWaiting);
return bytesWaiting;
}

263
libs/basic/src/lines.c Normal file
View File

@@ -0,0 +1,263 @@
/**
* SPDX-License-Identifier: MIT
* SPDX-FileCopyrightText: 2015-2016 Johan Van den Brande
*
* @file lines.c
*/
#include "lines.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "hexdump.h"
static char* __memory;
static char* __memory_end;
static size_t __memory_size;
static line* _next(line* l) {
char* p = (char*)l;
p += sizeof(line) - 1 + l->length;
return (line*)p;
}
static bool _is_end(line* l) { return l && l->number == 0 && l->length == 0; }
static line* _find_end(line* l) {
line* n = l;
while (!_is_end(n)) {
n = _next(n);
}
return n;
}
void lines_init(char* memory, size_t memory_size) {
__memory = memory;
__memory_end = memory;
__memory_size = memory_size;
// Signal end
line* l = (line*)__memory;
l->number = 0;
l->length = 0;
}
size_t lines_memory_used(void) {
char* p = __memory;
line* start = (line*)p;
line* end = _find_end(start);
end = _next(end);
char* m_start = (char*)start;
char* m_end = (char*)end;
return m_end - m_start;
}
size_t lines_memory_available(void) { return __memory_size - lines_memory_used(); }
bool lines_store(uint16_t number, char* contents) {
char* p = __memory;
line* l = (line*)p;
while (!_is_end(l)) {
line* next = _next(l);
// Find line that is to be insert after. That line has a line number <
// insert and the next line has a >
if (l->number < number && next->number > number) {
// The address of the insert is the same as the next line
line* insert = next;
// But we need to move the memory block holding the rest to the right.
line* end = _find_end(insert);
end = _next(end); // Move to next empty slot (we keep the sentinel in the copy)
// We have the end*, calculate size to move
char* m_src = (char*)insert;
char* m_end = (char*)end;
size_t m_size = m_end - m_src;
// Calculate offset to move
size_t insert_size = sizeof(line) - 1 + strlen(contents) + 1;
char* m_dst = m_src + insert_size;
// Move the memory block
memmove(m_dst, m_src, m_size);
// Set the data of the insert
insert->number = number;
insert->length = strlen(contents) + 1;
strcpy(&(insert->contents), contents);
return true;
}
// Replace
if (l->number == number) {
// We need to shift the memory to the new offset determined by the size of
// the line to be inserted
line* end = _find_end(l);
end = _next(end); // Move to next empty slot (we keep the sentinel in the copy)
// Calculate size of block
char* m_src = (char*)next;
char* m_end = (char*)end;
size_t m_size = m_end - m_src;
// Calculate offset to move
size_t replace_size = sizeof(line) - 1 + strlen(contents) + 1;
size_t actual_size = sizeof(line) - 1 + strlen(&(l->contents)) + 1;
int offset = replace_size - actual_size;
char* m_dst = m_src + offset;
// Move the memory block
memmove(m_dst, m_src, m_size);
// Set the data of the replace
l->length = strlen(contents) + 1;
strcpy(&(l->contents), contents);
return true;
}
// Prepend
if (l->number > number) {
// The address of the insert is the same as the actual line
line* insert = l;
// But we need to move the memory block holding the rest to the right.
line* end = _find_end(insert);
end = _next(end); // Move to next empty slot (we keep the sentinel in the copy)
// We have the end*, calculate size to move
char* m_src = (char*)insert;
char* m_end = (char*)end;
size_t m_size = m_end - m_src;
// Calculate offset to move
size_t insert_size = sizeof(line) - 1 + strlen(contents) + 1;
char* m_dst = m_src + insert_size;
// Move the memory block
memmove(m_dst, m_src, m_size);
// Set the data of the insert
insert->number = number;
insert->length = strlen(contents) + 1;
strcpy(&(insert->contents), contents);
return true;
}
l = next;
}
l->number = number;
l->length = strlen(contents) + 1; // Length is offset to next line
strcpy(&(l->contents), contents);
line* end = _next(l);
end->number = 0;
end->length = 0;
return true;
}
bool lines_delete(uint16_t number) {
// find the line
line* l = (line*)__memory;
while (!_is_end(l) && l->number != number) {
l = _next(l);
}
if (_is_end(l)) {
return false;
}
// l is the line to delete
// check if this is the last line
line* next = _next(l);
if (_is_end(next)) {
memset(l, 0x00, sizeof(line) - 1 + strlen(&(l->contents)) + 1);
l->number = 0;
l->length = 0;
strcpy(&(l->contents), "");
} else {
char* dst = (char*)l;
char* src = (char*)next;
line* lend = _find_end(next);
lend = _next(lend); // Move to next empty slot (we keep the sentinel in the copy)
char* end = (char*)lend;
size_t size = (char*)end - src;
memmove(dst, src, size);
size_t rest = src - dst;
memset(end - rest, 0x00, rest);
}
return true;
}
static bool _in_range(uint16_t i, uint16_t low, uint16_t high) {
if (low == 0 && high == 0) {
return true;
}
if (low == 0 && i <= high) {
return true;
}
if (high == 0 && i >= low) {
return true;
}
if (i >= low && i <= high) {
return true;
}
return false;
}
void lines_list(uint16_t start, uint16_t end, lines_list_cb out) {
char* p = __memory;
line* l = (line*)p;
while (!_is_end(l)) {
if (_in_range(l->number, start, end)) {
out(l->number, &(l->contents));
}
l = _next(l);
}
}
void lines_clear(void) {
char* end = (char*)_next(_find_end((line*)__memory));
memset(__memory, 0x00, end - __memory);
line* l = (line*)__memory;
l->number = 0;
l->length = 0;
}
char* lines_get_contents(uint16_t number) {
line* l = (line*)__memory;
while (!_is_end(l) && l->number != number) {
l = _next(l);
}
if (_is_end(l)) {
return NULL;
}
return &(l->contents);
}
uint16_t lines_first(void) {
line* l = (line*)__memory;
return l->number;
}
uint16_t lines_next(uint16_t number) {
line* l = (line*)__memory;
while (!_is_end(l) && l->number <= number) {
l = _next(l);
}
if (number == l->number) {
return 0;
}
return l->number;
}

2071
libs/basic/src/parser.c Normal file

File diff suppressed because it is too large Load Diff

222
libs/basic/src/tokenizer.c Normal file
View File

@@ -0,0 +1,222 @@
/**
* SPDX-License-Identifier: MIT
* SPDX-FileCopyrightText: 2015-2016 Johan Van den Brande
*
* @file tokenizer.c
*/
#include "tokenizer.h"
#include <ctype.h>
#include <math.h>
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "arch.h"
#include "array.h"
#include "hexdump.h"
static array *token_array = NULL;
add_token(T_ERROR, NULL);
add_token(T_EOF, NULL);
add_token(T_NUMBER, NULL);
add_token(T_STRING, NULL);
add_token(T_VARIABLE_STRING, NULL);
add_token(T_VARIABLE_NUMBER, NULL);
add_token(T_PLUS, "+");
add_token(T_MINUS, "-");
add_token(T_MULTIPLY, "*");
add_token(T_DIVIDE, "/");
add_token(T_LEFT_BANANA, "(");
add_token(T_RIGHT_BANANA, ")");
add_token(T_COLON, ":");
add_token(T_SEMICOLON, ";");
add_token(T_EQUALS, "=");
add_token(T_LESS, "<");
add_token(T_GREATER, ">");
add_token(T_COMMA, ",");
char *tokenizer_line = NULL;
char *tokenizer_p = NULL;
char *tokenizer_next_p = NULL;
token tokenizer_actual_token;
float tokenizer_actual_number;
char tokenizer_actual_char;
char tokenizer_actual_string[tokenizer_string_length];
char tokenizer_actual_variable[tokenizer_variable_length];
void tokenizer_setup(void) {
token_array = array_new(sizeof(token_entry));
tokenizer_register_token(&_T_ERROR);
tokenizer_register_token(&_T_EOF);
tokenizer_register_token(&_T_NUMBER);
tokenizer_register_token(&_T_STRING);
tokenizer_register_token(&_T_VARIABLE_STRING);
tokenizer_register_token(&_T_VARIABLE_NUMBER);
tokenizer_register_token(&_T_PLUS);
tokenizer_register_token(&_T_MINUS);
tokenizer_register_token(&_T_MULTIPLY);
tokenizer_register_token(&_T_DIVIDE);
tokenizer_register_token(&_T_LEFT_BANANA);
tokenizer_register_token(&_T_RIGHT_BANANA);
tokenizer_register_token(&_T_COLON);
tokenizer_register_token(&_T_SEMICOLON);
tokenizer_register_token(&_T_EQUALS);
tokenizer_register_token(&_T_LESS);
tokenizer_register_token(&_T_GREATER);
tokenizer_register_token(&_T_COMMA);
}
void tokenizer_init(char *input) {
tokenizer_line = input;
tokenizer_p = tokenizer_next_p = tokenizer_line;
}
char *tokenizer_char_pointer(char *set) {
if (set != NULL) {
tokenizer_p = set;
return NULL;
}
// Skip white space
while (*tokenizer_p && isspace(*tokenizer_p)) {
tokenizer_p++;
}
return tokenizer_p;
}
static bool isvarchar(char c) {
if (c >= 'A' && c <= 'Z') {
return true;
}
if (c == '$') {
return true;
}
if (c >= '0' && c <= '9') {
return true;
}
return false;
}
token _find_registered(void) {
for (size_t i = 0; i < array_size(token_array); i++) {
token_entry *entry = (token_entry *)array_get(token_array, i);
if (entry->name == NULL) continue;
if (strncmp(tokenizer_p, entry->name, strlen(entry->name)) == 0) {
tokenizer_next_p = tokenizer_p + strlen(entry->name);
tokenizer_p = tokenizer_next_p;
return entry->token;
}
}
return T_THE_END;
}
token tokenizer_get_next_token(void) {
if (!*tokenizer_p) {
return T_EOF;
}
// Skip white space
while (*tokenizer_p && isspace(*tokenizer_p)) {
tokenizer_p++;
}
// Check for number
if (isdigit(*tokenizer_p) || *tokenizer_p == '.') {
tokenizer_next_p = tokenizer_p;
size_t l = 0;
while (*tokenizer_next_p &&
(isdigit(*tokenizer_next_p) || *tokenizer_next_p == '.')) {
l++;
tokenizer_next_p++;
}
char number[l + 1];
memset(number, 0, l + 1);
strncpy(number, tokenizer_p, l);
number[l] = '\0';
tokenizer_p = tokenizer_next_p;
float f;
sscanf(number, "%f", &f);
tokenizer_actual_number = f;
return T_NUMBER;
}
// Check for string
if ('"' == *tokenizer_p) {
tokenizer_p++; // skip "
tokenizer_next_p = tokenizer_p;
size_t l = 0;
while (*tokenizer_next_p && '"' != *tokenizer_next_p) {
l++;
tokenizer_next_p++;
}
if (*tokenizer_next_p) {
tokenizer_next_p++; // skip trailing "
}
if (l > 80) {
return T_ERROR;
}
memcpy(tokenizer_actual_string, tokenizer_p, l);
tokenizer_actual_string[l] = '\0';
tokenizer_p = tokenizer_next_p;
return T_STRING;
}
token t = _find_registered();
if (t != T_THE_END) {
return t;
}
// Check for variable
tokenizer_next_p = tokenizer_p;
size_t len = 0;
while (*tokenizer_next_p && isvarchar(*tokenizer_next_p)) {
len++;
tokenizer_next_p++;
}
if (len > tokenizer_variable_length) {
return T_ERROR;
}
if (len > 0) {
memcpy(tokenizer_actual_variable, tokenizer_p, len);
tokenizer_actual_variable[len] = '\0';
tokenizer_p = tokenizer_next_p;
if (tokenizer_actual_variable[len - 1] == '$') {
return T_VARIABLE_STRING;
}
return T_VARIABLE_NUMBER;
}
return T_ERROR;
}
float tokenizer_get_number(void) { return tokenizer_actual_number; }
char *tokenizer_get_string(void) { return tokenizer_actual_string; }
void tokenizer_get_variable_name(char *name) {
strncpy(name, tokenizer_actual_variable, sizeof(tokenizer_actual_variable));
}
void tokenizer_register_token(token_entry *entry) {
array_push(token_array, entry);
}
void tokenizer_free_registered_tokens(void) {
array_destroy(token_array);
}

337
libs/basic/src/variables.c Normal file
View File

@@ -0,0 +1,337 @@
/**
* SPDX-License-Identifier: MIT
* SPDX-FileCopyrightText: 2015-2016 Johan Van den Brande
*
* @file variables.c
*/
#define _GNU_SOURCE
#include <array.h>
#include <dictionary.h>
#include <error.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <variables.h>
typedef union {
float num;
char* string;
} variable_value;
struct variable {
char* name;
variable_type type;
variable_value value;
bool is_array;
size_t nr_dimensions;
size_t dimensions[5];
array* array;
};
dictionary* _dictionary = NULL;
const char* E_INDEX_OUT_OF_BOUNDS = "INDEX OUT OF BOUNDS";
const char* E_VAR_NOT_FOUND = "VAR NOT FOUND";
static void vector_print(size_t* vector, size_t dimensions);
bool variables_init(void) {
_dictionary = dictionary_new();
return _dictionary != NULL;
}
static void cb(char* name, void* value, void* context) {
variable* var = (variable*)value;
if (var->type == variable_type_string) {
if (var->value.string != NULL) free(var->value.string);
}
if (var->is_array) {
array_destroy(var->array);
}
if (var->name != NULL) free(var->name);
free(var);
}
void variables_destroy(void) { dictionary_destroy(_dictionary, cb); }
variable* variable_get(char* name) { return dictionary_get(_dictionary, name); }
char* variable_get_string(char* name) {
variable* var = dictionary_get(_dictionary, name);
if (!var) {
var = variable_set_string(name, "");
}
return var->value.string;
}
float variable_get_numeric(char* name) {
variable* var = dictionary_get(_dictionary, name);
if (!var) {
var = variable_set_numeric(name, 0);
}
return var->value.num;
}
variable* variable_set_string(char* name, char* value) {
variable* var = dictionary_get(_dictionary, name);
if (var == NULL) {
var = (variable*)malloc(sizeof(variable));
var->name = strdup(name);
var->type = variable_type_string;
var->is_array = false;
} else {
if (var->value.string != NULL) {
free(var->value.string);
}
}
var->value.string = strdup(value);
dictionary_put(_dictionary, name, var);
return var;
}
variable* variable_set_numeric(char* name, float value) {
variable* var = dictionary_get(_dictionary, name);
if (var == NULL) {
var = (variable*)malloc(sizeof(variable));
var->name = strdup(name);
var->type = variable_type_numeric;
var->is_array = false;
}
var->value.num = value;
dictionary_put(_dictionary, name, var);
return var;
}
variable_type variable_get_type(char* name) {
variable* var = dictionary_get(_dictionary, name);
return var->type;
}
static size_t calc_size(variable* var) {
size_t size = 1;
for (size_t i = 0; i < var->nr_dimensions; ++i) {
size *= var->dimensions[i];
}
return size;
}
static bool check_in_bounds(variable* var, size_t* vector) {
for (size_t i = 0; i < var->nr_dimensions; i++) {
size_t vector_i = vector[i];
if (vector_i > var->dimensions[i]) {
return false;
}
}
return true;
}
/*
DIM A(2,3)
w h
x y
A(1,1) 0
A(1,2) 1
A(1,3) 2
A(2,1) 3
A(2,2) 4
A(2,3) 5
(x*ySize*zSize + y*zSize + z)
v[0] = x
v[1] = y
v[2] = z
v[0] * d[1] * ... d[n] + v[1] * d[2] ... d[n] + ... + v[n]
*/
static size_t calc_index(variable* var, size_t* vector) {
size_t index = 0;
for (size_t i = 0; i < var->nr_dimensions; ++i) {
// size_t product = vector[i] - 1;
size_t product = vector[i];
for (size_t j = i + 1; j < var->nr_dimensions; ++j) {
product *= var->dimensions[j];
}
index += product;
}
return index;
}
variable* variable_array_init(char* name, variable_type type, size_t dimensions, size_t* vector) {
variable* var = (variable*)malloc(sizeof(variable));
var->name = strdup(name);
var->is_array = true;
var->value.string = NULL;
var->value.num = 0;
var->type = type;
var->nr_dimensions = dimensions;
var->dimensions[0] = vector[0] + 1;
var->dimensions[1] = vector[1] + 1;
var->dimensions[2] = vector[2] + 1;
var->dimensions[3] = vector[3] + 1;
var->dimensions[4] = vector[4] + 1;
var->array = array_new(sizeof(variable_value));
array_alloc(var->array, calc_size(var));
dictionary_put(_dictionary, name, var);
return var;
}
variable* variable_array_set_string(char* name, char* value, size_t* vector) {
variable* var = dictionary_get(_dictionary, name);
if (var == NULL) {
error(E_VAR_NOT_FOUND);
return NULL;
}
if (!check_in_bounds(var, vector)) {
error(E_INDEX_OUT_OF_BOUNDS);
return NULL;
}
size_t index = calc_index(var, vector);
variable_value val;
val.string = strdup(value);
array_set(var->array, index, &val);
return var;
}
char* variable_array_get_string(char* name, size_t* vector) {
variable* var = dictionary_get(_dictionary, name);
if (var == NULL) {
error(E_VAR_NOT_FOUND);
return NULL;
}
if (!check_in_bounds(var, vector)) {
error(E_INDEX_OUT_OF_BOUNDS);
return NULL;
}
size_t index = calc_index(var, vector);
variable_value* val = array_get(var->array, index);
return val->string;
}
variable* variable_array_set_numeric(char* name, float value, size_t* vector) {
variable* var = dictionary_get(_dictionary, name);
if (var == NULL) {
error(E_VAR_NOT_FOUND);
return NULL;
}
if (!check_in_bounds(var, vector)) {
error(E_INDEX_OUT_OF_BOUNDS);
return NULL;
}
// variable_dump(var);
size_t index = calc_index(var, vector);
// printf("index = %ld\n", index);
variable_value val;
val.num = value;
array_set(var->array, index, &val);
// variable_dump(var);
return var;
}
float variable_array_get_numeric(char* name, size_t* vector) {
variable* var = dictionary_get(_dictionary, name);
if (var == NULL) {
error(E_VAR_NOT_FOUND);
return 0;
}
if (!check_in_bounds(var, vector)) {
error(E_INDEX_OUT_OF_BOUNDS);
return 0;
}
size_t index = calc_index(var, vector);
variable_value* val = array_get(var->array, index);
return val->num;
}
struct each_v_ctx {
variables_each_cb cb;
void* context;
};
void each_v(char* name, void* value, void* context) {
struct each_v_ctx* ctx = (struct each_v_ctx*)context;
variable* var = (variable*)value;
ctx->cb(var, ctx->context);
}
void variables_each(variables_each_cb each, void* context) {
struct each_v_ctx ctx = {.cb = each, .context = context};
dictionary_each(_dictionary, each_v, &ctx);
}
static void calc_vector(variable* var, size_t index, size_t* vector) {
size_t product = 1;
for (size_t i = 1; i < var->nr_dimensions; ++i) {
product *= var->dimensions[i];
}
for (int i = 0; i < var->nr_dimensions; ++i) {
vector[i] = index / product;
index %= product;
if ((i + 1) < var->nr_dimensions) {
product /= var->dimensions[i + 1];
}
}
}
static void vector_print(size_t* vector, size_t dimensions) {
for (size_t j = 0; j < dimensions; j++) {
printf("%ld", vector[j]);
if (j < dimensions - 1) {
printf(",");
}
}
}
void variable_dump(variable* var) {
printf(
"-- variable\n"
"\tname:'%s'\n"
"\ttype: %s\n",
var->name, (var->type == variable_type_numeric) ? "number" : "string");
if (var->is_array) {
printf("\tdimensions: %ld\n", var->nr_dimensions);
for (size_t d = 0; d < var->nr_dimensions; d++) {
printf("\tdim %ld size = %ld\n", d, var->dimensions[d]);
}
printf("\tarray size: %ld\n", array_size(var->array));
for (size_t i = 0; i < array_size(var->array); i++) {
size_t vector[5];
calc_vector(var, i, vector);
printf("\t%3ld %s", i, var->name);
vector_print(vector, var->nr_dimensions);
printf(") = ");
variable_value* val = array_get(var->array, i);
if (var->type == variable_type_string) {
printf("%s\n", (val->string) ? val->string : "");
} else {
printf("%f\n", val->num);
}
}
} else {
if (var->type == variable_type_numeric) {
printf("\tvalue: %f\n", var->value.num);
} else {
printf("\tvalue: '%s'\n", var->value.string);
}
}
}