mirror of
https://github.com/avinal/xeus-basic.git
synced 2026-01-09 22:58:36 +05:30
add BASIC interpreter
Signed-off-by: Avinal Kumar <avinal.xlvii@gmail.com>
This commit is contained in:
28
libs/basic/include/basic/arch.h
Normal file
28
libs/basic/include/basic/arch.h
Normal 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_
|
||||
28
libs/basic/include/basic/array.h
Normal file
28
libs/basic/include/basic/array.h
Normal 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_
|
||||
19
libs/basic/include/basic/callback.h
Normal file
19
libs/basic/include/basic/callback.h
Normal 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_
|
||||
25
libs/basic/include/basic/dictionary.h
Normal file
25
libs/basic/include/basic/dictionary.h
Normal 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_
|
||||
14
libs/basic/include/basic/error.h
Normal file
14
libs/basic/include/basic/error.h
Normal 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_
|
||||
13
libs/basic/include/basic/hexdump.h
Normal file
13
libs/basic/include/basic/hexdump.h
Normal 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_
|
||||
18
libs/basic/include/basic/io.h
Normal file
18
libs/basic/include/basic/io.h
Normal 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_
|
||||
13
libs/basic/include/basic/kbhit.h
Normal file
13
libs/basic/include/basic/kbhit.h
Normal 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_
|
||||
42
libs/basic/include/basic/lines.h
Normal file
42
libs/basic/include/basic/lines.h
Normal 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_
|
||||
87
libs/basic/include/basic/parser.h
Normal file
87
libs/basic/include/basic/parser.h
Normal 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_
|
||||
70
libs/basic/include/basic/tokenizer.h
Normal file
70
libs/basic/include/basic/tokenizer.h
Normal 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_
|
||||
41
libs/basic/include/basic/variables.h
Normal file
41
libs/basic/include/basic/variables.h
Normal 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
102
libs/basic/src/arch.c
Normal 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
56
libs/basic/src/array.c
Normal 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
163
libs/basic/src/dictionary.c
Normal 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
37
libs/basic/src/error.c
Normal 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
42
libs/basic/src/hexdump.c
Normal 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
49
libs/basic/src/io.c
Normal 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
30
libs/basic/src/kbhit.c
Normal 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
263
libs/basic/src/lines.c
Normal 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
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
222
libs/basic/src/tokenizer.c
Normal 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
337
libs/basic/src/variables.c
Normal 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);
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user