Update assembler to add scopes
This commit is contained in:
parent
0fd2656704
commit
4114812146
|
|
@ -89,7 +89,7 @@ void mainloop() {
|
|||
}
|
||||
|
||||
int cycles_this_frame = 0;
|
||||
int max_cycles_per_frame = 2000;
|
||||
int max_cycles_per_frame = 1000;
|
||||
while (cycles_this_frame < max_cycles_per_frame) {
|
||||
if (!step_vm(&vm)) {
|
||||
emscripten_cancel_main_loop();
|
||||
|
|
|
|||
|
|
@ -130,24 +130,29 @@ bool compileAndSave(const char *source_file, const char *output_file, VM *vm) {
|
|||
}
|
||||
|
||||
#ifdef STATIC
|
||||
#define SYMBOLS_COUNT 2048
|
||||
Symbol symbols[SYMBOLS_COUNT];
|
||||
#define SCOPES_COUNT 2048
|
||||
SymbolTable scopes[SCOPES_COUNT];
|
||||
#endif
|
||||
|
||||
void symbol_table_init(SymbolTable *t) {
|
||||
void symbol_table_init(ScopeTable *t) {
|
||||
#ifdef STATIC
|
||||
memset(symbols, 0, SYMBOLS_COUNT*sizeof(Symbol));
|
||||
t->symbols = symbols;
|
||||
memset(scopes, 0, SCOPES_COUNT*sizeof(SymbolTable));
|
||||
t->scopes = scopes;
|
||||
t->count = 0;
|
||||
t->capacity = SYMBOLS_COUNT;
|
||||
t->capacity = SCOPES_COUNT;
|
||||
#else
|
||||
t->symbols = calloc(16, sizeof(Symbol));
|
||||
t->scopes = calloc(16, sizeof(SymbolTable));
|
||||
t->count = 0;
|
||||
t->capacity = 16;
|
||||
#endif
|
||||
|
||||
// Make sure that all the parents are the 'global' namespace.
|
||||
for (u32 i = 0; i < t->capacity; i++) {
|
||||
t->scopes[i].parent = -1;
|
||||
}
|
||||
}
|
||||
|
||||
bool resize_or_check_size(SymbolTable *table) {
|
||||
bool table_realloc(ScopeTable *table) {
|
||||
#ifdef STATIC
|
||||
if (table->count >= table->capacity) {
|
||||
return false;
|
||||
|
|
@ -155,7 +160,12 @@ bool resize_or_check_size(SymbolTable *table) {
|
|||
#else
|
||||
if (table->count >= table->capacity) {
|
||||
table->capacity *= 2;
|
||||
table->symbols = realloc(table->symbols, table->capacity * sizeof(Symbol));
|
||||
table->scopes = realloc(table->scopes, table->capacity * sizeof(SymbolTable));
|
||||
|
||||
// Make sure that all the parents are the 'global' namespace.
|
||||
for (u32 i = table->count; i < table->capacity; i++) {
|
||||
table->scopes[i].parent = -1;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
return true;
|
||||
|
|
@ -183,11 +193,11 @@ bool assembleAndSave(const char *source_file, const char *output_file, VM *vm) {
|
|||
source[read] = '\0';
|
||||
fclose(f);
|
||||
|
||||
SymbolTable table = {0};
|
||||
ScopeTable table = {0};
|
||||
symbol_table_init(&table);
|
||||
assemble(vm, &table, source);
|
||||
#ifndef STATIC
|
||||
free(table.symbols);
|
||||
free(table.scopes);
|
||||
#endif
|
||||
|
||||
if (output_file) {
|
||||
|
|
|
|||
|
|
@ -162,29 +162,40 @@ void emit_u32(VM *vm, u32 value) {
|
|||
write_u32(vm, code, vm->cp, value);
|
||||
}
|
||||
|
||||
Symbol *symbol_table_lookup(SymbolTable *table, const char *name, u32 length) {
|
||||
for (u32 i = 0; i < table->count; i++) {
|
||||
if (table->symbols[i].name_length == length) {
|
||||
if (strleq(table->symbols[i].name, name, length)) {
|
||||
return &table->symbols[i];
|
||||
Symbol *symbol_table_lookup(ScopeTable *table, const char *name, u32 length,
|
||||
i32 scope_ref) {
|
||||
SymbolTable st = table->scopes[scope_ref];
|
||||
for (u32 i = 0; i < st.count; i++) {
|
||||
if (st.symbols[i].name_length == length) {
|
||||
if (strleq(st.symbols[i].name, name, length)) {
|
||||
return &table->scopes[scope_ref].symbols[i];
|
||||
}
|
||||
}
|
||||
}
|
||||
if (st.parent < 0)
|
||||
return nil;
|
||||
return symbol_table_lookup(table, name, length, st.parent);
|
||||
}
|
||||
|
||||
u32 symbol_table_add(SymbolTable *table, Symbol s) {
|
||||
Symbol *sym = symbol_table_lookup(table, s.name, s.name_length);
|
||||
u8 symbol_table_add(ScopeTable *table, Symbol s) {
|
||||
Symbol *sym =
|
||||
symbol_table_lookup(table, s.name, s.name_length, table->scope_ref);
|
||||
if (sym != nil) {
|
||||
fprintf(stderr,
|
||||
"Error: Symbol '%.*s' already defined, the assembler is not smart "
|
||||
"enough to do scope properly so please pick a different variable "
|
||||
"name (hard I know)\n",
|
||||
"Error: Symbol '%.*s' already defined, in this scope"
|
||||
" please pick a different variable name or create a new scope.\n",
|
||||
s.name_length, s.name);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
if (!resize_or_check_size(table)) {
|
||||
if (table->scopes[table->scope_ref].count + 1 > 255) {
|
||||
fprintf(stderr, "Error: Only 255 symbols are allowed per scope"
|
||||
" first off: impressive; secondly:"
|
||||
" just create a new scope and keep going.\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
if (!table_realloc(table)) {
|
||||
fprintf(stderr,
|
||||
"Error: Symbol table is out of memory! This is likely because you "
|
||||
" built the assembler in static mode, increase the static size."
|
||||
|
|
@ -203,15 +214,14 @@ u32 symbol_table_add(SymbolTable *table, Symbol s) {
|
|||
printf("code[%d] = %s\n", s.ref, s.name);
|
||||
}
|
||||
#endif
|
||||
|
||||
table->symbols[table->count] = s;
|
||||
u32 index = table->count;
|
||||
table->count++;
|
||||
table->scopes[table->scope_ref].symbols[table->scopes[table->scope_ref].count] = s;
|
||||
u8 index = table->scopes[table->scope_ref].count;
|
||||
table->scopes[table->scope_ref].count++;
|
||||
return index;
|
||||
}
|
||||
|
||||
u32 get_ref(SymbolTable *st, const char *name, u32 length) {
|
||||
Symbol *sym = symbol_table_lookup(st, name, length);
|
||||
u32 get_ref(ScopeTable *st, const char *name, u32 length) {
|
||||
Symbol *sym = symbol_table_lookup(st, name, length, st->scope_ref);
|
||||
if (!sym) {
|
||||
fprintf(stderr, "Error: Assembler has no idea what Symbol '%.*s' means.\n",
|
||||
length, name);
|
||||
|
|
@ -221,7 +231,7 @@ u32 get_ref(SymbolTable *st, const char *name, u32 length) {
|
|||
return sym->ref;
|
||||
}
|
||||
|
||||
u32 get_ptr(Token token, SymbolTable *st) {
|
||||
u32 get_ptr(Token token, ScopeTable *st) {
|
||||
if (token.type == TOKEN_IDENTIFIER) {
|
||||
return get_ref(st, token.start, token.length);
|
||||
}
|
||||
|
|
@ -246,7 +256,7 @@ u32 get_ptr(Token token, SymbolTable *st) {
|
|||
exit(1);
|
||||
}
|
||||
|
||||
u32 get_reg(Token token, SymbolTable *st) {
|
||||
u32 get_reg(Token token, ScopeTable *st) {
|
||||
if (token.type == TOKEN_IDENTIFIER) {
|
||||
return get_ref(st, token.start, token.length);
|
||||
}
|
||||
|
|
@ -303,7 +313,7 @@ Token next_token_is(TokenType type) {
|
|||
/**
|
||||
* Global .
|
||||
*/
|
||||
bool define_global(VM *vm, SymbolTable *st) {
|
||||
bool define_global(VM *vm, ScopeTable *st) {
|
||||
Symbol s;
|
||||
|
||||
Token token_type = next_token();
|
||||
|
|
@ -472,7 +482,7 @@ bool define_global(VM *vm, SymbolTable *st) {
|
|||
/**
|
||||
* Var .
|
||||
*/
|
||||
void define_var(SymbolTable *st, Token regType) {
|
||||
void define_var(ScopeTable *st, Token regType) {
|
||||
Symbol s;
|
||||
s.scope = VAR;
|
||||
switch (regType.type) {
|
||||
|
|
@ -553,7 +563,7 @@ void define_var(SymbolTable *st, Token regType) {
|
|||
/**
|
||||
* function .
|
||||
*/
|
||||
void define_function(VM *vm, SymbolTable *st) {
|
||||
void define_function(VM *vm, ScopeTable *st) {
|
||||
Symbol s;
|
||||
s.scope = LOCAL;
|
||||
s.type = FUNCTION;
|
||||
|
|
@ -570,6 +580,12 @@ void define_function(VM *vm, SymbolTable *st) {
|
|||
|
||||
next_token_is(TOKEN_LPAREN);
|
||||
|
||||
i32 temp = st->scope_ref;
|
||||
|
||||
st->count++;
|
||||
st->scopes[st->count].parent = st->scope_ref;
|
||||
st->scope_ref = (i32)st->count;
|
||||
|
||||
Token next = next_token();
|
||||
while (next.type != TOKEN_RPAREN) {
|
||||
define_var(st, next);
|
||||
|
|
@ -585,13 +601,17 @@ void define_function(VM *vm, SymbolTable *st) {
|
|||
}
|
||||
}
|
||||
s.ref = vm->cp;
|
||||
next = next_token_is(TOKEN_LBRACE);
|
||||
|
||||
st->scope_ref = temp; // need to add to the parents scope
|
||||
symbol_table_add(st, s);
|
||||
st->scope_ref = (i32)st->count;
|
||||
}
|
||||
|
||||
/**
|
||||
* Branch.
|
||||
*/
|
||||
void define_branch(VM *vm, SymbolTable *st) {
|
||||
void define_branch(VM *vm, ScopeTable *st) {
|
||||
Symbol s;
|
||||
s.scope = LOCAL;
|
||||
s.type = VOID;
|
||||
|
|
@ -702,7 +722,8 @@ int get_instruction_byte_size(const char *opname) {
|
|||
}
|
||||
|
||||
#define FAKE_OP(op) \
|
||||
} else if (strleq(token.start, op, token.length)) { \
|
||||
} \
|
||||
else if (strleq(token.start, op, token.length)) { \
|
||||
do { \
|
||||
while (token.type != TOKEN_SEMICOLON) { \
|
||||
token = next_token(); \
|
||||
|
|
@ -716,7 +737,7 @@ int get_instruction_byte_size(const char *opname) {
|
|||
/**
|
||||
* Build the symbol table and calculate the types/size/offsets of all values.
|
||||
*/
|
||||
void build_symbol_table(VM *vm, char *source, SymbolTable *st) {
|
||||
void build_symbol_table(VM *vm, char *source, ScopeTable *st) {
|
||||
Token token;
|
||||
init_lexer(source);
|
||||
do {
|
||||
|
|
@ -727,6 +748,22 @@ void build_symbol_table(VM *vm, char *source, SymbolTable *st) {
|
|||
}
|
||||
|
||||
if (token.type != TOKEN_EOF) {
|
||||
|
||||
if (token.type == TOKEN_LBRACE) {
|
||||
st->count++;
|
||||
st->scopes[st->count].parent = st->scope_ref;
|
||||
st->scope_ref = (i32)st->count;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (token.type == TOKEN_RBRACE) {
|
||||
i32 current_scope = st->scope_ref;
|
||||
i32 parent = st->scopes[current_scope].parent;
|
||||
if (parent < 0) parent = 0;
|
||||
st->scope_ref = parent;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (token.type == TOKEN_KEYWORD_GLOBAL) {
|
||||
define_global(vm, st);
|
||||
continue;
|
||||
|
|
@ -931,7 +968,7 @@ void build_symbol_table(VM *vm, char *source, SymbolTable *st) {
|
|||
/**
|
||||
* 2nd pass, emit the bytecode
|
||||
*/
|
||||
void emit_bytecode(VM *vm, char *source, SymbolTable *st) {
|
||||
void emit_bytecode(VM *vm, char *source, ScopeTable *st) {
|
||||
Token token;
|
||||
init_lexer(source);
|
||||
do {
|
||||
|
|
@ -942,6 +979,21 @@ void emit_bytecode(VM *vm, char *source, SymbolTable *st) {
|
|||
}
|
||||
if (token.type != TOKEN_EOF) {
|
||||
|
||||
if (token.type == TOKEN_LBRACE) {
|
||||
st->count++;
|
||||
st->scopes[st->count].parent = st->scope_ref;
|
||||
st->scope_ref = (i32)st->count;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (token.type == TOKEN_RBRACE) {
|
||||
i32 current_scope = st->scope_ref;
|
||||
i32 parent = st->scopes[current_scope].parent;
|
||||
if (parent < 0) parent = 0;
|
||||
st->scope_ref = parent;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (token.type == TOKEN_KEYWORD_GLOBAL) {
|
||||
/* ignore, already processed */
|
||||
next_token(); /* type */
|
||||
|
|
@ -2417,8 +2469,9 @@ void emit_bytecode(VM *vm, char *source, SymbolTable *st) {
|
|||
/**
|
||||
* Emit bytecode to the VM from the source string.
|
||||
*/
|
||||
void assemble(VM *vm, SymbolTable *st, char *source) {
|
||||
void assemble(VM *vm, ScopeTable *st, char *source) {
|
||||
build_symbol_table(vm, source, st);
|
||||
vm->cp = 0; /* actually start emitting code */
|
||||
st->count = 0;
|
||||
emit_bytecode(vm, source, st);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -26,6 +26,8 @@ typedef enum {
|
|||
|
||||
typedef struct symbol_s Symbol;
|
||||
typedef struct symbol_tab_s SymbolTable;
|
||||
typedef struct scope_tab_s ScopeTable;
|
||||
typedef struct assembler_s Assembler;
|
||||
|
||||
#define MAX_SYMBOL_NAME_LENGTH 64
|
||||
struct symbol_s {
|
||||
|
|
@ -38,13 +40,20 @@ struct symbol_s {
|
|||
};
|
||||
|
||||
struct symbol_tab_s {
|
||||
Symbol *symbols;
|
||||
u32 count;
|
||||
u32 capacity;
|
||||
Symbol symbols[256];
|
||||
u8 count;
|
||||
i32 parent;
|
||||
};
|
||||
|
||||
void assemble(VM *vm, SymbolTable *st, char *source);
|
||||
extern bool resize_or_check_size(SymbolTable *table);/* implement this in arch/ not here */
|
||||
struct scope_tab_s {
|
||||
SymbolTable *scopes;
|
||||
u32 count;
|
||||
u32 capacity;
|
||||
i32 scope_ref;
|
||||
};
|
||||
|
||||
void assemble(VM *vm, ScopeTable *st, char *source);
|
||||
extern bool table_realloc(ScopeTable *table);/* implement this in arch/ not here */
|
||||
|
||||
const char *opcode_to_string(Opcode op);
|
||||
|
||||
|
|
|
|||
|
|
@ -3,188 +3,18 @@
|
|||
#include "../../vm/common.h"
|
||||
#include "../../vm/opcodes.h"
|
||||
#include "../../vm/libc.h"
|
||||
#include "../../vm/fixed.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);
|
||||
}
|
||||
|
||||
typedef struct {
|
||||
Token current;
|
||||
Token previous;
|
||||
Token before;
|
||||
bool hadError;
|
||||
bool panicMode;
|
||||
i8 rp;
|
||||
} Parser;
|
||||
|
||||
typedef enum {
|
||||
|
|
@ -209,13 +39,6 @@ typedef struct {
|
|||
Precedence precedence;
|
||||
} ParseRule;
|
||||
|
||||
typedef struct {
|
||||
SymbolTable table;
|
||||
Symbol current;
|
||||
Symbol last;
|
||||
i8 rp; // Next free register
|
||||
} Compiler;
|
||||
|
||||
Parser parser;
|
||||
|
||||
const char *internalErrorMsg =
|
||||
|
|
@ -269,30 +92,24 @@ void consume(TokenType type, const char *message) {
|
|||
errorAtCurrent(message);
|
||||
}
|
||||
|
||||
static int allocateRegister(Compiler *c) {
|
||||
static int allocateRegister() {
|
||||
char buffer[38];
|
||||
if (c->rp + 1 > 31) {
|
||||
sprintf(buffer, "Out of registers (used %d, max 32)", c->rp + 1);
|
||||
if (parser.rp + 1 > 31) {
|
||||
sprintf(buffer, "Out of registers (used %d, max 32)", parser.rp + 1);
|
||||
error(buffer);
|
||||
return -1;
|
||||
}
|
||||
|
||||
return c->rp++;
|
||||
return parser.rp++;
|
||||
}
|
||||
|
||||
static void popRegister(Compiler *c) {
|
||||
if (c->rp - 1 > 0) {
|
||||
c->rp--;
|
||||
static void popRegister() {
|
||||
if (parser.rp - 1 > 0) {
|
||||
parser.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; }
|
||||
static void clearRegisters(u8 reg) { parser.rp = 0; }
|
||||
|
||||
void emit_byte(VM *vm, u8 byte) { vm->code[vm->cp++] = byte; }
|
||||
|
||||
|
|
@ -312,20 +129,17 @@ static bool match(TokenType type) {
|
|||
return true;
|
||||
}
|
||||
|
||||
static void expression(Compiler *c, VM *vm) {
|
||||
USED(c);
|
||||
static void expression(VM *vm) {
|
||||
USED(vm);
|
||||
}
|
||||
|
||||
void number(Compiler *c, VM *vm) {
|
||||
void number(VM *vm) {
|
||||
emit_opcode(vm, OP_LOAD_IMM);
|
||||
int reg = allocateRegister(c);
|
||||
int reg = allocateRegister();
|
||||
if (reg < 0)
|
||||
return;
|
||||
emit_byte(vm, reg);
|
||||
|
||||
c->last = Symbol{ .type=parser.previous.type };
|
||||
|
||||
switch (parser.previous.type) {
|
||||
case TOKEN_LITERAL_INT: {
|
||||
char *endptr;
|
||||
|
|
@ -351,16 +165,16 @@ void number(Compiler *c, VM *vm) {
|
|||
errorAtCurrent("Invalid number format");
|
||||
}
|
||||
|
||||
static void unary(Compiler *c, VM *vm) {
|
||||
static void unary(VM *vm) {
|
||||
TokenType operatorType = parser.previous.type;
|
||||
|
||||
// Compile the operand.
|
||||
expression(c, vm);
|
||||
expression(vm);
|
||||
|
||||
// Emit the operator instruction.
|
||||
switch (operatorType) {
|
||||
case TOKEN_MINUS: {
|
||||
switch (c->last.type) {
|
||||
switch (parser.previous.type) {
|
||||
case TOKEN_LITERAL_NAT:
|
||||
emit_opcode(vm, OP_NEG_NAT);
|
||||
case TOKEN_LITERAL_REAL:
|
||||
|
|
@ -378,16 +192,16 @@ static void unary(Compiler *c, VM *vm) {
|
|||
}
|
||||
}
|
||||
|
||||
static void emitHalt(Compiler *c, VM *vm) {
|
||||
static void emitHalt(VM *vm) {
|
||||
emit_opcode(vm, OP_EXIT);
|
||||
advance();
|
||||
number(c, vm);
|
||||
number(vm);
|
||||
}
|
||||
|
||||
static void endCompiler(Compiler *c, VM *vm) { emitHalt(c, vm); }
|
||||
static void endCompiler(VM *vm) { emitHalt(vm); }
|
||||
|
||||
static void grouping(Compiler *c, VM *vm) {
|
||||
expression(c, vm);
|
||||
static void grouping(VM *vm) {
|
||||
expression(vm);
|
||||
consume(TOKEN_RPAREN, "Expect ')' after expression.");
|
||||
}
|
||||
|
||||
|
|
@ -399,11 +213,10 @@ bool compile(const char *source, VM *vm) {
|
|||
parser.hadError = false;
|
||||
parser.panicMode = false;
|
||||
|
||||
Compiler compiler;
|
||||
advance();
|
||||
expression(&compiler, vm);
|
||||
expression(vm);
|
||||
consume(TOKEN_EOF, "Expect end of expression.");
|
||||
endCompiler(&compiler, vm);
|
||||
endCompiler(vm);
|
||||
|
||||
return parser.hadError;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
#include <string.h>
|
||||
|
||||
#include "../../vm/common.h"
|
||||
#include "lexer.h"
|
||||
#include "parser.h"
|
||||
|
||||
typedef struct {
|
||||
const char *start;
|
||||
|
|
|
|||
|
|
@ -16,6 +16,8 @@ typedef enum {
|
|||
TOKEN_TYPE_NAT,
|
||||
TOKEN_TYPE_REAL,
|
||||
TOKEN_TYPE_STR,
|
||||
TOKEN_TYPE_BOOL,
|
||||
TOKEN_TYPE_VOID,
|
||||
TOKEN_KEYWORD_PLEX,
|
||||
TOKEN_KEYWORD_FN,
|
||||
TOKEN_KEYWORD_CONST,
|
||||
|
|
@ -35,6 +37,8 @@ typedef enum {
|
|||
TOKEN_KEYWORD_WRITE,
|
||||
TOKEN_KEYWORD_REFRESH,
|
||||
TOKEN_KEYWORD_CLOSE,
|
||||
TOKEN_KEYWORD_LOOP,
|
||||
TOKEN_KEYWORD_DO,
|
||||
TOKEN_KEYWORD_NIL,
|
||||
TOKEN_KEYWORD_TRUE,
|
||||
TOKEN_KEYWORD_FALSE,
|
||||
|
|
|
|||
|
|
@ -3,20 +3,22 @@ global str new_line = "\n";
|
|||
global int x = 1;
|
||||
global int y = 1;
|
||||
|
||||
function main ()
|
||||
function main () {
|
||||
load_absolute_32 x -> $0;
|
||||
load_absolute_32 y -> $1;
|
||||
call add ($0 $1) -> $2;
|
||||
int_to_string $2 -> $3;
|
||||
call pln ($3);
|
||||
exit 0;
|
||||
}
|
||||
|
||||
function add (int a $0, int b $1)
|
||||
function add (int a $0, int b $1) {
|
||||
int result $2;
|
||||
add_int a b -> result;
|
||||
return result;
|
||||
}
|
||||
|
||||
function pln (str message $0)
|
||||
function pln (str message $0) {
|
||||
plex term $1;
|
||||
int msg_length $2;
|
||||
str nl $3;
|
||||
|
|
@ -33,3 +35,4 @@ function pln (str message $0)
|
|||
string_length nl -> nl_length;
|
||||
syscall WRITE term nl nl_length;
|
||||
return;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
global str terminal_namespace = "/dev/term/0";
|
||||
global str new_line = "\n";
|
||||
|
||||
function main ()
|
||||
function main () {
|
||||
int str_n $1;
|
||||
|
||||
load_immediate 35 -> $0;
|
||||
|
|
@ -9,8 +9,9 @@ function main ()
|
|||
int_to_string $0 -> str_n;
|
||||
call pln (str_n);
|
||||
exit 0;
|
||||
}
|
||||
|
||||
function fib (int n $0)
|
||||
function fib (int n $0) {
|
||||
load_immediate 2 -> $1;
|
||||
|
||||
jump_lt_int base_case n $1;
|
||||
|
|
@ -28,8 +29,9 @@ function fib (int n $0)
|
|||
|
||||
else base_case;
|
||||
return n;
|
||||
}
|
||||
|
||||
function pln (str message $0)
|
||||
function pln (str message $0) {
|
||||
plex term $1;
|
||||
int msg_length $2;
|
||||
str nl $3;
|
||||
|
|
@ -46,4 +48,4 @@ function pln (str message $0)
|
|||
string_length nl -> nl_length;
|
||||
syscall WRITE term nl nl_length;
|
||||
return;
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,14 +2,15 @@ global str terminal_namespace = "/dev/term/0";
|
|||
global str new_line = "\n";
|
||||
global str hello = "nuqneH 'u'?";
|
||||
|
||||
function main ()
|
||||
function main () {
|
||||
str msg $0;
|
||||
|
||||
load_address hello -> msg;
|
||||
call pln (msg);
|
||||
exit 0;
|
||||
}
|
||||
|
||||
function pln (str message $0)
|
||||
function pln (str message $0) {
|
||||
plex term $1;
|
||||
int msg_length $2;
|
||||
str nl $3;
|
||||
|
|
@ -26,3 +27,4 @@ function pln (str message $0)
|
|||
string_length nl -> nl_length;
|
||||
syscall WRITE term nl nl_length;
|
||||
return;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,36 +2,38 @@ global str terminal_namespace = "/dev/term/0";
|
|||
global str prompt = "Enter a string:";
|
||||
global str new_line = "\n";
|
||||
|
||||
function main ()
|
||||
function main () {
|
||||
real a $0;
|
||||
int i $1;
|
||||
int in_mode $11;
|
||||
str in_term $10;
|
||||
int mode $11;
|
||||
str term $10;
|
||||
|
||||
// do (i = 5000; i >= 0, i = i - 1)
|
||||
load_immediate 5.0 -> a;
|
||||
load_immediate 5000 -> i;
|
||||
load_immediate 0 -> $2;
|
||||
load_immediate -1 -> $3;
|
||||
load_immediate 5.0 -> $5;
|
||||
loop loop_body
|
||||
loop loop_body {
|
||||
add_real a $5 -> a;
|
||||
add_int i $3 -> i;
|
||||
jump_ge_int loop_body i $2;
|
||||
}
|
||||
|
||||
load_address terminal_namespace -> in_term;
|
||||
load_immediate 0 -> in_mode;
|
||||
syscall OPEN in_term in_mode in_term; // Terminal term = open("/dev/term/0", 0);
|
||||
load_address terminal_namespace -> term;
|
||||
load_immediate 0 -> mode;
|
||||
syscall OPEN term mode term; // Terminal term = open("/dev/term/0", 0);
|
||||
|
||||
nat b $1;
|
||||
real_to_nat a -> b;
|
||||
load_address prompt -> $7;
|
||||
string_length $7 -> $8;
|
||||
syscall WRITE in_term $7 $8; // print prompt
|
||||
syscall WRITE term $7 $8; // print prompt
|
||||
|
||||
str user_string $9;
|
||||
load_immediate 32 -> $8;
|
||||
malloc $8 -> user_string;
|
||||
syscall READ in_term user_string $8; // read in max 32 byte string
|
||||
syscall READ term user_string $8; // read in max 32 byte string
|
||||
|
||||
call pln (user_string);
|
||||
nat_to_string b -> $4;
|
||||
|
|
@ -39,8 +41,9 @@ function main ()
|
|||
real_to_string a -> $3;
|
||||
call pln ($3);
|
||||
exit 0;
|
||||
}
|
||||
|
||||
function pln (str message $0)
|
||||
function pln (str message $0) {
|
||||
plex term $1;
|
||||
int msg_length $2;
|
||||
str nl $3;
|
||||
|
|
@ -56,3 +59,4 @@ function pln (str message $0)
|
|||
string_length nl -> nl_length;
|
||||
syscall WRITE term nl nl_length;
|
||||
return;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,27 +2,28 @@ global str terminal_namespace = "/dev/term/0";
|
|||
global str prompt = "Enter a string:";
|
||||
global str new_line = "\n";
|
||||
|
||||
function main ()
|
||||
int in_mode $11;
|
||||
str in_term $10;
|
||||
function main () {
|
||||
int mode $11;
|
||||
str term $10;
|
||||
|
||||
load_address terminal_namespace -> in_term;
|
||||
load_immediate 0 -> in_mode;
|
||||
syscall OPEN in_term in_mode in_term; // Terminal term = open("/dev/term/0", 0);
|
||||
load_address terminal_namespace -> term;
|
||||
load_immediate 0 -> mode;
|
||||
syscall OPEN term mode term; // Terminal term = open("/dev/term/0", 0);
|
||||
|
||||
load_address prompt -> $7;
|
||||
string_length $7 -> $8;
|
||||
syscall WRITE in_term $7 $8; // print prompt
|
||||
syscall WRITE term $7 $8; // print prompt
|
||||
|
||||
str user_string $9;
|
||||
load_immediate 32 -> $8;
|
||||
malloc $8 -> user_string;
|
||||
syscall READ in_term user_string $8; // read in max 32 byte string
|
||||
syscall READ term user_string $8; // read in max 32 byte string
|
||||
|
||||
call pln (user_string);
|
||||
exit 0;
|
||||
}
|
||||
|
||||
function pln (str message $0)
|
||||
function pln (str message $0) {
|
||||
plex term $1;
|
||||
int msg_length $2;
|
||||
str nl $3;
|
||||
|
|
@ -39,4 +40,4 @@ function pln (str message $0)
|
|||
string_length nl -> nl_length;
|
||||
syscall WRITE term nl nl_length;
|
||||
return;
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@ global byte GRAY = 146;
|
|||
global byte LIGHT_GRAY = 182;
|
||||
global byte SELECTED_COLOR = 255;
|
||||
|
||||
function main ()
|
||||
function main () {
|
||||
// Open screen
|
||||
plex screen $0;
|
||||
str screen_name $18;
|
||||
|
|
@ -51,7 +51,7 @@ function main ()
|
|||
|
||||
nat m_zero $11;
|
||||
|
||||
loop draw_loop
|
||||
loop draw_loop {
|
||||
// load mouse click data
|
||||
syscall REFRESH mouse;
|
||||
|
||||
|
|
@ -93,12 +93,13 @@ function main ()
|
|||
call draw_box (screen_buffer width selected_color mouse_x mouse_y brush_size brush_size);
|
||||
|
||||
jump draw_loop;
|
||||
}
|
||||
|
||||
// Flush and exit
|
||||
exit 0;
|
||||
|
||||
function set_color_if_clicked (int click_x $0, int click_y $1,
|
||||
int box_x $2, int box_y $3, byte check_color $4, int bsize $5)
|
||||
int box_x $2, int box_y $3, byte check_color $4, int bsize $5) {
|
||||
|
||||
// Compute right
|
||||
int right_edge $6;
|
||||
|
|
@ -118,9 +119,10 @@ function set_color_if_clicked (int click_x $0, int click_y $1,
|
|||
|
||||
else fail
|
||||
return;
|
||||
}
|
||||
|
||||
function draw_outlined_swatch(nat dos_base $0,
|
||||
byte swatch_color $1, int x $2, int y $3, int dos_width $4)
|
||||
byte swatch_color $1, int x $2, int y $3, int dos_width $4) {
|
||||
|
||||
// Constants
|
||||
nat background_color $5;
|
||||
|
|
@ -152,10 +154,11 @@ function draw_outlined_swatch(nat dos_base $0,
|
|||
call draw_box (dos_base dos_width swatch_color $9 $10 fill_size fill_size);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
function draw_box (nat db_base $0, nat screen_width $1,
|
||||
byte box_color $2, nat x_start $3, nat y_start $4,
|
||||
nat db_width $5, nat height $6)
|
||||
nat db_width $5, nat height $6) {
|
||||
|
||||
// Compute start address: base + y*640 + x
|
||||
nat offset $15;
|
||||
|
|
@ -172,9 +175,11 @@ function draw_box (nat db_base $0, nat screen_width $1,
|
|||
int zero $26;
|
||||
load_immediate 0 -> zero;
|
||||
|
||||
loop draw_box_outer
|
||||
loop draw_box_outer {
|
||||
memset_8 box_color db_width -> offset; // draw row
|
||||
add_int offset screen_width -> offset; // next row += 640
|
||||
sub_int height i -> height; // decrement row count
|
||||
jump_gt_int draw_box_outer height zero;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
|
@ -34,7 +34,7 @@ global byte DARK_ORANGE = 208;
|
|||
global byte GOLD = 244;
|
||||
global byte SELECTED_COLOR = 255;
|
||||
|
||||
function main ()
|
||||
function main () {
|
||||
// Open screen
|
||||
plex screen $0;
|
||||
str screen_name $18;
|
||||
|
|
@ -118,14 +118,14 @@ function main ()
|
|||
|
||||
nat m_zero $11;
|
||||
|
||||
loop draw_loop
|
||||
loop draw_loop {
|
||||
// load mouse click data
|
||||
syscall REFRESH mouse;
|
||||
|
||||
byte left_down $9;
|
||||
load_offset_8 mouse 16 -> left_down; // load btn1 pressed
|
||||
|
||||
jump_eq_nat draw_loop left_down m_zero;
|
||||
jump_eq_nat draw_loop left_down m_zero; // if (!btn1.left) continue;
|
||||
|
||||
nat mouse_x $7;
|
||||
nat mouse_y $8;
|
||||
|
|
@ -207,12 +207,14 @@ function main ()
|
|||
call draw_box (screen_buffer width selected_color mouse_x mouse_y brush_size brush_size);
|
||||
|
||||
jump draw_loop;
|
||||
}
|
||||
|
||||
// Flush and exit
|
||||
exit 0;
|
||||
}
|
||||
|
||||
function set_color_if_clicked (int click_x $0, int click_y $1,
|
||||
int box_x $2, int box_y $3, byte check_color $4, int bsize $5)
|
||||
int box_x $2, int box_y $3, byte check_color $4, int bsize $5) {
|
||||
|
||||
// Compute right
|
||||
int right_edge $6;
|
||||
|
|
@ -232,9 +234,10 @@ function set_color_if_clicked (int click_x $0, int click_y $1,
|
|||
|
||||
else fail
|
||||
return;
|
||||
}
|
||||
|
||||
function draw_outlined_swatch(nat dos_base $0,
|
||||
byte swatch_color $1, int x $2, int y $3, int dos_width $4)
|
||||
byte swatch_color $1, int x $2, int y $3, int dos_width $4) {
|
||||
|
||||
// Constants
|
||||
nat background_color $5;
|
||||
|
|
@ -266,10 +269,11 @@ function draw_outlined_swatch(nat dos_base $0,
|
|||
call draw_box (dos_base dos_width swatch_color $9 $10 fill_size fill_size);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
function draw_box (nat db_base $0, nat screen_width $1,
|
||||
byte box_color $2, nat x_start $3, nat y_start $4,
|
||||
nat db_width $5, nat height $6)
|
||||
nat db_width $5, nat height $6) {
|
||||
|
||||
// Compute start address: base + y*640 + x
|
||||
nat offset $15;
|
||||
|
|
@ -286,9 +290,11 @@ function draw_box (nat db_base $0, nat screen_width $1,
|
|||
int zero $26;
|
||||
load_immediate 0 -> zero;
|
||||
|
||||
loop draw_box_outer
|
||||
loop draw_box_outer {
|
||||
memset_8 box_color db_width -> offset; // draw row
|
||||
add_int offset screen_width -> offset; // next row += 640
|
||||
sub_int height i -> height; // decrement row count
|
||||
jump_gt_int draw_box_outer height zero;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
|
@ -1,15 +1,16 @@
|
|||
global str terminal_namespace = "/dev/term/0";
|
||||
global str new_line = "\n";
|
||||
|
||||
function main ()
|
||||
function main () {
|
||||
load_immediate 1.0 -> $0;
|
||||
load_immediate 2.0 -> $1;
|
||||
add_real $0 $1 -> $0;
|
||||
real_to_string $0 -> $0;
|
||||
call pln ($0);
|
||||
exit 0;
|
||||
}
|
||||
|
||||
function pln (str message $0)
|
||||
function pln (str message $0) {
|
||||
plex term $1;
|
||||
int msg_length $2;
|
||||
str nl $3;
|
||||
|
|
@ -26,3 +27,4 @@ function pln (str message $0)
|
|||
string_length nl -> nl_length;
|
||||
syscall WRITE term nl nl_length;
|
||||
return;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@ global str terminal_namespace = "/dev/term/0";
|
|||
global str new_line = "\n";
|
||||
global byte WHITE = 255;
|
||||
|
||||
function main ()
|
||||
function main () {
|
||||
plex screen $0;
|
||||
plex mouse $1;
|
||||
str tmp_str $2;
|
||||
|
|
@ -47,13 +47,13 @@ function main ()
|
|||
|
||||
syscall WRITE screen screen_buffer buffer_size; // redraw
|
||||
|
||||
loop draw_loop
|
||||
loop draw_loop {
|
||||
// load mouse click data
|
||||
syscall REFRESH mouse;
|
||||
|
||||
load_offset_8 mouse 16 -> left_down;
|
||||
|
||||
jump_eq_nat draw_loop left_down mode; // mode = 0 / false
|
||||
jump_eq_nat draw_loop left_down mode; // if (!left_down) continue;
|
||||
|
||||
load_offset_32 mouse 8 -> x;
|
||||
load_offset_32 mouse 12 -> y;
|
||||
|
|
@ -71,9 +71,12 @@ function main ()
|
|||
syscall WRITE screen screen_buffer buffer_size; // redraw
|
||||
|
||||
jump draw_loop;
|
||||
exit 0;
|
||||
}
|
||||
|
||||
function pln (str message $0)
|
||||
exit 0;
|
||||
}
|
||||
|
||||
function pln (str message $0) {
|
||||
plex term $1;
|
||||
int msg_length $2;
|
||||
str nl $3;
|
||||
|
|
@ -90,3 +93,4 @@ function pln (str message $0)
|
|||
string_length nl -> nl_length;
|
||||
syscall WRITE term nl nl_length;
|
||||
return;
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue