aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMarvin Borner2021-04-20 00:54:43 +0200
committerMarvin Borner2021-04-20 00:54:43 +0200
commitaac2dae5cfcd360ad48f265910511c98decbf9e7 (patch)
tree45b7d421d2ff3d3db390f0c7fd969e4d8a58cd65
parent3ecfdb1064f7c4f45f53c415a77803ce2153d04d (diff)
Beautiful blub blabs
-rw-r--r--Makefile2
-rw-r--r--src/inc/def.h2
-rw-r--r--src/inc/lexer.h20
-rw-r--r--src/inc/parser.h4
-rw-r--r--src/inc/warnings.h11
-rw-r--r--src/lexer.c188
-rw-r--r--src/parser.c624
-rw-r--r--src/warnings.c56
8 files changed, 896 insertions, 11 deletions
diff --git a/Makefile b/Makefile
index 992b8b2..b33f360 100644
--- a/Makefile
+++ b/Makefile
@@ -5,7 +5,7 @@ OBJS = $(patsubst $(SOURCEDIR)/%.c, $(BUILDDIR)/%.o, $(SOURCES))
CC = gcc
WARNINGS = -Wall -Wextra -Wshadow -Wpointer-arith -Wwrite-strings -Wredundant-decls -Wnested-externs -Wformat=2 -Wmissing-declarations -Wstrict-prototypes -Wmissing-prototypes -Wcast-qual -Wswitch-default -Wswitch-enum -Wlogical-op -Wunreachable-code -Wundef -Wold-style-definition -Wvla -pedantic
-CFLAGS = -O3 $(WARNINGS) -I$(SOURCEDIR)/inc/ $(shell pkg-config --cflags --libs gtk+-3.0)
+CFLAGS = -Ofast $(WARNINGS) -I$(SOURCEDIR)/inc/ $(shell pkg-config --cflags --libs gtk+-3.0) -fsanitize=undefined
all: $(OBJS)
@$(CC) -o ./$(BUILDDIR)/out $^ $(CFLAGS)
diff --git a/src/inc/def.h b/src/inc/def.h
index bd06eb9..22e1bda 100644
--- a/src/inc/def.h
+++ b/src/inc/def.h
@@ -10,5 +10,7 @@ typedef signed short s16;
typedef signed char s8;
#define UNUSED(bla) ((void)(bla))
+#define MIN(a, b) (((a) < (b)) ? (a) : (b))
+#define MAX(a, b) (((a) > (b)) ? (a) : (b))
#endif
diff --git a/src/inc/lexer.h b/src/inc/lexer.h
index 833e522..82d533c 100644
--- a/src/inc/lexer.h
+++ b/src/inc/lexer.h
@@ -1,7 +1,9 @@
#ifndef LEXER_H
#define LEXER_H
-enum token {
+#include <def.h>
+
+enum token_type {
UNKNOWN,
NEWLINE,
NOP,
@@ -44,7 +46,7 @@ enum token {
DUBB,
MUL,
CJNE,
- SWP,
+ SWAP,
DA,
CRL,
XCH,
@@ -55,10 +57,16 @@ enum token {
DB,
DW,
INCLUDE,
- BRACE_OPEN,
- BRACE_CLOSE,
- DATA,
- BIT,
};
+struct token {
+ enum token_type type;
+ char *start;
+ u32 length;
+ void *data;
+};
+
+void token_print(struct token *tok);
+struct token token_resolve(char *token, u32 size);
+
#endif
diff --git a/src/inc/parser.h b/src/inc/parser.h
index c46ead1..0c59681 100644
--- a/src/inc/parser.h
+++ b/src/inc/parser.h
@@ -1,5 +1,5 @@
-#ifndef LEXER_H
-#define LEXER_H
+#ifndef PARSER_H
+#define PARSER_H
#include <def.h>
diff --git a/src/inc/warnings.h b/src/inc/warnings.h
new file mode 100644
index 0000000..495b2e2
--- /dev/null
+++ b/src/inc/warnings.h
@@ -0,0 +1,11 @@
+#ifndef WARNINGS_H
+#define WARNINGS_H
+
+#include <def.h>
+
+void warnings_print(void);
+void warnings_add(u32 line, const char *fmt, ...);
+void warnings_clear(void);
+u8 warnings_exist(void);
+
+#endif
diff --git a/src/lexer.c b/src/lexer.c
new file mode 100644
index 0000000..ecbc613
--- /dev/null
+++ b/src/lexer.c
@@ -0,0 +1,188 @@
+#include <def.h>
+#include <lexer.h>
+#include <stdio.h>
+#include <string.h>
+
+#define CMP(tok) (strncmp(tok " ", str, MIN(strlen(tok) + 1, size)) == 0)
+
+void token_print(struct token *tok)
+{
+ if (!tok->length)
+ return;
+
+ char swp = tok->start[tok->length];
+ tok->start[tok->length] = 0;
+ printf("%s\n", tok->start);
+ tok->start[tok->length] = swp;
+}
+
+struct token token_resolve(char *str, u32 size)
+{
+ enum token_type type = UNKNOWN;
+ u32 length = 0;
+
+ // "Beautiful" ~ Everyone. Probably.
+ if (CMP("nop")) {
+ type = NOP;
+ length = 3;
+ } else if (CMP("jbc")) {
+ type = JBC;
+ length = 3;
+ } else if (CMP("jb")) {
+ type = JB;
+ length = 2;
+ } else if (CMP("jnb")) {
+ type = JNB;
+ length = 3;
+ } else if (CMP("jc")) {
+ type = JC;
+ length = 2;
+ } else if (CMP("jnc")) {
+ type = JNC;
+ length = 3;
+ } else if (CMP("jz")) {
+ type = JZ;
+ length = 2;
+ } else if (CMP("jnz")) {
+ type = JNZ;
+ length = 3;
+ } else if (CMP("sjmp")) {
+ type = SJMP;
+ length = 4;
+ } else if (CMP("mov")) {
+ type = MOV;
+ length = 3;
+ } else if (CMP("orl")) {
+ type = ORL;
+ length = 3;
+ } else if (CMP("anl")) {
+ type = ANL;
+ length = 3;
+ } else if (CMP("push")) {
+ type = PUSH;
+ length = 4;
+ } else if (CMP("pop")) {
+ type = POP;
+ length = 3;
+ } else if (CMP("movx")) {
+ type = MOVX;
+ length = 4;
+ } else if (CMP("ajmp")) {
+ type = AJMP;
+ length = 4;
+ } else if (CMP("acall")) {
+ type = ACALL;
+ length = 5;
+ } else if (CMP("ljmp")) {
+ type = LJMP;
+ length = 4;
+ } else if (CMP("lcall")) {
+ type = LCALL;
+ length = 5;
+ } else if (CMP("reti")) {
+ type = RETI;
+ length = 4;
+ } else if (CMP("ret")) {
+ type = RET;
+ length = 3;
+ } else if (CMP("xrl")) {
+ type = XRL;
+ length = 3;
+ } else if (CMP("cpl")) {
+ type = CPL;
+ length = 3;
+ } else if (CMP("clr")) {
+ type = CLR;
+ length = 3;
+ } else if (CMP("setb")) {
+ type = SETB;
+ length = 4;
+ } else if (CMP("rr")) {
+ type = RR;
+ length = 2;
+ } else if (CMP("rrc")) {
+ type = RRC;
+ length = 3;
+ } else if (CMP("rl")) {
+ type = RL;
+ length = 2;
+ } else if (CMP("rlc")) {
+ type = RLC;
+ length = 3;
+ } else if (CMP("xlr")) {
+ type = XLR;
+ length = 3;
+ } else if (CMP("jmp")) {
+ type = JMP;
+ length = 3;
+ } else if (CMP("movc")) {
+ type = MOVC;
+ length = 4;
+ } else if (CMP("inc")) {
+ type = INC;
+ length = 3;
+ } else if (CMP("dec")) {
+ type = DEC;
+ length = 3;
+ } else if (CMP("add")) {
+ type = ADD;
+ length = 3;
+ } else if (CMP("addc")) {
+ type = ADDC;
+ length = 4;
+ } else if (CMP("div")) {
+ type = DIV;
+ length = 3;
+ } else if (CMP("dubb")) {
+ type = DUBB;
+ length = 4;
+ } else if (CMP("mul")) {
+ type = MUL;
+ length = 3;
+ } else if (CMP("cjne")) {
+ type = CJNE;
+ length = 4;
+ } else if (CMP("swap")) {
+ type = SWAP;
+ length = 4;
+ } else if (CMP("da")) {
+ type = DA;
+ length = 2;
+ } else if (CMP("crl")) {
+ type = CRL;
+ length = 3;
+ } else if (CMP("xch")) {
+ type = XCH;
+ length = 3;
+ } else if (CMP("djnz")) {
+ type = DJNZ;
+ length = 4;
+ } else if (CMP("xchd")) {
+ type = XCHD;
+ length = 4;
+ } else if (CMP("call")) {
+ type = CALL;
+ length = 4;
+ } else if (CMP("org")) {
+ type = ORG;
+ length = 3;
+ } else if (CMP("db")) {
+ type = DB;
+ length = 2;
+ } else if (CMP("dw")) {
+ type = DW;
+ length = 2;
+ } else if (CMP("include")) {
+ type = INCLUDE;
+ length = 7;
+ }
+
+ struct token tok = {
+ .type = type,
+ .start = str,
+ .length = length,
+ .data = 0,
+ };
+
+ return tok;
+}
diff --git a/src/parser.c b/src/parser.c
index e4d0251..7cc23e5 100644
--- a/src/parser.c
+++ b/src/parser.c
@@ -1,16 +1,629 @@
#include <def.h>
+#include <lexer.h>
#include <parser.h>
#include <stdio.h>
#include <string.h>
+#include <warnings.h>
-#define PEEK(hay, needle) (strcmp(hay, needle) == 0)
+/**
+ * Definitions
+ */
+
+#define ROM_SIZE 4096 // TODO: Actual ROM size?
+
+/**
+ * ROM blub blabs
+ */
+
+static u8 rom[ROM_SIZE] = { 0 };
+static u32 rom_index = 0;
+static void rom_add(u8 byte)
+{
+ rom[rom_index] = byte;
+ rom_index++;
+}
+
+/**
+ * Main parsing
+ */
+
+static u32 parse_nop(u32 line, char *str, u32 size)
+{
+ UNUSED(line);
+ UNUSED(str);
+ UNUSED(size);
+ rom_add(0);
+ return 0;
+}
+
+static u32 parse_jbc(u32 line, char *str, u32 size)
+{
+ UNUSED(line);
+ UNUSED(str);
+ UNUSED(size);
+ return 0;
+}
+
+static u32 parse_jb(u32 line, char *str, u32 size)
+{
+ UNUSED(line);
+ UNUSED(str);
+ UNUSED(size);
+ return 0;
+}
+
+static u32 parse_jnb(u32 line, char *str, u32 size)
+{
+ UNUSED(line);
+ UNUSED(str);
+ UNUSED(size);
+ return 0;
+}
+
+static u32 parse_jc(u32 line, char *str, u32 size)
+{
+ UNUSED(line);
+ UNUSED(str);
+ UNUSED(size);
+ return 0;
+}
+
+static u32 parse_jnc(u32 line, char *str, u32 size)
+{
+ UNUSED(line);
+ UNUSED(str);
+ UNUSED(size);
+ return 0;
+}
+
+static u32 parse_jz(u32 line, char *str, u32 size)
+{
+ UNUSED(line);
+ UNUSED(str);
+ UNUSED(size);
+ return 0;
+}
+
+static u32 parse_jnz(u32 line, char *str, u32 size)
+{
+ UNUSED(line);
+ UNUSED(str);
+ UNUSED(size);
+ return 0;
+}
+
+static u32 parse_sjmp(u32 line, char *str, u32 size)
+{
+ UNUSED(line);
+ UNUSED(str);
+ UNUSED(size);
+ return 0;
+}
+
+static u32 parse_mov(u32 line, char *str, u32 size)
+{
+ UNUSED(line);
+ UNUSED(str);
+ UNUSED(size);
+ return 0;
+}
+
+static u32 parse_orl(u32 line, char *str, u32 size)
+{
+ UNUSED(line);
+ UNUSED(str);
+ UNUSED(size);
+ return 0;
+}
+
+static u32 parse_anl(u32 line, char *str, u32 size)
+{
+ UNUSED(line);
+ UNUSED(str);
+ UNUSED(size);
+ return 0;
+}
+
+static u32 parse_push(u32 line, char *str, u32 size)
+{
+ UNUSED(line);
+ UNUSED(str);
+ UNUSED(size);
+ return 0;
+}
+
+static u32 parse_pop(u32 line, char *str, u32 size)
+{
+ UNUSED(line);
+ UNUSED(str);
+ UNUSED(size);
+ return 0;
+}
+
+static u32 parse_movx(u32 line, char *str, u32 size)
+{
+ UNUSED(line);
+ UNUSED(str);
+ UNUSED(size);
+ return 0;
+}
+
+static u32 parse_ajmp(u32 line, char *str, u32 size)
+{
+ UNUSED(line);
+ UNUSED(str);
+ UNUSED(size);
+ return 0;
+}
+
+static u32 parse_acall(u32 line, char *str, u32 size)
+{
+ UNUSED(line);
+ UNUSED(str);
+ UNUSED(size);
+ return 0;
+}
+
+static u32 parse_ljmp(u32 line, char *str, u32 size)
+{
+ UNUSED(line);
+ UNUSED(str);
+ UNUSED(size);
+ return 0;
+}
+
+static u32 parse_lcall(u32 line, char *str, u32 size)
+{
+ UNUSED(line);
+ UNUSED(str);
+ UNUSED(size);
+ return 0;
+}
+
+static u32 parse_reti(u32 line, char *str, u32 size)
+{
+ UNUSED(line);
+ UNUSED(str);
+ UNUSED(size);
+ return 0;
+}
+
+static u32 parse_ret(u32 line, char *str, u32 size)
+{
+ UNUSED(line);
+ UNUSED(str);
+ UNUSED(size);
+ return 0;
+}
+
+static u32 parse_xrl(u32 line, char *str, u32 size)
+{
+ UNUSED(line);
+ UNUSED(str);
+ UNUSED(size);
+ return 0;
+}
+
+static u32 parse_cpl(u32 line, char *str, u32 size)
+{
+ UNUSED(line);
+ UNUSED(str);
+ UNUSED(size);
+ return 0;
+}
+
+static u32 parse_clr(u32 line, char *str, u32 size)
+{
+ UNUSED(line);
+ UNUSED(str);
+ UNUSED(size);
+ return 0;
+}
+
+static u32 parse_setb(u32 line, char *str, u32 size)
+{
+ UNUSED(line);
+ UNUSED(str);
+ UNUSED(size);
+ return 0;
+}
+
+static u32 parse_rr(u32 line, char *str, u32 size)
+{
+ UNUSED(line);
+ UNUSED(str);
+ UNUSED(size);
+ return 0;
+}
+
+static u32 parse_rrc(u32 line, char *str, u32 size)
+{
+ UNUSED(line);
+ UNUSED(str);
+ UNUSED(size);
+ return 0;
+}
+
+static u32 parse_rl(u32 line, char *str, u32 size)
+{
+ UNUSED(line);
+ UNUSED(str);
+ UNUSED(size);
+ return 0;
+}
+
+static u32 parse_rlc(u32 line, char *str, u32 size)
+{
+ UNUSED(line);
+ UNUSED(str);
+ UNUSED(size);
+ return 0;
+}
+
+static u32 parse_xlr(u32 line, char *str, u32 size)
+{
+ UNUSED(line);
+ UNUSED(str);
+ UNUSED(size);
+ return 0;
+}
+
+static u32 parse_jmp(u32 line, char *str, u32 size)
+{
+ UNUSED(line);
+ UNUSED(str);
+ UNUSED(size);
+ return 0;
+}
+
+static u32 parse_movc(u32 line, char *str, u32 size)
+{
+ UNUSED(line);
+ UNUSED(str);
+ UNUSED(size);
+ return 0;
+}
+
+static u32 parse_inc(u32 line, char *str, u32 size)
+{
+ UNUSED(line);
+ UNUSED(str);
+ UNUSED(size);
+ return 0;
+}
+
+static u32 parse_dec(u32 line, char *str, u32 size)
+{
+ UNUSED(line);
+ UNUSED(str);
+ UNUSED(size);
+ return 0;
+}
+
+static u32 parse_add(u32 line, char *str, u32 size)
+{
+ UNUSED(line);
+ UNUSED(str);
+ UNUSED(size);
+ return 0;
+}
+
+static u32 parse_addc(u32 line, char *str, u32 size)
+{
+ UNUSED(line);
+ UNUSED(str);
+ UNUSED(size);
+ return 0;
+}
+
+static u32 parse_div(u32 line, char *str, u32 size)
+{
+ UNUSED(line);
+ UNUSED(str);
+ UNUSED(size);
+ return 0;
+}
+
+static u32 parse_dubb(u32 line, char *str, u32 size)
+{
+ UNUSED(line);
+ UNUSED(str);
+ UNUSED(size);
+ return 0;
+}
+
+static u32 parse_mul(u32 line, char *str, u32 size)
+{
+ UNUSED(line);
+ UNUSED(str);
+ UNUSED(size);
+ return 0;
+}
+
+static u32 parse_cjne(u32 line, char *str, u32 size)
+{
+ UNUSED(line);
+ UNUSED(str);
+ UNUSED(size);
+ return 0;
+}
+
+static u32 parse_swap(u32 line, char *str, u32 size)
+{
+ UNUSED(line);
+ UNUSED(str);
+ UNUSED(size);
+ return 0;
+}
+
+static u32 parse_da(u32 line, char *str, u32 size)
+{
+ UNUSED(line);
+ UNUSED(str);
+ UNUSED(size);
+ return 0;
+}
+
+static u32 parse_crl(u32 line, char *str, u32 size)
+{
+ UNUSED(line);
+ UNUSED(str);
+ UNUSED(size);
+ return 0;
+}
+
+static u32 parse_xch(u32 line, char *str, u32 size)
+{
+ UNUSED(line);
+ UNUSED(str);
+ UNUSED(size);
+ return 0;
+}
+
+static u32 parse_djnz(u32 line, char *str, u32 size)
+{
+ UNUSED(line);
+ UNUSED(str);
+ UNUSED(size);
+ return 0;
+}
+
+static u32 parse_xchd(u32 line, char *str, u32 size)
+{
+ UNUSED(line);
+ UNUSED(str);
+ UNUSED(size);
+ return 0;
+}
+
+static u32 parse_call(u32 line, char *str, u32 size)
+{
+ UNUSED(line);
+ UNUSED(str);
+ UNUSED(size);
+ return 0;
+}
+
+static u32 parse_org(u32 line, char *str, u32 size)
+{
+ UNUSED(line);
+ UNUSED(str);
+ UNUSED(size);
+ return 0;
+}
+
+static u32 parse_db(u32 line, char *str, u32 size)
+{
+ UNUSED(line);
+ UNUSED(str);
+ UNUSED(size);
+ return 0;
+}
+
+static u32 parse_dw(u32 line, char *str, u32 size)
+{
+ UNUSED(line);
+ UNUSED(str);
+ UNUSED(size);
+ return 0;
+}
+
+static u32 parse_include(u32 line, char *str, u32 size)
+{
+ UNUSED(line);
+ UNUSED(str);
+ UNUSED(size);
+ return 0;
+}
+
+static u32 parse_instruction(u32 line, char *str, u32 size)
+{
+ struct token tok = token_resolve(str, size);
+
+ token_print(&tok);
+
+ u32 ret = tok.length;
+
+ switch (tok.type) {
+ case UNKNOWN:
+ warnings_add(line, "Unknown instruction");
+ return 0;
+ case NEWLINE:
+ break;
+ case NOP:
+ ret += parse_nop(line, str, size);
+ break;
+ case JBC:
+ ret += parse_jbc(line, str, size);
+ break;
+ case JB:
+ ret += parse_jb(line, str, size);
+ break;
+ case JNB:
+ ret += parse_jnb(line, str, size);
+ break;
+ case JC:
+ ret += parse_jc(line, str, size);
+ break;
+ case JNC:
+ ret += parse_jnc(line, str, size);
+ break;
+ case JZ:
+ ret += parse_jz(line, str, size);
+ break;
+ case JNZ:
+ ret += parse_jnz(line, str, size);
+ break;
+ case SJMP:
+ ret += parse_sjmp(line, str, size);
+ break;
+ case MOV:
+ ret += parse_mov(line, str, size);
+ break;
+ case ORL:
+ ret += parse_orl(line, str, size);
+ break;
+ case ANL:
+ ret += parse_anl(line, str, size);
+ break;
+ case PUSH:
+ ret += parse_push(line, str, size);
+ break;
+ case POP:
+ ret += parse_pop(line, str, size);
+ break;
+ case MOVX:
+ ret += parse_movx(line, str, size);
+ break;
+ case AJMP:
+ ret += parse_ajmp(line, str, size);
+ break;
+ case ACALL:
+ ret += parse_acall(line, str, size);
+ break;
+ case LJMP:
+ ret += parse_ljmp(line, str, size);
+ break;
+ case LCALL:
+ ret += parse_lcall(line, str, size);
+ break;
+ case RETI:
+ ret += parse_reti(line, str, size);
+ break;
+ case RET:
+ ret += parse_ret(line, str, size);
+ break;
+ case XRL:
+ ret += parse_xrl(line, str, size);
+ break;
+ case CPL:
+ ret += parse_cpl(line, str, size);
+ break;
+ case CLR:
+ ret += parse_clr(line, str, size);
+ break;
+ case SETB:
+ ret += parse_setb(line, str, size);
+ break;
+ case RR:
+ ret += parse_rr(line, str, size);
+ break;
+ case RRC:
+ ret += parse_rrc(line, str, size);
+ break;
+ case RL:
+ ret += parse_rl(line, str, size);
+ break;
+ case RLC:
+ ret += parse_rlc(line, str, size);
+ break;
+ case XLR:
+ ret += parse_xlr(line, str, size);
+ break;
+ case JMP:
+ ret += parse_jmp(line, str, size);
+ break;
+ case MOVC:
+ ret += parse_movc(line, str, size);
+ break;
+ case INC:
+ ret += parse_inc(line, str, size);
+ break;
+ case DEC:
+ ret += parse_dec(line, str, size);
+ break;
+ case ADD:
+ ret += parse_add(line, str, size);
+ break;
+ case ADDC:
+ ret += parse_addc(line, str, size);
+ break;
+ case DIV:
+ ret += parse_div(line, str, size);
+ break;
+ case DUBB:
+ ret += parse_dubb(line, str, size);
+ break;
+ case MUL:
+ ret += parse_mul(line, str, size);
+ break;
+ case CJNE:
+ ret += parse_cjne(line, str, size);
+ break;
+ case SWAP:
+ ret += parse_swap(line, str, size);
+ break;
+ case DA:
+ ret += parse_da(line, str, size);
+ break;
+ case CRL:
+ ret += parse_crl(line, str, size);
+ break;
+ case XCH:
+ ret += parse_xch(line, str, size);
+ break;
+ case DJNZ:
+ ret += parse_djnz(line, str, size);
+ break;
+ case XCHD:
+ ret += parse_xchd(line, str, size);
+ break;
+ case CALL:
+ ret += parse_call(line, str, size);
+ break;
+ case ORG:
+ ret += parse_org(line, str, size);
+ break;
+ case DB:
+ ret += parse_db(line, str, size);
+ break;
+ case DW:
+ ret += parse_dw(line, str, size);
+ break;
+ case INCLUDE:
+ ret += parse_include(line, str, size);
+ break;
+ default:
+ warnings_add(line, "Super-unknown instruction");
+ }
+
+ return ret;
+}
+
+static void clean_buffers(void)
+{
+ if (rom_index)
+ memset(rom, 0, sizeof(rom));
+ warnings_clear();
+}
u8 parse(char *buf, u32 size)
{
+ clean_buffers();
+
u32 line = 0;
for (u32 i = 0; i < size; i++) {
- /* printf("'%c'\n", buf[i]); */
if (buf[i] == '\0')
break;
@@ -18,6 +631,13 @@ u8 parse(char *buf, u32 size)
line++;
continue;
}
+
+ i += parse_instruction(line, buf + i, size - i);
+ }
+
+ if (warnings_exist()) {
+ warnings_print();
+ return 0;
}
return 1;
diff --git a/src/warnings.c b/src/warnings.c
new file mode 100644
index 0000000..fd11264
--- /dev/null
+++ b/src/warnings.c
@@ -0,0 +1,56 @@
+#include <assert.h>
+#include <def.h>
+#include <gui.h>
+#include <stdarg.h>
+#include <stdio.h>
+#include <string.h>
+#include <warnings.h>
+
+#define WARNING_COUNT 1024 // Well, something went horribly wrong I guess
+#define WARNING_LENGTH 64
+
+struct warning {
+ u8 exists;
+ u32 line;
+ char text[WARNING_LENGTH];
+};
+
+static struct warning warnings[WARNING_COUNT] = { 0 };
+static u32 warning_index = 0;
+void warnings_add(u32 line, const char *fmt, ...)
+{
+ assert(warning_index + 1 < WARNING_COUNT);
+
+ warnings[warning_index].exists = 1;
+ warnings[warning_index].line = line;
+
+ va_list ap;
+ va_start(ap, fmt);
+ vsnprintf(warnings[warning_index].text, WARNING_LENGTH, fmt, ap);
+ va_end(ap);
+
+ warning_index++;
+}
+
+// TODO: Print somewhere else (e.g. next to line)
+void warnings_print(void)
+{
+ for (u32 i = 0; i < WARNING_COUNT; i++) {
+ if (!warnings[i].exists)
+ continue;
+
+ /* gui_show_warning(warnings[i].text); */
+ printf("Line %d: %s\n", warnings[i].line, warnings[i].text);
+ }
+}
+
+u8 warnings_exist(void)
+{
+ return warning_index > 0;
+}
+
+void warnings_clear(void)
+{
+ if (warning_index)
+ memset(warnings, 0, sizeof(warnings));
+}