FlagVM/flagpole/src/main.c

516 lines
15 KiB
C

#include <stdio.h>
#include <unistd.h>
#include <ctype.h>
#define LAZY_IMPL
#include "lazy.h"
#include "token.h"
#include "var.h"
bool is_int_literal(Lz_SB *sb) {
for (int i = 0; i < sb->cnt; ++i) {
char c = sb->data[i];
if (!(isdigit(c) || (i == 0 && c == '-'))) {
return false;
}
}
return true;
}
bool is_float_literal(Lz_SB *sb) {
for (int i = 0; i < sb->cnt-1; ++i) {
char c = sb->data[i];
if (!(isdigit(c) || (i == 0 && c == '-') || c == '.')) {
return false;
}
}
return sb->data[sb->cnt-1] == 'f';
}
bool is_double_literal(Lz_SB *sb) {
for (int i = 0; i < sb->cnt; ++i) {
char c = sb->data[i];
if (!(isdigit(c) || (i == 0 && c == '-') || c == '.')) {
return false;
}
}
return true;
}
bool is_hex_literal(Lz_SB *sb) {
if (sb->data[0] != '0' || sb->data[1] != 'x') {
return false;
}
for (int i = 2; i < sb->cnt; ++i) {
char c = sb->data[i];
if (c >= '0' && c <= '9') continue;
if (c >= 'a' && c <= 'f') continue;
if (c >= 'A' && c <= 'F') continue;
return false;
}
return true;
}
bool is_bin_literal(Lz_SB *sb) {
if (sb->data[0] != '0' || sb->data[1] != 'b') {
return false;
}
for (int i = 2; i < sb->cnt; ++i) {
char c = sb->data[i];
if (c == '0' && c == '1') continue;
return false;
}
return true;
}
bool SBeq(Lz_SB *sb, const char *cstr) {
size_t l = strlen(cstr);
if (l != sb->cnt) return false;
return !memcmp(sb->data, cstr, l);
}
void commentStack(void *stack) {
typedef Lz_DA(int) intstack;
intstack *s = stack;
printf(" ; Stack:");
lz_da_foreach(int, x, *s) {
printf(" %d", *x);
}
printf("\n");
}
static inline bool isKW(Lz_SB *sb) {
return
SBeq(sb, "proc")
|| SBeq(sb, "endproc")
|| SBeq(sb, "return")
|| SBeq(sb, "ld8")
|| SBeq(sb, "st8")
|| SBeq(sb, "dup")
|| SBeq(sb, "swap")
|| SBeq(sb, "while")
|| SBeq(sb, "do")
|| SBeq(sb, "if")
|| SBeq(sb, "then")
|| SBeq(sb, "endif")
|| SBeq(sb, "endwhile")
|| SBeq(sb, "==")
|| SBeq(sb, "not")
|| SBeq(sb, "u+")
|| SBeq(sb, "u-")
|| SBeq(sb, "u*")
|| SBeq(sb, "u/")
|| SBeq(sb, "u%")
|| SBeq(sb, "u>")
|| SBeq(sb, "u<")
|| SBeq(sb, "pop")
|| SBeq(sb, "$inc")
;
}
int main(uint argc, char **argv) {
int opt;
Lz_DA(FILE *) inpfiles = {};
while ((opt = getopt(argc, argv, "f:")) != -1) {
switch(opt) {
case 'f': {
FILE *inpfile = fopen(optarg, "r");
if (!inpfile) {
printf("Failed to open file %s\n", optarg);
exit(1);
}
lz_da_append(inpfiles, inpfile);
break;
}
default: break;
}
}
if (inpfiles.cnt == 0) {
printf("No file requested\n");
exit(1);
}
FILE *currFile = lz_da_pop(inpfiles);
TokenKind currTokenKind;
Lz_SB tokenAccumulator = {0};
int counter = 0;
bool isQuote = false;
bool isProc = false;
bool isInclude = false;
Lz_DA(int) labelStack = {0};
uint64_t allocHead = 0x7000000000000000;
char funcName[128];
Lz_DA(Variable) vars;
char newchar;
printf("include 'fvm.inc'\n");
printf("define STACK_START 0x6000000000000000\n");
printf("define STACK_SP 125\n");
printf("org 0x4000000000000000\n");
printf(" MovI64 STACK_SP, STACK_START\n");
printf(" Call __fp_user_main\n");
printf(" Halt\n");
printf("macro pushstack reg\n");
printf(" MovI64 124, 8\n");
printf(" SubR64 STACK_SP, 124\n");
printf(" St64 reg, STACK_SP\n");
printf("end macro\n\n");
printf("macro popstack reg\n");
printf(" MovI64 124, 8\n");
printf(" Ld64 reg, STACK_SP\n");
printf(" AddR64 STACK_SP, 124\n");
printf("end macro\n\n");
// Genuinely idk why goto is possessing me today
compileStart:
while ((newchar = fgetc(currFile)) != EOF) {
++counter;
if (isspace(newchar) && !isQuote) {
if (tokenAccumulator.cnt == 0) continue;
if (is_int_literal(&tokenAccumulator)) {
currTokenKind = TOKEN_INTLIT;
goto codegen;
} else if (is_float_literal(&tokenAccumulator)) {
currTokenKind = TOKEN_FLOATLIT;
goto codegen;
} else if (is_double_literal(&tokenAccumulator)) {
currTokenKind = TOKEN_DOUBLELIT;
goto codegen;
} else if (is_hex_literal(&tokenAccumulator)) {
currTokenKind = TOKEN_HEXLIT;
goto codegen;
} else if (is_bin_literal(&tokenAccumulator)) {
currTokenKind = TOKEN_BINLIT;
goto codegen;
} else {
currTokenKind = TOKEN_IDENTIFIER;
if (isKW(&tokenAccumulator)) {
currTokenKind = TOKEN_KEYWORD;
}
goto codegen;
}
}
if (newchar == '"') {
if (isQuote) {
currTokenKind = TOKEN_STRINGLIT;
isQuote = false;
goto codegen;
} else {
if (tokenAccumulator.cnt != 0) {
fprintf(stderr, "error %d\n", __LINE__);
exit(1);
} else {
isQuote = true;
}
continue;
}
}
lz_da_append(tokenAccumulator, newchar);
continue;
codegen:
//printf("I must gen code i am now Amista Azozin\n");
//fprintf(stderr,"Token type: %d\n", currTokenKind);
//fprintf(stderr,"Tok: "LZ_STR_FMT"\n", LZ_STR_PRINTF(tokenAccumulator));
printf(" ; "LZ_STR_FMT"\n", LZ_STR_PRINTF(tokenAccumulator));
switch (currTokenKind) {
case TOKEN_KEYWORD: {
if (SBeq(&tokenAccumulator, "proc")) {
isProc = true;
break;
}
if (SBeq(&tokenAccumulator, "endproc")) {
printf(" Ret\n");
printf("\n\n");
if (labelStack.cnt != 0) {
fprintf(stderr,
"Unmatched statement in function %s\n", funcName);
exit(1);
}
funcName[0] = 0;
break;
}
if (SBeq(&tokenAccumulator, "return")) {
printf(" Ret\n");
break;
}
if (SBeq(&tokenAccumulator, "ld8")) {
printf(" popstack 101\n");
printf(" Ld8 102, 101\n");
printf(" pushstack 102\n");
break;
}
if (SBeq(&tokenAccumulator, "st8")) {
printf(" popstack 101\n");
printf(" popstack 102\n");
printf(" St8 102, 101\n");
break;
}
if (SBeq(&tokenAccumulator, "dup")) {
printf(" popstack 106\n");
printf(" pushstack 106\n");
printf(" pushstack 106\n");
break;
}
if (SBeq(&tokenAccumulator, "swap")) {
printf(" popstack 118\n");
printf(" popstack 119\n");
printf(" pushstack 118\n");
printf(" pushstack 119\n");
break;
}
if (SBeq(&tokenAccumulator, "while")) {
lz_da_append(labelStack, counter);
commentStack(&labelStack);
printf("__whilehead_%d:\n", counter);
break;
}
if (SBeq(&tokenAccumulator, "do")) {
int lbl = lz_da_pop(labelStack);
lz_da_append(labelStack, lbl);
printf(" popstack 108\n");
printf(" RSetF 108\n");
printf(" JmpIE __whiletail_%d\n", lbl);
break;
}
if (SBeq(&tokenAccumulator, "endwhile")) {
int lbl = lz_da_pop(labelStack);
commentStack(&labelStack);
printf(" Jmp __whilehead_%d\n", lbl);
printf("__whiletail_%d:\n", lbl);
break;
}
if (SBeq(&tokenAccumulator, "if")) {
lz_da_append(labelStack, counter);
commentStack(&labelStack);
break;
}
if (SBeq(&tokenAccumulator, "then")) {
commentStack(&labelStack);
int lbl = lz_da_pop(labelStack);
lz_da_append(labelStack, lbl);
printf(" popstack 123\n");
printf(" RSetF 123\n");
printf(" JmpIE __iftail_%d\n", lbl);
break;
}
if (SBeq(&tokenAccumulator, "endif")) {
commentStack(&labelStack);
int lbl = lz_da_pop(labelStack);
printf("__iftail_%d:\n", lbl);
break;
}
if (SBeq(&tokenAccumulator, "==")) {
// Hacked like crazy...
printf(" popstack 110\n");
printf(" popstack 111\n");
printf(" Cmp64 110, 111\n");
printf(" JmpIZ __Eq%d\n", counter);
printf(" MovI64 112, 0\n");
printf(" Jmp __DoneEqCheck%d\n", counter);
printf("__Eq%d:\n", counter);
printf(" MovI64 112, 1\n");
printf("__DoneEqCheck%d:\n", counter);
printf(" pushstack 112\n");
break;
}
if (SBeq(&tokenAccumulator, "not")) {
printf(" popstack 96\n");
printf(" Not64 96\n");
printf(" pushstack 96\n");
break;
}
if (SBeq(&tokenAccumulator, "u+")) {
printf(" popstack 97\n");
printf(" popstack 98\n");
printf(" AddR64 98, 97\n");
printf(" pushstack 98\n");
break;
}
if (SBeq(&tokenAccumulator, "u-")) {
printf(" popstack 97\n");
printf(" popstack 98\n");
printf(" SubR64 98, 97\n");
printf(" pushstack 98\n");
break;
}
if (SBeq(&tokenAccumulator, "u*")) {
printf(" popstack 97\n");
printf(" popstack 98\n");
printf(" MulR64 98, 97\n");
printf(" pushstack 98\n");
break;
}
if (SBeq(&tokenAccumulator, "u/")) {
printf(" popstack 97\n");
printf(" popstack 98\n");
printf(" DivR64 98, 97\n");
printf(" pushstack 98\n");
break;
}
if (SBeq(&tokenAccumulator, "u%")) {
printf(" popstack 97\n");
printf(" popstack 98\n");
printf(" ModR64 98, 97\n");
printf(" pushstack 98\n");
break;
}
if (SBeq(&tokenAccumulator, "u>")) {
printf(" popstack 97\n");
printf(" popstack 98\n");
printf(" Cmp64 98, 97\n");
printf(" JmpIP __Cmp%d\n", counter);
printf(" MovI64 112, 0\n");
printf(" Jmp __DoneCmp%d\n", counter);
printf("__Cmp%d:\n", counter);
printf(" MovI64 112, 1\n");
printf("__DoneCmp%d:\n", counter);
printf(" pushstack 112\n");
break;
}
if (SBeq(&tokenAccumulator, "pop")) {
printf(" popstack 113\n");
break;
}
if (SBeq(&tokenAccumulator, "$inc")) {
isInclude = true;
break;
}
printf("Unimplemented keyword: "LZ_STR_FMT"\n",
LZ_STR_PRINTF(tokenAccumulator));
exit(1);
}
case TOKEN_IDENTIFIER: {
if (isInclude) {
char *fname = malloc(tokenAccumulator.cnt+1);
memcpy(fname, tokenAccumulator.data, tokenAccumulator.cnt);
fname[tokenAccumulator.cnt] = 0;
FILE *f = fopen(fname, "rb");
if (!f) {
fprintf(stderr, "Could not open file %s or doesn't exist\n",
fname);
}
lz_da_append(inpfiles, f);
isInclude = false;
break;
}
if (isProc) {
printf("__fp_user_"LZ_STR_FMT":\n",
LZ_STR_PRINTF(tokenAccumulator));
isProc = false;
if (tokenAccumulator.cnt < 127) {
memcpy(funcName, tokenAccumulator.data, tokenAccumulator.cnt);
funcName[tokenAccumulator.cnt] = 0;
} else {
memcpy(funcName, tokenAccumulator.data, 127);
funcName[127] = 0;
}
break;
}
if (tokenAccumulator.data[0] == ':') {
printf(" Call __fp_user_"LZ_STR_FMT"\n",
tokenAccumulator.cnt-1,
tokenAccumulator.data+1);
break;
}
if (tokenAccumulator.data[0] == '@') {
char varName[128];
if (tokenAccumulator.cnt < 128) {
memcpy(varName, tokenAccumulator.data+1,
tokenAccumulator.cnt-1);
varName[tokenAccumulator.cnt] = 0;
} else {
memcpy(varName, tokenAccumulator.data+1, 127);
varName[127] = 0;
}
uint64_t addr = 0;
lz_da_foreach(Variable, v, vars) {
if (!strcmp(v->name, varName) && !strcmp(v->func, funcName)) {
addr = v->addr;
break;
}
}
if (addr == 0) {
addr = allocHead;
Variable v = (Variable) {
.addr = addr
};
memcpy(&v.func, funcName, 128);
memcpy(&v.name, varName, 128);
lz_da_append(vars, v);
allocHead += 8;
}
printf(" popstack 120\n");
printf(" MovI64 121, 0x%16lX\n", addr);
printf(" St64 120, 121\n");
break;
}
if (tokenAccumulator.data[0] == '&') {
char varName[128];
if (tokenAccumulator.cnt < 128) {
memcpy(varName, tokenAccumulator.data+1,
tokenAccumulator.cnt-1);
varName[tokenAccumulator.cnt-1] = 0;
} else {
memcpy(varName, tokenAccumulator.data+1, 127);
varName[127] = 0;
}
uint64_t addr = 0;
lz_da_foreach(Variable, v, vars) {
if (!strcmp(v->name, varName) && !strcmp(v->func, funcName)) {
addr = v->addr;
break;
}
}
if (addr == 0) {
fprintf(stderr, "Undeclared variable %s in function %s\n",
varName, funcName);
exit(1);
}
printf(" MovI64 121, 0x%16lX\n", addr);
printf(" Ld64 120, 121\n");
printf(" pushstack 120\n");
break;
}
// Iirc there's not a general thing for identifiers so just fail?
fprintf(stderr, "Useless Identifier: "LZ_STR_FMT"\n",
LZ_STR_PRINTF(tokenAccumulator));
exit(0);
}
case TOKEN_INTLIT: {
printf(" MovI64 103, "LZ_STR_FMT"\n",
LZ_STR_PRINTF(tokenAccumulator));
printf(" pushstack 103\n");
break;
}
case TOKEN_HEXLIT: {
printf(" MovI64 103, "LZ_STR_FMT"\n",
LZ_STR_PRINTF(tokenAccumulator));
printf(" pushstack 103\n");
break;
}
case TOKEN_STRINGLIT: {
printf(" Jmp endstring%d\n", counter);
printf("string%d db '"LZ_STR_FMT"', 0\n",
counter,
LZ_STR_PRINTF(tokenAccumulator));
printf("endstring%d:\n", counter);
printf(" MovI64 100, string%d\n", counter);
printf(" pushstack 100\n", counter);
break;
}
default: {
printf("Bad: %d\n", currTokenKind);
exit(1);
}
}
tokenAccumulator.cnt = 0;
}
if (inpfiles.cnt != 0) {
currFile = lz_da_pop(inpfiles);
tokenAccumulator.cnt = 0;
isProc = false;
isQuote = false;
isInclude = false;
labelStack.cnt = 0;
goto compileStart;
}
}