lli

A small emulated asm like lang
Log | Files | Refs

commit 65a143c4e5ab822dd47961dcb53a096f2e302dd7
parent 3bdadaa9da7500a076605dcc21907ada32491ec0
Author: thing1 <l.standen@posteo.com>
Date:   Wed,  1 Oct 2025 19:10:25 +0100

First major version

Diffstat:
M.gitignore | 1+
MMakefile | 13++++++++++---
Acores/unix_core.c | 29+++++++++++++++++++++++++++++
Acores/unix_core.h | 13+++++++++++++
Aexamples/Makefile | 10++++++++++
Aexamples/cat.ll | 18++++++++++++++++++
Mlli.c | 141+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++--------------
Mlli.h | 33++++++++++++++++++---------------
Mlliasm.c | 173++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-----------------
Dspec.md | 11-----------
Dtest.ll | 1-
Dtest.rom | 0
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.