commit 65a143c4e5ab822dd47961dcb53a096f2e302dd7
parent 3bdadaa9da7500a076605dcc21907ada32491ec0
Author: thing1 <l.standen@posteo.com>
Date: Wed, 1 Oct 2025 19:10:25 +0100
First major version
Diffstat:
12 files changed, 351 insertions(+), 92 deletions(-)
diff --git a/.gitignore b/.gitignore
@@ -1,2 +1,3 @@
lli
lliasm
+*.rom
diff --git a/Makefile b/Makefile
@@ -2,10 +2,17 @@ CFLAGS=-ggdb
all: lli lliasm
-lli: lli.c
- cc lli.c -o lli ${CFLAGS}
+lli: lli.c cores/unix_core.c
+ cc lli.c cores/unix_core.c -o lli ${CFLAGS}
lliasm: lliasm.c
cc lliasm.c -o lliasm ${CFLAGS}
+install: all
+ cp lli lliasm /usr/local/bin
+
+uninstall:
+ rm /usr/local/bin/lli
+ rm /usr/local/bin/lliasm
+
clean:
- rm -rf lli lliasm
+ rm -rf lli lliasm *.rom
diff --git a/cores/unix_core.c b/cores/unix_core.c
@@ -0,0 +1,29 @@
+#include <stdio.h>
+#include <stdlib.h>
+
+/* table of memory
+ * | function | size |
+ * ------------------
+ * | stdin | 1 |
+ * | stdout | 1 |
+ * | stderr | 1 |
+ */
+
+void
+onwrite_unix_memio(char *addr) {
+ if (*(addr + 1)) {
+ putc(*(addr + 1), stdout);
+ *(addr + 1) = 0;
+ }
+ if (*(addr + 2)) {
+ putc(*(addr + 2), stderr);
+ *(addr + 2) = 0;
+ }
+}
+
+void
+onread_unix_memio(const char *addr, char *ptr) {
+ if (ptr == addr) {
+ *ptr = getc(stdin);
+ }
+}
diff --git a/cores/unix_core.h b/cores/unix_core.h
@@ -0,0 +1,13 @@
+#include <stdio.h>
+#include <stdlib.h>
+
+/* table of memory
+ * | function | size |
+ * ------------------
+ * | stdin | 1 |
+ * | stdout | 1 |
+ * | stderr | 1 |
+ */
+
+void onwrite_unix_memio(const char *addr);
+void onread_unix_memio(const char *addr, const char *ptr);
diff --git a/examples/Makefile b/examples/Makefile
@@ -0,0 +1,10 @@
+all: cat
+
+cat: cat.ll
+ lliasm cat.ll cat.rom
+
+run: all
+ lli ./cat.rom
+
+clean:
+ rm -rf *.rom
diff --git a/examples/cat.ll b/examples/cat.ll
@@ -0,0 +1,18 @@
+|0x0 @stdin
+|0x1 @stdout
+|0x2 @stderr
+
+|0x1000
+
+@while
+
+&stdin
+loadb
+
+&stdout
+storeb
+
+&while
+jmp
+
+halt
diff --git a/lli.c b/lli.c
@@ -3,39 +3,130 @@
#include <string.h>
#include "lli.h"
+#include "cores/unix_core.h"
-void
-push(stack *s, value *v) {
- if (((s->sptr + sizeof(value)) - s->arr) > s->cap)
- errormsg("Stack overflow");
-
- s->sptr = v;
- s->sptr += sizeof(value);
-}
+#define mkpop(type) \
+ type pop_##type(stack *s) {\
+ if (s->sptr == s->arr) \
+ errormsg("Stack underflow"); \
+ s->sptr -= sizeof(type); \
+ return *(type *)s->sptr; \
+ }
-value *
-pop(stack *s) {
- if (s->sptr == s->arr)
- errormsg("Stack underflow");
+#define mkpeek(type) \
+ type peek_##type(stack *s) {\
+ if (s->sptr == s->arr) \
+ errormsg("Stack underflow"); \
+ return *(type *)s->sptr; \
+ }
- s->sptr -= sizeof(value);
- return s->sptr;
-}
-value *
-peak(stack *s) {
- if (s->sptr == s->arr)
- errormsg("Stack underflow");
+#define mkpush(type) \
+ type push_##type(stack *s, type *v) { \
+ if (((s->sptr + sizeof(type)) - s->arr) > s->cap) \
+ errormsg("Stack overflow"); \
+ memcpy(s->sptr, v, sizeof(type)); \
+ s->sptr += sizeof(type); \
+ }
- return s->sptr;
-}
+mkpop(uint32_t);
+mkpop(uint16_t);
+mkpop(uint8_t);
+
+mkpeek(uint32_t);
+mkpeek(uint16_t);
+mkpeek(uint8_t);
+
+mkpush(uint32_t);
+mkpush(uint16_t);
+mkpush(uint8_t);
+
+char memory[INT32_MAX];
+char *pc = &memory[0x1000];
+
+void
+lliexec() {
+ stack s = {
+ .cap = 512,
+ .arr = malloc(512),
+ };
+ s.sptr = s.arr;
+
+step:
+ uint8_t opcode = *(uint8_t *)pc, val8;
+ uint16_t val16;
+ uint32_t loc, val32;
-inline int
-depth(stack *s) {
- return (s->sptr - s->arr) / sizeof(value);
+ switch (opcode) {
+
+ case LOADB:
+ case LOADS:
+ case LOADI:
+ loc = pop_uint32_t(&s);
+ onread_unix_memio(&memory[0x0], &memory[loc]);
+ switch (opcode) {
+ case LOADB: push_uint8_t(&s, (void*)&memory[loc]); break;
+ case LOADS: push_uint16_t(&s, (void*)&memory[loc]); break;
+ case LOADI: push_uint32_t(&s, (void*)&memory[loc]); break;
+ }
+ break;
+
+ case STOREB:
+ case STORES:
+ case STOREI:
+ loc = pop_uint32_t(&s);
+ switch (opcode) {
+ case STOREB:
+ val8 = pop_uint8_t(&s);
+ memcpy(&memory[loc], &val8, sizeof(uint8_t));
+ break;
+ case STORES:
+ val16 = pop_uint16_t(&s);
+ memcpy(&memory[loc], &val16, sizeof(uint16_t));
+ break;
+ case STOREI:
+ val32 = pop_uint32_t(&s);
+ memcpy(&memory[loc], &val32, sizeof(uint32_t));
+ break;
+ }
+ onwrite_unix_memio(&memory[0x0]);
+ break;
+
+ case JMP:
+ loc = pop_uint32_t(&s);
+ pc = &memory[loc];
+ goto step;
+
+ case PUSHA:
+ case PUSH:
+ pc++;
+ push_uint32_t(&s, (uint32_t *)pc);
+ pc += sizeof(uint32_t);
+ goto step;
+
+ case HALT: goto end;
+ case DELB: pop_uint8_t(&s); break;
+ case DELS: pop_uint16_t(&s); break;
+ case DELI: pop_uint32_t(&s); break;
+ }
+ pc++;
+ goto step;
+
+end:
+ printf("%s\n", s.arr);
+ free(s.arr);
}
int
-main() {
+main(int argc, char **argv) {
+ FILE *f = fopen(argv[1], "rb");
+ fseek(f, 0, SEEK_END);
+ int len = ftell(f);
+ rewind(f);
+
+ if (len > INT32_MAX) exit(1);
+ fread(memory, 1, INT32_MAX, f);
+ fclose(f);
+ lliexec();
}
diff --git a/lli.h b/lli.h
@@ -7,13 +7,26 @@
typedef enum ttype {
ILIT,
SLIT,
+
LABEL,
PAD,
- DEL,
- DUP,
- STORE,
- LOAD,
+ PUSH,
+ PUSHA,
+
+ DELB,
+ DELS,
+ DELI,
+
+ STOREB,
+ STORES,
+ STOREI,
+
+ LOADB,
+ LOADS,
+ LOADI,
+
JMP,
+ HALT,
} ttype;
typedef struct tval {
@@ -21,19 +34,9 @@ typedef struct tval {
char *val;
} tval;
-typedef enum dtype {
- INT,
- STR,
-} dtype;
-
-typedef struct value {
- bool prot;
- uint8_t val;
-} value;
-
typedef struct stack {
int cap; /* in bytes */
- value *arr, *sptr;
+ uint8_t *arr, *sptr;
} stack;
void
diff --git a/lliasm.c b/lliasm.c
@@ -6,6 +6,8 @@
#include "lli.h"
+#define SAME(s1, s2) (strcmp(s1, s2) == 0)
+
struct dict {
char *label;
int address;
@@ -14,7 +16,8 @@ struct dict {
int label_count = 0;
-#define SAME(s1, s2) (strcmp(s1, s2) == 0)
+char buffer[INT16_MAX] = {0};
+int len = 0;
char *
drainfile(FILE *f) {
@@ -44,68 +47,153 @@ readword(char *in) {
}
tval *
-tokenize(char *word) {
+tokenize(char *word, int *size) {
tval *val = malloc(sizeof(tval));
+ struct dict label;
if (isdigit(*word)) {
val->type = ILIT;
val->val = word;
+ *size += sizeof(int);
return val;
}
else if (*word == '\"') {
val->type = SLIT;
val->val = word + 1;
+ *size += strlen(word + 1);
return val;
}
else if (*word == '@') {
val->type = LABEL;
val->val = word + 1;
+
+ label.label = val->val;
+ label.address = *size;
+
+ for (int i = 0; i < label_count; i++) {
+ if (SAME(label_table[i].label, val->val)) {
+ memcpy(&label_table[i], &label, sizeof(struct dict));
+ return val;
+ }
+ }
+
+ memcpy(&label_table[label_count], &label, sizeof(struct dict));
+ label_count++;
return val;
}
else if (*word == '|') {
val->type = PAD;
val->val = word + 1;
+ *size = strtol(word + 1, NULL, 0);
+ return val;
+ }
+ else if (*word == 'p') {
+ val->type = PUSH;
+ val->val = word + 1;
+ *size += sizeof(int) + sizeof(uint8_t);
+ return val;
+ }
+ else if (*word == '&') {
+ val->type = PUSHA;
+ val->val = word + 1;
+ *size += sizeof(int) + sizeof(uint8_t);
+
+ label.label = val->val;
+ label.address = 0;
+
+ for (int i = 0; i < label_count; i++) {
+ if (SAME(label_table[i].label, val->val))
+ return val;
+ }
+ memcpy(&label_table[label_count], &label, sizeof(struct dict));
+ label_count++;
+
return val;
}
- else if (SAME(word, "del"))
- val->type = DEL;
- else if (SAME(word, "dup"))
- val->type = DUP;
- else if (SAME(word, "load"))
- val->type = LOAD;
- else if (SAME(word, "store"))
- val->type = STORE;
+ else if (SAME(word, "deli"))
+ val->type = DELI;
+ else if (SAME(word, "dels"))
+ val->type = DELS;
+ else if (SAME(word, "delb"))
+ val->type = DELB;
+
+ else if (SAME(word, "loadi"))
+ val->type = LOADI;
+ else if (SAME(word, "loads"))
+ val->type = LOADS;
+ else if (SAME(word, "loadb"))
+ val->type = LOADB;
+
+ else if (SAME(word, "storei"))
+ val->type = STOREI;
+ else if (SAME(word, "stores"))
+ val->type = STORES;
+ else if (SAME(word, "storeb"))
+ val->type = STOREB;
+
else if (SAME(word, "jmp"))
val->type = JMP;
+
+ else if (SAME(word, "halt"))
+ val->type = HALT;
+ else {
+ fprintf(stderr, "Unknown cmd: %s\n", word);
+ exit(1);
+ }
+ *size += sizeof(uint8_t);
val->val = word;
return val;
}
int
-compile(int f, tval *val, int bytesdeep) {
- int ilit, ZERO = 0;
+appendbuf(const void *data, int size) {
+ memcpy(&buffer[len], data, size);
+ len += size;
+ return size;
+}
+
+int
+compile(tval *val, int bytesdeep) {
+ uint32_t ilit, ZERO = 0;
+ uint8_t u8lit;
struct dict label = {val->val, bytesdeep};
switch (val->type) {
case ILIT:
- ilit = atoi(val->val);
- bytesdeep += write(f, &ilit, sizeof(int));
+ ilit = strtol(val->val, NULL, 0);
+ bytesdeep += appendbuf(&ilit, sizeof(int));
break;
case SLIT:
- bytesdeep += write(f, val->val, strlen(val->val));
+ bytesdeep += appendbuf(val->val, strlen(val->val));
break;
case LABEL:
memcpy(&label_table[label_count], &label, sizeof(struct dict));
label_count++;
break;
case PAD:
- while (bytesdeep != atoi(val->val))
- bytesdeep += write(f, &ZERO, 1);
+ while (bytesdeep != strtol(val->val, NULL, 0))
+ bytesdeep += appendbuf(&ZERO, 1);
+ break;
+ case PUSH:
+ u8lit = (uint8_t)val->type;
+ bytesdeep += appendbuf(&u8lit, sizeof(uint8_t));
+ ilit = strtol(val->val, NULL, 0);
+ bytesdeep += appendbuf(&ilit, sizeof(int));
+ break;
+ case PUSHA:
+ u8lit = (uint8_t)val->type;
+ bytesdeep += appendbuf(&u8lit, sizeof(uint8_t));
+
+ for (int i = 0; i < label_count; i++) {
+ if (SAME(label_table[i].label , val->val))
+ ilit = label_table[i].address;
+ }
+ bytesdeep += appendbuf(&ilit, sizeof(int));
break;
default:
- ilit = (int)val->type;
- bytesdeep += write(f, &ilit, sizeof(int));
+ u8lit = (uint8_t)val->type;
+ bytesdeep += appendbuf(&u8lit, sizeof(uint8_t));
break;
}
@@ -115,32 +203,43 @@ compile(int f, tval *val, int bytesdeep) {
int
main(int argc, char **argv) {
FILE *in, *out;
- if (argc < 2)
- in = stdin;
- else {
- in = fopen(argv[1], "r");
- if (!in)
- errormsg("couldn't open file");
- }
-
- out = fopen("test.rom", "wb");
- int o = fileno(out);
- char *input = drainfile(in);
+ if (argc < 2)
+ errormsg("No file given");
+ in = fopen(argv[1], "r");
+ if (!in)
+ errormsg("couldn't open input");
+ if (argc == 3) {
+ out = fopen(argv[2], "wb");
+ if (!out)
+ errormsg("couldn't open output");
+ } else
+ out = fopen("a.rom", "wb");
+
+ int size;
+ char *input = drainfile(in), *swp = strdup(input), *tmp = input;
char *word;
tval *val;
int bytesdeep;
- word = readword(input);
- val = tokenize(word);
- bytesdeep = compile(o, val, 0);
+again:
+ size = 0;
+ word = readword(tmp);
+ val = tokenize(word, &size);
+ if (tmp != input) bytesdeep = compile(val, 0);
while ((word = readword(NULL))) {
- val = tokenize(word);
- bytesdeep = compile(o, val, bytesdeep);
+ val = tokenize(word, &size);
+ if (tmp != input) bytesdeep = compile(val, bytesdeep);
}
- fclose(out);
- close(o);
+ if (tmp != swp) {
+ tmp = swp;
+ goto again;
+ }
+ fwrite(buffer, 1, len, out);
+
+ fclose(out);
free(input);
+ free(swp);
}
diff --git a/spec.md b/spec.md
@@ -1,11 +0,0 @@
-SPEC
-====
-
-| Keyword | Stack pops | Stack pushes | Function |
-|---------|------------|--------------|--------------------------------------------------------|
-| write | ANY | | writes the top value of stack to stdout |
-| del | ANY | | pops the top value and does nothing |
-| copy | INT | ANY | copys the value from val1 deep in the stack to the top |
-| replace | INT, ANY | ANY | swaps the value from val1 deep in the stack with val2 |
-
-- labels start with @
diff --git a/test.ll b/test.ll
@@ -1 +0,0 @@
-|100 @str "hello 10 "world 0
diff --git a/test.rom b/test.rom
Binary files differ.