lli

A small emulated asm like lang
Log | Files | Refs

commit 49ecfefebf572d3c298ca2d0a6ed3916ee5b0cb7
parent 47e635186720d4bcf9e6d9577659b2f509facc53
Author: thing1 <l.standen@posteo.com>
Date:   Sat,  4 Oct 2025 16:53:58 +0100

added various features, mainly branching code

Diffstat:
Mexamples/Makefile | 4+++-
Mexamples/callstack.ll | 2+-
Aexamples/conditional.ll | 7+++++++
Mexamples/print.ll | 29++++++++++++++++++++---------
Mlli.c | 89+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++------------------
Mlli.h | 77+++++++++++++++++++++++++++++++++++++++++++++--------------------------------
Mlliasm.c | 112+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++--------------
7 files changed, 237 insertions(+), 83 deletions(-)

diff --git a/examples/Makefile b/examples/Makefile @@ -1,4 +1,4 @@ -all: cat loadprog callstack print +all: cat loadprog callstack print conditional cat: cat.ll lliasm cat.ll cat.rom @@ -8,6 +8,8 @@ callstack: callstack.ll lliasm callstack.ll callstack.rom print: print.ll lliasm print.ll print.rom +conditional: conditional.ll + lliasm conditional.ll conditional.rom clean: rm -rf *.rom diff --git a/examples/callstack.ll b/examples/callstack.ll @@ -1,5 +1,5 @@ |0x0 @stdin |0x1 @stdout |0x2 @stderr -|0x20 @str "hello 0 +|0x20 @str "hello b0 |0x100 @tester &str loadb &stdout storeb diff --git a/examples/conditional.ll b/examples/conditional.ll @@ -0,0 +1,7 @@ +|0x0 @stdin |0x1 @stdout |0x2 @stderr + +|0x1000 @main +&stdin loadb b2i #65 equ +&stdin loadb delb +&main jnz +halt diff --git a/examples/print.ll b/examples/print.ll @@ -1,12 +1,23 @@ -|0x0 @stdin |0x1 @stdout |0x2 @stderr -|0x10 @str "hello 0 +|0x0 @stdin |0x1 @stdout |0x2 @stderr (define stdin, stdout and error) +|0x10 @str "hello b32 "world b10 b0 (define the string to print, the b32, b10, and b0 are ascii for ' ', '\n' and '\0') -|0x100 @print -dupi -loadb &stdout storeb -p1 add -&print jmp +|0x100 @print (define a print function) +dupi (duplicate the input address, so it stays on the stack for the next call) +loadb dupb b2i #0 equ (load the byte at the input address, duplicate it, check if its '\0') +&end jnz (jump if it was 0) +&stdout storeb (print the char) +#1 add (add 1 to the address) +&print jmp (repeat) + +@end +delb (stack cleanup) +deli +ret (return) |0x1000 -&str &print call -halt +&str &print call (call the function print with the address of str as an arg) +&str &print call (call the function print with the address of str as an arg) +halt (end the program) + + + (This program works by having a 0 at the end of a string, it prints the string 1 char at a time, and if it finds a 0 it stops) diff --git a/lli.c b/lli.c @@ -123,13 +123,27 @@ step: loc = pop_uint32_t(&s); pc = &memory[loc]; goto step; - + case JNZ: + loc = pop_uint32_t(&s); + val8 = pop_uint8_t(&s); + if (!val8) break; + pc = &memory[loc]; + goto step; case CALL: loc = pop_uint32_t(&s); val32 = (pc - &memory[0]) + 1; push_uint32_t(&cs, &val32); pc = &memory[loc]; goto step; + case CALLNZ: + loc = pop_uint32_t(&s); + val8 = pop_uint8_t(&s); + if (!val8) break; + val32 = (pc - &memory[0]) + 1; + push_uint32_t(&cs, &val32); + pc = &memory[loc]; + goto step; + case RET: pc = &memory[pop_uint32_t(&cs)]; goto step; @@ -142,32 +156,67 @@ step: goto step; case ADD: - operand2 = pop_uint32_t(&s); - operand1 = pop_uint32_t(&s); - val32 = operand1 + operand2; - push_uint32_t(&s, &val32); - break; - case SUB: - operand2 = pop_uint32_t(&s); - operand1 = pop_uint32_t(&s); - val32 = operand1 - operand2; - push_uint32_t(&s, &val32); - break; - case DIV: + case MUL: + case EQU: + case NEQ: operand2 = pop_uint32_t(&s); operand1 = pop_uint32_t(&s); - val32 = operand1 / operand2; - push_uint32_t(&s, &val32); + switch (opcode) { + case ADD: + val32 = operand1 + operand2; + push_uint32_t(&s, &val32); + break; + case SUB: + val32 = operand1 - operand2; + push_uint32_t(&s, &val32); + break; + case DIV: + val32 = operand1 / operand2; + push_uint32_t(&s, &val32); + break; + case MUL: + val32 = operand1 * operand2; + push_uint32_t(&s, &val32); + break; + + case EQU: + val8 = (operand1 == operand2); + push_uint8_t(&s, &val8); + break; + case NEQ: + val8 = (operand1 != operand2); + push_uint8_t(&s, &val8); + break; + } break; - case MUL: - operand2 = pop_uint32_t(&s); - operand1 = pop_uint32_t(&s); - val32 = operand1 * operand2; - push_uint32_t(&s, &val32); + case B2S: + case B2I: + val8 = pop_uint8_t(&s); + switch (opcode) { + case B2S: val16 = val8; push_uint16_t(&s, &val16); break; + case B2I: val32 = val8; push_uint32_t(&s, &val32); break; + } + break; + case S2B: + case S2I: + val16 = pop_uint16_t(&s); + switch (opcode) { + case S2B: val8 = (uint8_t)val16; push_uint8_t(&s, &val8); break; + case S2I: val32 = val16; push_uint32_t(&s, &val32); break; + } + break; + case I2B: + case I2S: + val32 = pop_uint32_t(&s); + switch (opcode) { + case I2B: val8 = (uint8_t)val32; push_uint8_t(&s, &val8); break; + case I2S: val16 = (uint16_t)val32; push_uint16_t(&s, &val16); break; + } break; + case HALT: goto end; case DELB: pop_uint8_t(&s); break; diff --git a/lli.h b/lli.h @@ -5,41 +5,54 @@ #include <stdint.h> typedef enum ttype { - ILIT, + BLIT, SLIT, - + ILIT, + STRLIT, LABEL, PAD, - PUSH, - PUSHA, - - DELB, - DELS, - DELI, - - STOREB, - STORES, - STOREI, - - DUPB, - DUPS, - DUPI, - - LOADB, - LOADS, - LOADI, - - ADD, - SUB, - DIV, - MUL, - - JMP, - JMPZ, - CALL, - CALLZ, - RET, - HALT, + + PUSH = 10, + PUSHA = 11, + + DELB = 12, + DELS = 13, + DELI = 14, + + STOREB = 15, + STORES = 16, + STOREI = 17, + + DUPB = 18, + DUPS = 19, + DUPI = 20, + + LOADB = 21, + LOADS = 22, + LOADI = 23, + + ADD = 24, + SUB = 25, + DIV = 26, + MUL = 27, + + JMP = 28, + JNZ = 29, + CALL = 30, + CALLNZ = 31, + RET = 32, + + B2S = 33, + B2I = 34, + S2B = 35, + S2I = 36, + I2B = 37, + I2S = 38, + + EQU = 39, + NEQ = 40, + + HALT = 41, } ttype; typedef struct tval { diff --git a/lliasm.c b/lliasm.c @@ -35,6 +35,24 @@ drainfile(FILE *f) { return contents; } +char +*stripcomments(char *in) { + int len = strlen(in); + char *out = malloc(len + 1); + int i = 0; + for (char *s = in; *s != 0; s++) { + if (*s == '(') { + do { s++; } while (*s != ')'); + s++; + } + out[i] = *s; + i++; + } + out[len] = 0; + free(in); + return out; +} + char * readword(char *in) { char *input; @@ -50,19 +68,36 @@ tval * 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; + if (isdigit(word[1]) && (*word == 'b' || *word == 's' || *word == 'i')) { + for (char *c = word + 1; *c != 0; c++) + if (!isdigit(*c)) goto notnum; + if (*word == 'b') { + val->type = BLIT; + val->val = word + 1; + *size += sizeof(uint32_t); + return val; + } + else if (*word == 's') { + val->type = SLIT; + val->val = word + 1; + *size += sizeof(uint16_t); + return val; + } + else if (*word == 'i') { + val->type = ILIT; + val->val = word + 1; + *size += sizeof(int); + return val; + } } - else if (*word == '\"') { - val->type = SLIT; +notnum: + if (*word == '\"') { /* hard coded string */ + val->type = STRLIT; val->val = word + 1; *size += strlen(word + 1); return val; } - else if (*word == '@') { + else if (*word == '@') { /* label */ val->type = LABEL; val->val = word + 1; @@ -80,19 +115,19 @@ tokenize(char *word, int *size) { label_count++; return val; } - else if (*word == '|') { + else if (*word == '|') { /* align data */ val->type = PAD; val->val = word + 1; *size = strtol(word + 1, NULL, 0); return val; } - else if (*word == 'p') { + else if (*word == '#') { /* push int */ val->type = PUSH; val->val = word + 1; *size += sizeof(int) + sizeof(uint8_t); return val; } - else if (*word == '&') { + else if (*word == '&') { /* location of label */ val->type = PUSHA; val->val = word + 1; *size += sizeof(int) + sizeof(uint8_t); @@ -110,7 +145,7 @@ tokenize(char *word, int *size) { return val; } - + /* removing data */ else if (SAME(word, "deli")) val->type = DELI; else if (SAME(word, "dels")) @@ -118,6 +153,7 @@ tokenize(char *word, int *size) { else if (SAME(word, "delb")) val->type = DELB; + /* loading data */ else if (SAME(word, "loadi")) val->type = LOADI; else if (SAME(word, "loads")) @@ -125,6 +161,7 @@ tokenize(char *word, int *size) { else if (SAME(word, "loadb")) val->type = LOADB; + /* storing data */ else if (SAME(word, "storei")) val->type = STOREI; else if (SAME(word, "stores")) @@ -132,6 +169,7 @@ tokenize(char *word, int *size) { else if (SAME(word, "storeb")) val->type = STOREB; + /* dups */ else if (SAME(word, "dupi")) val->type = DUPI; else if (SAME(word, "dups")) @@ -139,18 +177,19 @@ tokenize(char *word, int *size) { else if (SAME(word, "dupb")) val->type = DUPB; + /* jumps */ else if (SAME(word, "jmp")) val->type = JMP; - else if (SAME(word, "jmpz")) - val->type = JMPZ; - + else if (SAME(word, "jnz")) + val->type = JNZ; else if (SAME(word, "call")) val->type = CALL; - else if (SAME(word, "callz")) - val->type = CALLZ; + else if (SAME(word, "callnz")) + val->type = CALLNZ; else if (SAME(word, "ret")) val->type = RET; + /* maths */ else if (SAME(word, "add")) val->type = ADD; else if (SAME(word, "sub")) @@ -159,9 +198,32 @@ tokenize(char *word, int *size) { val->type = DIV; else if (SAME(word, "mul")) val->type = MUL; - + + /* casts */ + else if (SAME(word, "b2s")) + val->type = B2S; + else if (SAME(word, "b2i")) + val->type = B2I; + else if (SAME(word, "s2b")) + val->type = S2B; + else if (SAME(word, "s2i")) + val->type = S2I; + else if (SAME(word, "i2b")) + val->type = I2B; + else if (SAME(word, "i2s")) + val->type = I2S; + + /* comparisons */ + else if (SAME(word, "equ")) + val->type = EQU; + else if (SAME(word, "neq")) + val->type = NEQ; + + /* misc */ else if (SAME(word, "halt")) val->type = HALT; + + else if (*word == 0) return NULL; else { fprintf(stderr, "Unknown cmd: %s\n", word); exit(1); @@ -181,15 +243,25 @@ appendbuf(const void *data, int size) { int compile(tval *val, int bytesdeep) { + if (!val) return bytesdeep; uint32_t ilit, ZERO = 0; + uint16_t u16lit; uint8_t u8lit; struct dict label = {val->val, bytesdeep}; switch (val->type) { + case BLIT: + u8lit = strtol(val->val, NULL, 0); + bytesdeep += appendbuf(&u8lit, sizeof(uint8_t)); + break; + case SLIT: + u16lit = strtol(val->val, NULL, 0); + bytesdeep += appendbuf(&u16lit, sizeof(uint16_t)); + break; case ILIT: ilit = strtol(val->val, NULL, 0); bytesdeep += appendbuf(&ilit, sizeof(int)); break; - case SLIT: + case STRLIT: bytesdeep += appendbuf(val->val, strlen(val->val)); break; case LABEL: @@ -241,7 +313,7 @@ main(int argc, char **argv) { out = fopen("a.rom", "wb"); int size; - char *input = drainfile(in), *swp = strdup(input), *tmp = input; + char *input = stripcomments(drainfile(in)), *swp = strdup(input), *tmp = input; char *word; tval *val; int bytesdeep;