516 lines
15 KiB
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;
|
|
}
|
|
}
|