commit eef899c1eee677950b7d34143cc2fef157beb789
parent f7428b37836cb89392527bf1d28303e33a3be72b
Author: Virgil Dupras <hsoft@hardcoded.net>
Date: Thu, 8 Dec 2022 09:11:19 -0500
New concept: C "header" files
See doc/cc/usage.
Also, begin using the arena allocator in asm/uxntal, along with linked lists,
so that it reserves less space in memory.
Diffstat:
6 files changed, 69 insertions(+), 20 deletions(-)
diff --git a/fs/asm/uxntal.c b/fs/asm/uxntal.c
@@ -1,9 +1,6 @@
/* Source: https://git.sr.ht/~rabbits/uxn
* License: /license/dll-uxn.txt
*/
-// TODO: Compiles, doesn't crash when ran, but doesn't output the right thing.
-// Almost there!
-// (oh, actually it crashes on i386...)
#define TRIM $100
#define LENGTH $10000
@@ -12,6 +9,8 @@ typedef unsigned char Uint8;
typedef char Sint8;
typedef unsigned short Uint16;
+static int _arena = NULL;
+
struct Macro {
// TODO: allow multiple decls per line
char name[$40];
@@ -20,6 +19,7 @@ struct Macro {
};
struct Label {
+ Label *next;
char name[$40];
Uint16 addr;
Uint16 refs;
@@ -36,10 +36,9 @@ struct Program {
Uint8 data[LENGTH];
unsigned int ptr;
unsigned int length;
- Uint16 llen;
Uint16 mlen;
Uint16 rlen;
- Label labels[$400];
+ Label *labels;
Macro macros[$100];
Reference refs[$800];
char scope[$40];
@@ -90,10 +89,12 @@ findmacro(char *name)
static Label *
findlabel(char *name)
{
- int i;
- for(i = 0; i < p.llen; i++)
- if(scmp(p.labels[i].name, name, $40))
- return &p.labels[i];
+ Label *l = p.labels;
+ while (l) {
+ if(scmp(l->name, name, $40))
+ return l;
+ l = l->next;
+ }
return NULL;
}
@@ -177,9 +178,10 @@ makelabel(char *name)
return error("Label name is hex number", name);
if(findopcode(name) || scmp(name, "BRK"0, 4) || !slen(name))
return error("Label name is invalid", name);
- if(p.llen == $400)
- return error("Labels limit exceeded", name);
- l = &p.labels[p.llen++];
+ // TODO: add sizeof()
+ l = alloc_allot($48, _arena);
+ llappend(l, &p.labels);
+ l->next = NULL;
l->addr = p.ptr;
l->refs = 0;
scpy(name, l->name, $40);
@@ -451,21 +453,28 @@ assemble(int hdl)
static void
review()
{
- int i;
- for(i = 0; i < p.llen; i++)
- if(p.labels[i].name[0] >= 'A' && p.labels[i].name[0] <= 'Z')
- continue; /* Ignore capitalized labels(devices) */
- else if(!p.labels[i].refs)
- fprintf(p.labels[i].name, "-- Unused label: %z\n", ConsoleOut());
+ Label *l = p.labels;
+ while (l) {
+ if (!l->refs) {
+ if(l->name[0] < 'A' || l->name[0] > 'Z')
+ fprintf(l->name, "-- Unused label: %z\n", ConsoleOut());
+ }
+ l = l->next;
+ }
fprintf(
- p.mlen, p.llen, p.length-TRIM,
+ p.mlen, llcnt(p.labels), p.length-TRIM,
"Assembled %d bytes, %d labels, %d macros.\n", ConsoleOut());
}
int
uxntal(int srchdl)
{
- p.llen = (p.mlen = (p.rlen = (p.length = (p.ptr = 0))));
+ if (_arena == NULL) {
+ _arena = arena_new();
+ }
+ arena_reset(_arena);
+ p.mlen = (p.rlen = (p.length = (p.ptr = 0)));
+ p.labels = NULL;
if(!assemble(srchdl))
return !error("Assembly", "Failed to assemble rom."0);
if(p.length <= TRIM)
diff --git a/fs/asm/uxntal.fs b/fs/asm/uxntal.fs
@@ -1,2 +1,3 @@
?f<< /comp/c/lib.fs
+?f<< /lib/arena.h
cc<< /asm/uxntal.c
diff --git a/fs/comp/c/lib.fs b/fs/comp/c/lib.fs
@@ -20,6 +20,9 @@
:c int ConsoleOut();
:c unsigned char stdin();
:c void stdout(unsigned char c);
+:c int llend(int ll);
+:c void llappend(int elem, int ll);
+:c int llcnt(int ll);
: strlen c@ ;
:c unsigned int strlen(char *str);
diff --git a/fs/doc/cc/usage.txt b/fs/doc/cc/usage.txt
@@ -170,3 +170,19 @@ just like the signature.
Macros are not exposed to Forth as words and are cleared at the beginning of the
"cc<<" call.
+
+## Header files
+
+Dusk OS has some ".h" files littered around which have the same name as a
+corresponding Forth source file. These files are not C source files, they're
+Forth source files, but they serve the purpose of a traditional ".h" file in the
+outside world, that is, to provide C with an interface.
+
+These files can't be simple C source files because providing a C interface to a
+Forth library often involves more than simple function prototypes or structure
+definitions. It often involves mangling of the arguments, which have to be done
+in wrapper words written in Forth.
+
+Therefore, if you want to use a Forth library in C that has a corresponding ".h"
+file, you'll want to load that ".h" file with "?f<<" before you compile your C
+code.
diff --git a/fs/lib/alloc.h b/fs/lib/alloc.h
@@ -0,0 +1,8 @@
+\ Allocator
+
+?f<< /lib/alloc.fs
+?f<< /comp/c/cc.fs
+
+\ We don't expose the Allocator struct. We don't need to.
+: alloc_allot Allocator :allot ;
+:c int alloc_allot(unsigned int n, int self);
diff --git a/fs/lib/arena.h b/fs/lib/arena.h
@@ -0,0 +1,12 @@
+\ Arena
+
+?f<< /lib/arena.fs
+?f<< /lib/alloc.h
+
+\ We don't expose the Arena struct. We don't need to.
+: arena_new Arena :new ;
+:c int arena_new();
+: arena_reset Arena :reset ;
+:c void arena_reset(int self);
+: arena_reserve Arena :reserve ;
+:c void arena_reserve(int self);