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:
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;