summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorpeter <peter@pmikkelsen.com>2026-08-30 20:52:43 +0000
committerpeter <peter@pmikkelsen.com>2026-08-30 20:52:43 +0000
commit729964bea692f9683860978b89848784a7fc2f46 (patch)
treeba5b37a61206142fce18214c7af341ac837a7923 /src
parent04827577ea502a9f0edc69e00e008751c8119cbc (diff)
Still a lot to be done, but I'm going to bed.
Two remaining big issues: * aplwc (the parameter passed "everywhere") - should it move or not? * values returned from the public API should not move. FossilOrigin-Name: 31ab3154b8f3d5ac167218496e9e204324bf0ac9d36b7bada8fe2a6c8f93d51c
Diffstat (limited to 'src')
-rw-r--r--src/bin/main.c23
-rw-r--r--src/include/aplwc.h7
-rw-r--r--src/lib/aplwc_internal.h23
-rw-r--r--src/lib/eval.c1
-rw-r--r--src/lib/main.c82
-rw-r--r--src/lib/memory.c241
-rw-r--r--src/lib/module.c17
-rw-r--r--src/lib/syntax.c22
8 files changed, 325 insertions, 91 deletions
diff --git a/src/bin/main.c b/src/bin/main.c
index fb75a9d..99149f6 100644
--- a/src/bin/main.c
+++ b/src/bin/main.c
@@ -4,15 +4,21 @@
#include <errno.h>
#include "aplwc_repl.h"
-#define MEMSIZE 20000
+static void *my_alloc(size_t min, size_t max, size_t *actual)
+{
+ UNUSED_PARAMETER(max);
+
+ *actual = min;
+ return malloc(min);
+}
int
main(int argc, char *argv[])
{
+ struct aplwc_fns fns;
struct aplwc *aplwc;
struct aplwc_line *line;
struct aplwc_value *value;
- uint8_t *data;
char *input, *src;
int ret, exit_code, line_number;
size_t input_size, src_size, i;
@@ -28,6 +34,9 @@ main(int argc, char *argv[])
exit_code = 0;
line_number = 0;
+ memset(&fns, 0, sizeof(fns));
+ fns.alloc = my_alloc;
+
while((opt = getopt(argc, argv, "x")) != -1){
switch(opt){
case 'x':
@@ -52,16 +61,9 @@ usage:
else
goto usage;
- data = malloc(MEMSIZE);
- if(data == NULL){
- fprintf(stderr, "Couldn't allocate memory\n");
- return 1;
- }
-
- ret = aplwc_new(&aplwc, data, MEMSIZE);
+ ret = aplwc_new(&aplwc, fns);
if(ret){
fprintf(stderr, "Couldn't create new aplwc instance: %s\n", aplwc_errstr_rc(ret));
- free(data);
return 1;
}
@@ -152,6 +154,5 @@ exit:
aplwc_free_value(value);
aplwc_destroy(aplwc);
- free(data);
return exit_code;
}
diff --git a/src/include/aplwc.h b/src/include/aplwc.h
index ad640e4..843fe42 100644
--- a/src/include/aplwc.h
+++ b/src/include/aplwc.h
@@ -18,7 +18,12 @@ struct aplwc;
struct aplwc_line;
struct aplwc_value;
-enum aplwc_rc aplwc_new(struct aplwc **, uint8_t *, size_t);
+struct aplwc_fns {
+ void *(*alloc)(size_t, size_t, size_t *);
+ void (*dealloc)(void *);
+};
+
+enum aplwc_rc aplwc_new(struct aplwc **, struct aplwc_fns);
void aplwc_destroy(struct aplwc *);
const char *aplwc_errstr_rc(enum aplwc_rc);
const char *aplwc_errstr(struct aplwc *);
diff --git a/src/lib/aplwc_internal.h b/src/lib/aplwc_internal.h
index 23b26f9..a7b7030 100644
--- a/src/lib/aplwc_internal.h
+++ b/src/lib/aplwc_internal.h
@@ -9,13 +9,21 @@
#include <string.h>
struct aplwc {
+ struct aplwc_fns fns;
enum aplwc_rc last_error;
struct aplwc_module *modules;
/* Memory management */
uint8_t *data;
+ uint8_t *unaligned_data;
size_t size;
- size_t offset;
+ struct memory_ptr_frame *memptrs;
+};
+
+struct memory_ptr_frame {
+ struct memory_ptr_frame *link;
+ void ***ptrs;
+ size_t count;
};
struct aplwc_line {
@@ -79,8 +87,8 @@ struct aplwc_module {
struct aplwc_value *eval_line(struct aplwc_line *);
/* memory.c */
-void memory_init(struct aplwc *, uint8_t *, size_t);
-struct aplwc *memory_alloc_aplwc(struct aplwc *);
+void memory_init(struct aplwc *);
+void memory_destroy(struct aplwc *);
struct aplwc_line *memory_alloc_aplwc_line(struct aplwc *);
struct string *memory_alloc_string(struct aplwc *, size_t);
struct token_list *memory_alloc_token_list(struct aplwc *, size_t);
@@ -88,6 +96,15 @@ struct aplwc_value *memory_alloc_aplwc_value(struct aplwc *);
struct aplwc_module *memory_alloc_aplwc_module(struct aplwc *);
struct module_imports *memory_alloc_module_imports(struct aplwc *, size_t);
void memory_free_root(struct aplwc *, void *);
+void memptrs_add(struct aplwc *, struct memory_ptr_frame *, void ***, size_t);
+void memptrs_remove(struct aplwc *, struct memory_ptr_frame *);
+
+#define MEMPTRS(aplwc, n) \
+ void **memptrs[n]; \
+ struct memory_ptr_frame memptrs_frame; \
+ memptrs_add(aplwc, &memptrs_frame, memptrs, n);
+#define MEMPTR(n, ptr) memptrs[n] = (void **)&ptr
+#define MEMPTRS_EXIT(aplwc) memptrs_remove(aplwc, &memptrs_frame)
/* string.c */
struct string *chars_to_string(struct aplwc *, const char *, int len);
diff --git a/src/lib/eval.c b/src/lib/eval.c
index 21fb223..50c3cda 100644
--- a/src/lib/eval.c
+++ b/src/lib/eval.c
@@ -14,5 +14,6 @@ eval_line(struct aplwc_line *line)
value->aplwc = aplwc;
value->tag = VALUE_NULL;
}
+
return value;
}
diff --git a/src/lib/main.c b/src/lib/main.c
index 81cd6bb..03c31a5 100644
--- a/src/lib/main.c
+++ b/src/lib/main.c
@@ -2,24 +2,32 @@
#include "boot.h"
enum aplwc_rc
-aplwc_new(struct aplwc **p, uint8_t *data, size_t size)
+aplwc_new(struct aplwc **p, struct aplwc_fns fns)
{
- struct aplwc tmp_aplwc;
-
- memory_init(&tmp_aplwc, data, size);
-
- *p = memory_alloc_aplwc(&tmp_aplwc);
- if(*p == NULL)
- return tmp_aplwc.last_error;
- memcpy(*p, &tmp_aplwc, sizeof(tmp_aplwc));
-
- return aplwc_load_module(*p, "Boot", (const char *)boot_src, boot_src_len);
+ struct aplwc *aplwc;
+ size_t size;
+
+ if(fns.alloc == NULL)
+ return APLWC_OUT_OF_MEMORY;
+ aplwc = fns.alloc(sizeof(*aplwc), sizeof(*aplwc), &size);
+ if(aplwc == NULL)
+ return APLWC_OUT_OF_MEMORY;
+ *p = aplwc;
+
+ aplwc->fns = fns;
+ memory_init(aplwc);
+ return aplwc_load_module(aplwc, "Boot", (const char *)boot_src, boot_src_len);
}
void
aplwc_destroy(struct aplwc *p)
{
- UNUSED_PARAMETER(p);
+ if(p == NULL)
+ return;
+
+ memory_destroy(p);
+ if(p->fns.dealloc)
+ p->fns.dealloc(p);
}
const char *
@@ -70,26 +78,30 @@ aplwc_read(struct aplwc *aplwc, const char *line)
struct token_list *tokens;
struct aplwc_line *ret;
- text = chars_to_string(aplwc, line, -1);
- if(text == NULL)
- return NULL;
+ MEMPTRS(aplwc, 2);
+
+ ret = NULL;
- tokens = scan_string(aplwc, text, 1);
- if(tokens == NULL)
- return NULL;
+ if((text = chars_to_string(aplwc, line, -1)) == NULL)
+ goto end;
+ MEMPTR(0, text);
- aplwc->last_error = check_tokens(tokens);
- if(aplwc->last_error != APLWC_OK)
- return NULL;
+ if((tokens = scan_string(aplwc, text, 1)) == NULL)
+ goto end;
+ MEMPTR(1, tokens);
- ret = memory_alloc_aplwc_line(aplwc);
- if(ret == NULL)
- return NULL;
+ if((aplwc->last_error = check_tokens(tokens)) != APLWC_OK)
+ goto end;
+
+ if((ret = memory_alloc_aplwc_line(aplwc)) == NULL)
+ goto end;
ret->aplwc = aplwc;
ret->text = text;
ret->tokens = tokens;
+end:
+ MEMPTRS_EXIT(aplwc);
return ret;
}
@@ -131,16 +143,22 @@ aplwc_load_module(struct aplwc *aplwc, const char *name, const char *src, int sr
struct string *text, *namestr;
struct token_list *tokens;
+ MEMPTRS(aplwc, 3);
+
if((namestr = chars_to_string(aplwc, name, -1)) == NULL)
- goto error;
+ goto end;
+ MEMPTR(0, namestr);
+
if((text = chars_to_string(aplwc, src, srclen)) == NULL)
- goto error;
+ goto end;
+ MEMPTR(1, text);
+
if((tokens = scan_string(aplwc, text, 0)) == NULL)
- goto error;
- if(load_module(aplwc, namestr, tokens) != APLWC_OK){
-error:
- return aplwc_last_error(aplwc);
- }
+ goto end;
+ MEMPTR(2, tokens);
- return APLWC_OK;
+ aplwc->last_error = load_module(aplwc, namestr, tokens);
+end:
+ MEMPTRS_EXIT(aplwc);
+ return aplwc_last_error(aplwc);
}
diff --git a/src/lib/memory.c b/src/lib/memory.c
index 94f903c..8a91d2d 100644
--- a/src/lib/memory.c
+++ b/src/lib/memory.c
@@ -1,41 +1,201 @@
#include "aplwc_internal.h"
+#define ALIGNMENT 8
+#define HEADER_SIZE (sizeof(struct chunk) + (sizeof(struct chunk) % ALIGNMENT))
+
+enum chunk_tag {
+ CHUNK_TAG_FREE,
+ CHUNK_TAG_APLWC_LINE,
+ CHUNK_TAG_STRING,
+ CHUNK_TAG_TOKEN_LIST,
+ CHUNK_TAG_APLWC_VALUE,
+ CHUNK_TAG_APLWC_MODULE
+};
+
+struct chunk {
+ struct chunk *next;
+ size_t size;
+ enum chunk_tag tag;
+ uint8_t *data;
+};
+
void
-memory_init(struct aplwc *aplwc, uint8_t *data , size_t size)
+memory_init(struct aplwc *aplwc)
{
- aplwc->data = data;
- aplwc->size = size;
- aplwc->offset = 0;
+ aplwc->data = NULL;
+ aplwc->unaligned_data = NULL;
+ aplwc->size = 0;
+ aplwc->memptrs = NULL;
}
-static void *
-alloc(struct aplwc *aplwc, size_t size, size_t align)
+void
+memory_destroy(struct aplwc *aplwc)
{
- uintptr_t ptr;
- size_t alloc_size, adjust;
- void *p;
+ if(aplwc->fns.dealloc)
+ aplwc->fns.dealloc(aplwc->unaligned_data);
+}
- ptr = ((uintptr_t)aplwc->data) + aplwc->offset;
- alloc_size = size;
+static void
+fixrefs(struct aplwc *aplwc, uint8_t *new, uint8_t *old)
+{
+#define FIX(ptr) do{ \
+ if(ptr){ \
+ (ptr) = (void*)(((uint8_t*)(ptr))+add); \
+ (ptr) = (void*)(((uint8_t*)(ptr))-sub); \
+ } \
+}while(0)
- if(NEVER(align == 0))
- return NULL;
- adjust = ptr % align;
+#define FIX_DATA(type, ptr) FIX(((type *)c->data)->ptr)
- if(adjust)
- alloc_size += align - adjust;
+ struct chunk *c;
+ struct memory_ptr_frame *frame;
+ size_t add, sub, i;
- if((aplwc->size - aplwc->offset) >= alloc_size){
- p = aplwc->data+aplwc->offset+alloc_size-size;
- assert((((uintptr_t)p) % align) == 0);
- aplwc->offset += alloc_size;
- memset(p, 0, size);
+ if(new > old){
+ add = new-old;
+ sub = 0;
}else{
- p = NULL;
- aplwc->last_error = APLWC_OUT_OF_MEMORY;
+ add = 0;
+ sub = old-new;
}
- return p;
+ for(c = (struct chunk *)new; c; c = c->next){
+ FIX(c->next);
+ FIX(c->data);
+
+ switch(c->tag){
+ case CHUNK_TAG_APLWC_LINE:
+ FIX_DATA(struct aplwc_line, text);
+ FIX_DATA(struct aplwc_line, tokens);
+ break;
+ case CHUNK_TAG_STRING:
+ break;
+ case CHUNK_TAG_TOKEN_LIST:
+ FIX_DATA(struct token_list, text);
+ break;
+ case CHUNK_TAG_APLWC_VALUE:
+ break;
+ case CHUNK_TAG_APLWC_MODULE:
+ FIX_DATA(struct aplwc_module, name);
+ FIX_DATA(struct aplwc_module, tokens);
+ FIX_DATA(struct aplwc_module, link);
+ break;
+ case CHUNK_TAG_FREE:
+ break;
+ }
+ }
+
+ for(frame = aplwc->memptrs; frame; frame = frame->link)
+ for(i = 0; i < frame->count; i++)
+ if(frame->ptrs[i])
+ FIX(*frame->ptrs[i]);
+
+#undef FIX
+#undef FIX_DATA
+}
+
+static enum aplwc_rc
+grow(struct aplwc *aplwc, size_t extra)
+{
+ uint8_t *unaligned_data, *aligned_data;
+ size_t unaligned_newsize, aligned_newsize, adjust;
+ struct chunk **free;
+
+ if(aplwc->fns.alloc == NULL)
+ goto error;
+
+ unaligned_data = aplwc->fns.alloc(aplwc->size + extra + HEADER_SIZE + 2*ALIGNMENT, 0, &unaligned_newsize);
+ if(unaligned_data == NULL)
+ goto error;
+
+ adjust = ((uintptr_t)unaligned_data) % ALIGNMENT;
+ if(adjust)
+ adjust = ALIGNMENT - adjust;
+ aligned_newsize = unaligned_newsize - adjust;
+ aligned_data = unaligned_data + adjust;
+
+ aligned_newsize -= aligned_newsize % ALIGNMENT;
+
+ assert(aligned_newsize >= (aplwc->size + extra));
+
+ if(aplwc->data){
+ memmove(aligned_data, aplwc->data, aplwc->size);
+ fixrefs(aplwc, aligned_data, aplwc->data);
+ if(aplwc->fns.dealloc)
+ aplwc->fns.dealloc(aplwc->unaligned_data);
+ for(free = (struct chunk **)&aligned_data; (*free); free = &(*free)->next)
+ assert((*free)->tag != CHUNK_TAG_FREE);
+ }else
+ free = (struct chunk **)&aligned_data;
+
+
+ (*free) = (struct chunk *)(aligned_data + aplwc->size);
+ (*free)->tag = CHUNK_TAG_FREE;
+ (*free)->data = NULL;
+ (*free)->size = aligned_newsize - aplwc->size;
+ (*free)->next = NULL;
+
+ aplwc->unaligned_data = unaligned_data;
+ aplwc->data = aligned_data;
+ aplwc->size = aligned_newsize;
+ return 1;
+
+error:
+ aplwc->last_error = APLWC_OUT_OF_MEMORY;
+ return 0;
+}
+
+static struct chunk *
+find_free(struct aplwc *aplwc, size_t min)
+{
+ struct chunk *c;
+
+ min += HEADER_SIZE;
+
+ if(aplwc->data == NULL)
+ return NULL;
+
+ for(c = (struct chunk *)aplwc->data; c; c = c->next){
+ if((c->tag == CHUNK_TAG_FREE) && (c->size >= min))
+ break;
+ }
+
+ return c;
+}
+
+static void *
+alloc(struct aplwc *aplwc, size_t size, enum chunk_tag tag)
+{
+ struct chunk *free;
+ struct chunk *new;
+
+retry:
+ free = find_free(aplwc, size);
+ if(!free){
+ if(grow(aplwc, size))
+ goto retry;
+ else
+ return NULL;
+ }
+
+ assert(free->data == NULL);
+
+ new = free;
+
+ if(free->size > (size + 2*HEADER_SIZE)){
+ free = (struct chunk *)(((uint8_t*)free) + HEADER_SIZE + size);
+ free->tag = CHUNK_TAG_FREE;
+ free->size = new->size - (HEADER_SIZE + size);
+ free->data = NULL;
+ }
+
+ new->tag = tag;
+ new->size = sizeof(struct chunk) + size;
+ new->data = ((uint8_t*)new) + sizeof(struct chunk);
+
+ new->data += ((uintptr_t)new->data) % ALIGNMENT;
+
+ return new->data;
}
void
@@ -47,13 +207,25 @@ memory_free_root(struct aplwc *aplwc, void *p)
UNUSED_PARAMETER(aplwc);
}
-struct aplwc *
-memory_alloc_aplwc(struct aplwc *aplwc)
+void
+memptrs_add(struct aplwc *aplwc, struct memory_ptr_frame *frame, void ***ptrs, size_t count)
{
- struct aplwc *p;
+ size_t i;
- p = alloc(aplwc, sizeof(struct aplwc), alignof(struct aplwc));
- return p;
+ frame->ptrs = ptrs;
+ frame->link = aplwc->memptrs;
+ frame->count = count;
+ aplwc->memptrs = frame;
+
+ for(i = 0; i < count; i++)
+ frame->ptrs[i] = NULL;
+}
+
+void
+memptrs_remove(struct aplwc *aplwc, struct memory_ptr_frame *frame)
+{
+ assert(aplwc->memptrs == frame);
+ aplwc->memptrs = frame->link;
}
struct aplwc_line *
@@ -61,7 +233,7 @@ memory_alloc_aplwc_line(struct aplwc *aplwc)
{
struct aplwc_line *p;
- p = alloc(aplwc, sizeof(struct aplwc_line), alignof(struct aplwc_line));
+ p = alloc(aplwc, sizeof(struct aplwc_line), CHUNK_TAG_APLWC_LINE);
return p;
}
@@ -70,7 +242,8 @@ memory_alloc_string(struct aplwc *aplwc, size_t bytes)
{
struct string *p;
- p = alloc(aplwc, sizeof(struct string) + bytes, alignof(struct string));
+ p = alloc(aplwc, sizeof(struct string) + bytes, CHUNK_TAG_STRING);
+
return p;
}
@@ -79,7 +252,7 @@ memory_alloc_token_list(struct aplwc *aplwc, size_t tokens)
{
struct token_list *p;
- p = alloc(aplwc, sizeof(struct token_list) + (tokens * sizeof(struct token)), alignof(struct token_list));
+ p = alloc(aplwc, sizeof(struct token_list) + (tokens * sizeof(struct token)), CHUNK_TAG_TOKEN_LIST);
return p;
}
@@ -88,7 +261,7 @@ memory_alloc_aplwc_value(struct aplwc *aplwc)
{
struct aplwc_value *p;
- p = alloc(aplwc, sizeof(struct aplwc_value), alignof(struct aplwc_value));
+ p = alloc(aplwc, sizeof(struct aplwc_value), CHUNK_TAG_APLWC_VALUE);
return p;
}
@@ -97,6 +270,6 @@ memory_alloc_aplwc_module(struct aplwc *aplwc)
{
struct aplwc_module *p;
- p = alloc(aplwc, sizeof(struct aplwc_module), alignof(struct aplwc_module));
+ p = alloc(aplwc, sizeof(struct aplwc_module), CHUNK_TAG_APLWC_MODULE);
return p;
}
diff --git a/src/lib/module.c b/src/lib/module.c
index f559f00..3bca396 100644
--- a/src/lib/module.c
+++ b/src/lib/module.c
@@ -58,9 +58,17 @@ load_module(struct aplwc *aplwc, struct string *name, struct token_list *tokens)
enum aplwc_rc rc;
struct aplwc_module *module;
+ MEMPTRS(aplwc, 2);
+
+ MEMPTR(0, name);
+ MEMPTR(1, tokens);
+
module = memory_alloc_aplwc_module(aplwc);
- if(module == NULL)
- return aplwc->last_error;
+ if(module == NULL){
+ rc = aplwc_last_error(aplwc);
+ goto end;
+ }
+
module->aplwc = aplwc;
module->name = name;
module->tokens = tokens;
@@ -70,8 +78,11 @@ load_module(struct aplwc *aplwc, struct string *name, struct token_list *tokens)
if(rc == APLWC_OK){
module->link = aplwc->modules;
aplwc->modules = module;
- }
+ }else
+ aplwc->last_error = rc;
+end:
+ MEMPTRS_EXIT(aplwc);
return rc;
}
diff --git a/src/lib/syntax.c b/src/lib/syntax.c
index 75d6c14..ae52343 100644
--- a/src/lib/syntax.c
+++ b/src/lib/syntax.c
@@ -240,15 +240,17 @@ scan_string(struct aplwc *aplwc, struct string *text, int oneline)
struct token_list *tokens;
size_t n, i;
+ MEMPTRS(aplwc, 1);
+ MEMPTR(0, text);
+
+ tokens = NULL;
rc = check(text, &n);
- if(rc != APLWC_OK){
- aplwc->last_error = rc;
- return NULL;
- }
+ if(rc != APLWC_OK)
+ goto end;
tokens = memory_alloc_token_list(aplwc, n);
if(tokens == NULL)
- return NULL;
+ goto end;
tokens->text = text;
tokens->length = n;
scan(text, tokens);
@@ -258,11 +260,17 @@ scan_string(struct aplwc *aplwc, struct string *text, int oneline)
continue;
for(i++; i < n; i++){
- if(tokens->tokens[i].tag != TOKEN_TAG_NEWLINE)
- return NULL;
+ if(tokens->tokens[i].tag != TOKEN_TAG_NEWLINE){
+ rc = APLWC_INVALID_SYNTAX;
+ tokens = NULL;
+ goto end;
+ }
}
}
+end:
+ aplwc->last_error = rc;
+ MEMPTRS_EXIT(aplwc);
return tokens;
}