undar-lang/src/tools/compiler/compiler.c

503 lines
12 KiB
C

#include "compiler.h"
#include "../../vm/common.h"
#include "../../vm/libc.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
NamesTable *names_table_init() {
NamesTable *table = malloc(sizeof(NamesTable));
table->names = malloc(16 * sizeof(char *));
table->count = 0;
table->capacity = 16;
return table;
}
FunctionTable *function_table_init() {
FunctionTable *table = malloc(sizeof(FunctionTable));
table->symbols = malloc(16 * sizeof(FunctionDef));
table->count = 0;
table->capacity = 16;
return table;
}
ArrayTable *array_table_init() {
ArrayTable *table = malloc(sizeof(ArrayTable));
table->symbols = malloc(16 * sizeof(ArrayDef));
table->count = 0;
table->capacity = 16;
return table;
}
PlexTable *plex_table_init() {
PlexTable *table = malloc(sizeof(PlexTable));
table->symbols = malloc(16 * sizeof(PlexDef));
table->count = 0;
table->capacity = 16;
return table;
}
PlexFieldsTable *plex_fields_table_init() {
PlexFieldsTable *table = malloc(sizeof(PlexFieldsTable));
table->plex_refs = malloc(64 * sizeof(u32));
table->fields = malloc(64 * sizeof(ValueType));
table->count = 0;
table->capacity = 64;
return table;
}
u32 names_table_add(NamesTable *table, const char *name) {
for (u32 i = 0; i < table->count; i++) {
if (strcmp(table->names[i], name) == 0) {
return (u32)i;
}
}
if (table->count >= table->capacity) {
table->capacity *= 2;
table->names = realloc(table->names, table->capacity * sizeof(char *));
}
table->names[table->count] = malloc(strlen(name) + 1);
strcpy(table->names[table->count], name);
u32 index = (u32)table->count;
table->count++;
return index;
}
u32 function_table_add(FunctionTable *table, FunctionDef def) {
if (table->count >= table->capacity) {
table->capacity *= 2;
table->symbols =
realloc(table->symbols, table->capacity * sizeof(FunctionDef));
}
table->symbols[table->count] = def;
u32 index = (u32)table->count;
table->count++;
return index;
}
u32 array_table_add(ArrayTable *table, ArrayDef def) {
if (table->count >= table->capacity) {
table->capacity *= 2;
table->symbols = realloc(table->symbols, table->capacity * sizeof(ArrayDef));
}
table->symbols[table->count] = def;
u32 index = (u32)table->count;
table->count++;
return index;
}
u32 plex_add(PlexTable *plex_table, u32 name, u32 size, u32 field_start,
u32 field_count) {
if (plex_table->count >= plex_table->capacity) {
plex_table->capacity *= 2;
plex_table->symbols =
realloc(plex_table->symbols, plex_table->capacity * sizeof(PlexDef));
}
plex_table->symbols[plex_table->count].name = name;
plex_table->symbols[plex_table->count].size = size;
plex_table->symbols[plex_table->count].field_ref_start = field_start;
plex_table->symbols[plex_table->count].field_count = field_count;
u32 index = (u32)plex_table->count;
plex_table->count++;
return index;
}
u32 plex_fields_add(PlexFieldsTable *fields_table, u32 plex_ref,
ValueType field) {
if (fields_table->count + 1 > fields_table->capacity) {
u32 new_capacity = fields_table->capacity * 2;
if (new_capacity < fields_table->count + 1) {
new_capacity = fields_table->count + 1;
}
fields_table->plex_refs =
realloc(fields_table->plex_refs, new_capacity * sizeof(u32));
fields_table->fields =
realloc(fields_table->fields, new_capacity * sizeof(ValueType));
fields_table->capacity = new_capacity;
}
u32 start_index = fields_table->count;
fields_table->plex_refs[start_index] = plex_ref;
fields_table->fields[start_index] = field;
fields_table->count++;
return start_index;
}
int plex_get_field_index_by_name(PlexTable *plex_table,
PlexFieldsTable *fields_table,
NamesTable *names_table, u32 plex_index,
const char *field_name) {
if (plex_index >= plex_table->count)
return -1;
PlexDef *plex_def = &plex_table->symbols[plex_index];
u32 field_start = plex_def->field_ref_start;
u32 field_count = plex_def->field_count;
for (u32 i = 0; i < field_count; i++) {
u32 field_table_index = field_start + i;
ValueType *field = &fields_table->fields[field_table_index];
if (field->name < names_table->count) {
if (strcmp(names_table->names[field->name], field_name) == 0) {
return (int)i; // Return field index within the plex
}
}
}
return -1; // Not found
}
ValueType *plex_get_field(PlexTable *plex_table, PlexFieldsTable *fields_table,
u32 plex_index, u32 field_in_plex_index) {
if (plex_index >= plex_table->count)
return nil;
PlexDef *plex_def = &plex_table->symbols[plex_index];
if (field_in_plex_index >= plex_def->field_count)
return nil;
u32 field_table_index = plex_def->field_ref_start + field_in_plex_index;
return &fields_table->fields[field_table_index];
}
ValueType *plex_get_field_by_name(PlexTable *plex_table,
PlexFieldsTable *fields_table,
NamesTable *names_table, u32 plex_index,
const char *field_name) {
int field_index = plex_get_field_index_by_name(
plex_table, fields_table, names_table, plex_index, field_name);
if (field_index == -1)
return nil;
return plex_get_field(plex_table, fields_table, plex_index, (u32)field_index);
}
Symbol *global(VM *vm) {
Symbol s;
ValueType t;
s.ref.global = vm->mp;
Token token_type = nextToken();
Token array_or_eq = nextToken();
if (array_or_eq.type == TOKEN_LBRACKET) {
Token rb = nextToken();
if (rb.type != TOKEN_RBRACKET)
return nil;
Token eq = nextToken();
if (eq.type != TOKEN_EQ)
return nil;
t.type = ARRAY;
ValueType array_type;
switch (token_type.type) {
case TOKEN_TYPE_I8:
array_type.type = I8;
break;
case TOKEN_TYPE_I16:
array_type.type = I16;
break;
case TOKEN_TYPE_INT:
array_type.type = I32;
break;
case TOKEN_TYPE_U8:
array_type.type = U8;
break;
case TOKEN_TYPE_U16:
array_type.type = U16;
break;
case TOKEN_TYPE_NAT:
array_type.type = U32;
break;
case TOKEN_TYPE_REAL:
array_type.type = F32;
break;
case TOKEN_TYPE_STR:
array_type.type = STR;
break;
case TOKEN_IDENTIFIER:
break;
default:
return nil;
}
} else {
// its not an array, so should be =
if (array_or_eq.type != TOKEN_EQ)
return nil;
switch (token_type.type) {
case TOKEN_TYPE_I8:
t.type = I8;
break;
case TOKEN_TYPE_I16:
t.type = I16;
break;
case TOKEN_TYPE_INT:
t.type = I32;
break;
case TOKEN_TYPE_U8:
t.type = U8;
break;
case TOKEN_TYPE_U16:
t.type = U16;
break;
case TOKEN_TYPE_NAT:
t.type = U32;
break;
case TOKEN_TYPE_REAL:
t.type = F32;
break;
case TOKEN_TYPE_STR:
t.type = STR;
break;
case TOKEN_IDENTIFIER:
break;
default:
return nil;
}
}
s.type = t;
Token value = nextToken();
return nil;
}
typedef struct {
Token current;
Token previous;
bool hadError;
bool panicMode;
} Parser;
typedef enum {
PREC_NONE,
PREC_ASSIGNMENT, /* = */
PREC_OR, /* or */
PREC_AND, /* and */
PREC_EQUALITY, /* == != */
PREC_COMPARISON, /* < > <= >= */
PREC_TERM, /* + - */
PREC_FACTOR, /* * / */
PREC_UNARY, /* not */
PREC_CALL, /* . () */
PREC_PRIMARY
} Precedence;
typedef void (*ParseFn)(char *program);
typedef struct {
ParseFn prefix;
ParseFn infix;
Precedence precedence;
} ParseRule;
typedef struct {
SymbolTable table;
Symbol current;
Symbol last;
i8 rp; // Next free register
} Compiler;
Parser parser;
const char *internalErrorMsg =
"FLAGRANT COMPILER ERROR\n\nCompiler over.\nBug = Very Yes.";
bool isType(TokenType type) {
return type == TOKEN_TYPE_INT || type == TOKEN_TYPE_NAT ||
type == TOKEN_TYPE_REAL || type == TOKEN_TYPE_STR ||
type == TOKEN_TYPE_BOOL;
}
void errorAt(Token *token, const char *message) {
if (parser.panicMode)
return;
parser.panicMode = true;
fprintf(stderr, "[line %d] Error", token->line);
if (token->type == TOKEN_EOF) {
fprintf(stderr, " at end");
} else if (token->type == TOKEN_ERROR) {
} else {
fprintf(stderr, " at '%.*s'", token->length, token->start);
}
fprintf(stderr, ": %s\n", message);
parser.hadError = true;
}
void error(const char *message) { errorAt(&parser.previous, message); }
void errorAtCurrent(const char *message) { errorAt(&parser.current, message); }
void advance() {
parser.previous = parser.current;
for (;;) {
parser.current = nextToken();
if (parser.current.type != TOKEN_ERROR)
break;
errorAtCurrent(parser.current.start);
}
}
void consume(TokenType type, const char *message) {
if (parser.current.type == type) {
advance();
return;
}
errorAtCurrent(message);
}
static int allocateRegister(Compiler *c) {
char buffer[38];
if (c->rp + 1 > 31) {
sprintf(buffer, "Out of registers (used %d, max 32)", c->rp + 1);
error(buffer);
return -1;
}
return c->rp++;
}
static void popRegister(Compiler *c) {
if (c->rp - 1 > 0) {
c->rp--;
}
}
static void freeRegister(Compiler *c, u8 reg) {
if (reg == c->rp - 1) {
c->rp--;
}
}
static void clearRegisters(Compiler *c, u8 reg) { c->rp = 0; }
void emit_byte(VM *vm, u8 byte) { vm->code[vm->cp++] = byte; }
void emit_u32(VM *vm, u32 value) {
write_u32(vm, code, vm->cp, value);
vm->cp += 4;
}
void emit_opcode(VM *vm, Opcode op) { emit_byte(vm, op); }
static bool check(TokenType type) { return parser.current.type == type; }
static bool match(TokenType type) {
if (!check(type))
return false;
advance();
return true;
}
static void expression(Compiler *c, VM *vm) {
USED(c);
USED(vm);
}
void number(Compiler *c, VM *vm) {
emit_opcode(vm, OP_LOAD_IMM);
int reg = allocateRegister(c);
if (reg < 0)
return;
emit_byte(vm, reg);
c->last = Symbol{ .type=parser.previous.type };
switch (parser.previous.type) {
case TOKEN_INT_LITERAL: {
char *endptr;
i32 value = (i32)strtol(parser.previous.start, &endptr, 10);
emit_u32(vm, value);
return;
}
case TOKEN_UINT_LITERAL: {
long value = atol(parser.previous.start);
emit_u32(vm, value);
return;
}
case TOKEN_FLOAT_LITERAL: {
float value = atof(parser.previous.start);
fixed_t fvalue = float_to_fixed(value);
emit_u32(vm, fvalue);
return;
}
default:
return; // Unreachable.
}
errorAtCurrent("Invalid number format");
}
static void unary(Compiler *c, VM *vm) {
TokenType operatorType = parser.previous.type;
// Compile the operand.
expression(c, vm);
// Emit the operator instruction.
switch (operatorType) {
case TOKEN_MINUS: {
switch (c->last.type) {
case TOKEN_UINT_LITERAL:
emit_opcode(vm, OP_NEG_UINT);
case TOKEN_FLOAT_LITERAL:
emit_opcode(vm, OP_NEG_FLOAT);
default:
emit_opcode(vm, OP_NEG_INT);
}
int dest = allocateRegister();
emit_byte(vm, dest);
emit_byte(vm, dest);
}
default:
return; // Unreachable.
}
}
static void emitHalt(Compiler *c, VM *vm) {
emit_opcode(vm, OP_HALT);
advance();
number(c, vm);
}
static void endCompiler(Compiler *c, VM *vm) { emitHalt(c, vm); }
static void grouping(Compiler *c, VM *vm) {
expression(c, vm);
consume(TOKEN_RPAREN, "Expect ')' after expression.");
}
bool compile(const char *source, VM *vm) {
USED(source);
USED(vm);
initLexer(source);
parser.hadError = false;
parser.panicMode = false;
Compiler compiler;
advance();
expression(&compiler, vm);
consume(TOKEN_EOF, "Expect end of expression.");
endCompiler(&compiler, vm);
return parser.hadError;
}