diff --git a/src/tools/assembler/assembler.h b/src/tools/assembler/assembler.h index 95edd43..ba2492d 100644 --- a/src/tools/assembler/assembler.h +++ b/src/tools/assembler/assembler.h @@ -27,7 +27,6 @@ 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 { diff --git a/src/tools/compiler/compiler.c b/src/tools/compiler/compiler.c index 04e6ae0..cc1890a 100644 --- a/src/tools/compiler/compiler.c +++ b/src/tools/compiler/compiler.c @@ -1,222 +1,2339 @@ +#include "../../vm/common.h" +#include "../../vm/fixed.h" +#include "../../vm/libc.h" +#include "../../vm/opcodes.h" + #include "parser.h" #include "compiler.h" -#include "../../vm/common.h" -#include "../../vm/opcodes.h" -#include "../../vm/libc.h" -#include "../../vm/fixed.h" + +/* FIXME: remove these and replace with libc.h instead */ #include #include #include -typedef struct { - Token current; - Token previous; - Token before; - bool hadError; - bool panicMode; - i8 rp; -} 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; - -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 emit_op(VM *vm, u8 byte) { + vm->code[vm->cp] = byte; } -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 emit_byte(VM *vm, u8 byte) { + vm->code[vm->cp] = byte; } -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 = next_token(); - 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() { - char buffer[38]; - if (parser.rp + 1 > 31) { - sprintf(buffer, "Out of registers (used %d, max 32)", parser.rp + 1); - error(buffer); - return -1; - } - - return parser.rp++; -} - -static void popRegister() { - if (parser.rp - 1 > 0) { - parser.rp--; - } -} - -static void clearRegisters(u8 reg) { parser.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); } +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); +} -static bool check(TokenType type) { return parser.current.type == type; } +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, in this scope" + " please pick a different variable name or create a new scope.\n", + s.name_length, s.name); + exit(1); + } -static bool match(TokenType type) { - if (!check(type)) + 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." + " if you built using malloc, that means your computer is out of" + " memory. Close a few tabs in your web browser and try again." + " Count was %d, while capacity was %d\n", + table->count, table->capacity); + exit(1); + } +#ifdef DEBUG_PRINT + if (s.scope == VAR) { + printf("$%d = %s\n", s.ref, s.name); + } else if (s.scope == GLOBAL) { + printf("memory[%d] = %s\n", s.ref, s.name); + } else { + printf("code[%d] = %s\n", s.ref, s.name); + } +#endif + 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(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); + exit(1); + return 0; + } + return sym->ref; +} + +u32 get_ptr(Token token, ScopeTable *st) { + if (token.type == TOKEN_IDENTIFIER) { + return get_ref(st, token.start, token.length); + } + + if (token.type == TOKEN_LITERAL_INT) { + return atoi(token.start); + } + + if (token.type == TOKEN_LITERAL_NAT) { + char *endptr; + u32 out = (u32)strtoul(token.start, &endptr, 10); + if (endptr == token.start || *endptr != '\0') { + fprintf(stderr, "Invalid decimal literal at line %d: %.*s\n", token.line, + token.length, token.start); + exit(1); + } + return out; + } + + fprintf(stderr, "Error: Not a pointer or symbol at line %d: %.*s\n", + token.line, token.length, token.start); + exit(1); +} + +u32 get_reg(Token token, ScopeTable *st) { + if (token.type == TOKEN_IDENTIFIER) { + return get_ref(st, token.start, token.length); + } + + if (token.type == TOKEN_BIG_MONEY) { + token = next_token(); + return atoi(token.start); + } + + fprintf(stderr, "Error: Not a register or symbol at line %d: %.*s\n", + token.line, token.length, token.start); + exit(1); +} + +Token next_id_or_reg() { + Token token = next_token(); + if (token.type == TOKEN_IDENTIFIER) { + return token; + } + + if (token.type == TOKEN_BIG_MONEY) { + token = next_token(); + return token; + } + + printf("Not an ID or register at line %d: %.*s\n", token.line, token.length, + token.start); + exit(1); + + return token; +} + +Token next_id_or_ptr() { + Token token = next_token(); + + if (token.type != TOKEN_IDENTIFIER && token.type != TOKEN_LITERAL_NAT && + token.type != TOKEN_LITERAL_INT && token.type != TOKEN_LITERAL_REAL) { + printf("Not an ID or register at line %d: %.*s\n", token.line, token.length, + token.start); + exit(1); + } + return token; +} + +Token next_token_is(TokenType type) { + Token token = next_token(); + if (token.type != type) { + printf("ERROR at line %d: %.*s\n", token.line, token.length, token.start); + exit(1); + } + return token; +} + +/** + * Global . + */ +bool define_global(VM *vm, ScopeTable *st) { + Symbol s; + + Token token_type = next_token(); + switch (token_type.type) { + case TOKEN_TYPE_BOOL: + s.type = BOOL; + s.size = 1; + break; + case TOKEN_TYPE_I8: + s.type = I8; + s.size = 1; + break; + case TOKEN_TYPE_U8: + s.type = U8; + s.size = 1; + break; + case TOKEN_TYPE_I16: + s.type = I16; + s.size = 2; + break; + case TOKEN_TYPE_U16: + s.type = U16; + s.size = 2; + break; + case TOKEN_TYPE_INT: + s.type = I32; + s.size = 4; + break; + case TOKEN_TYPE_NAT: + s.type = U32; + s.size = 4; + break; + case TOKEN_TYPE_REAL: + s.type = F32; + s.size = 4; + break; + case TOKEN_TYPE_STR: + s.type = STR; + break; + case TOKEN_IDENTIFIER: + break; + default: return false; - advance(); + } + + Token name = next_token_is(TOKEN_IDENTIFIER); + if (name.length > MAX_SYMBOL_NAME_LENGTH) { + return false; + } + + memcpy(s.name, name.start, name.length); + s.name_length = name.length; + s.name[name.length] = '\0'; + + u32 addr = vm->mp; + s.ref = addr; + s.scope = GLOBAL; + + next_token_is(TOKEN_EQ); + + Token value = next_token(); + switch (value.type) { + case TOKEN_KEYWORD_TRUE: { + u32 addr = vm->mp; + write_u8(vm, memory, addr, 1); + + vm->mp += s.size; + vm->frames[vm->fp].end += s.size; + break; + } + case TOKEN_KEYWORD_FALSE: { + u32 addr = vm->mp; + write_u8(vm, memory, addr, 0); + + vm->mp += s.size; + vm->frames[vm->fp].end += s.size; + break; + } + case TOKEN_LITERAL_INT: { + i32 out = atoi(value.start); + + u32 addr = vm->mp; + write_u32(vm, memory, addr, out); + + vm->mp += s.size; + vm->frames[vm->fp].end += s.size; + break; + } + case TOKEN_LITERAL_NAT: { + char *endptr; + u32 out = (u32)strtoul(value.start, &endptr, 10); + if (endptr == value.start || *endptr != '\0') { + fprintf(stderr, "Invalid decimal literal: %s\n", value.start); + exit(1); + } + + u32 addr = vm->mp; + write_u32(vm, memory, addr, out); + + vm->mp += s.size; + vm->frames[vm->fp].end += s.size; + break; + } + case TOKEN_LITERAL_REAL: { + fixed_t out = float_to_fixed(atof(value.start)); + + u32 addr = vm->mp; + write_u32(vm, memory, addr, out); + + vm->mp += s.size; + vm->frames[vm->fp].end += s.size; + break; + } + case TOKEN_LITERAL_STR: { + const char *src = value.start; + i32 len = 0; + i32 i = 0; + + while (i < value.length) { + char c = src[i++]; + if (c == '"') { + continue; + } + if (c == '\\' && i < value.length) { + switch (src[i++]) { + case 'n': + c = '\n'; + break; + case 't': + c = '\t'; + break; + case 'r': + c = '\r'; + break; + case '\\': + case '"': + case '\'': + break; + default: + i--; /* Rewind for unknown escapes */ + } + } + write_u8(vm, memory, addr + 4 + len, c); + len++; + } + + u32 size = len + 5; /* 4 (len) + dst_len + 1 (null) */ + s.size = size; + + vm->mp += size; + vm->frames[vm->fp].end += size; + + write_u32(vm, memory, addr, len); + write_u8(vm, memory, addr + 4 + len, '\0'); + break; + } + default: + return false; + } + next_token_is(TOKEN_SEMICOLON); + + symbol_table_add(st, s); return true; } -static void expression(VM *vm) { - USED(vm); -} - -void number(VM *vm) { - emit_opcode(vm, OP_LOAD_IMM); - int reg = allocateRegister(); - if (reg < 0) - return; - emit_byte(vm, reg); - - switch (parser.previous.type) { - case TOKEN_LITERAL_INT: { - char *endptr; - i32 value = (i32)strtol(parser.previous.start, &endptr, 10); - emit_u32(vm, value); - return; +/** + * Var . + */ +void define_var(ScopeTable *st, Token regType) { + Symbol s; + s.scope = VAR; + switch (regType.type) { + case TOKEN_KEYWORD_PLEX: { + s.type = PLEX; + s.size = 4; /* not really this type, pointer alias which is 4 */ + break; } - case TOKEN_LITERAL_NAT: { - long value = atol(parser.previous.start); - emit_u32(vm, value); - return; + case TOKEN_TYPE_I8: { + s.type = I8; + s.size = 1; + break; } - case TOKEN_LITERAL_REAL: { - float value = atof(parser.previous.start); - fixed_t fvalue = float_to_fixed(value); - emit_u32(vm, fvalue); - return; + case TOKEN_TYPE_I16: { + s.type = I16; + s.size = 2; + break; + } + case TOKEN_TYPE_INT: { + s.type = I32; + s.size = 4; + break; + } + case TOKEN_TYPE_U8: { + s.type = U8; + s.size = 1; + break; + } + case TOKEN_TYPE_U16: { + s.type = U16; + s.size = 2; + break; + } + case TOKEN_TYPE_NAT: { + s.type = U32; + s.size = 4; + break; + } + case TOKEN_TYPE_REAL: { + s.type = F32; + s.size = 4; + break; + } + case TOKEN_TYPE_BOOL: { + s.type = BOOL; + s.size = 1; + break; + } + case TOKEN_TYPE_STR: { + s.type = STR; + s.size = 4; /* not really this type, pointer alias which is 4 */ + break; } default: - return; // Unreachable. + printf("ERROR at line %d: %.*s\n", regType.line, regType.length, + regType.start); + exit(1); } - errorAtCurrent("Invalid number format"); + Token name = next_token_is(TOKEN_IDENTIFIER); + if (name.length > MAX_SYMBOL_NAME_LENGTH) { + printf("VARIABLE NAME TOO LONG at line %d: %.*s\n", regType.line, + regType.length, regType.start); + exit(1); + } + + memcpy(s.name, name.start, name.length); + s.name[name.length] = '\0'; + s.name_length = name.length; + + next_token_is(TOKEN_BIG_MONEY); + + Token reg_num = next_token_is(TOKEN_LITERAL_INT); + s.ref = atoi(reg_num.start); + symbol_table_add(st, s); } -static void unary(VM *vm) { - TokenType operatorType = parser.previous.type; +/** + * function . + */ +void define_function(VM *vm, ScopeTable *st) { + Symbol s; + s.scope = LOCAL; + s.type = FUNCTION; - // Compile the operand. - expression(vm); + Token name = next_token_is(TOKEN_IDENTIFIER); + if (name.length > MAX_SYMBOL_NAME_LENGTH) { + printf("FUNCITON NAME TOO LONG at line %d: %.*s\n", name.line, name.length, + name.start); + exit(1); + } + memcpy(s.name, name.start, name.length); + s.name[name.length] = '\0'; + s.name_length = name.length; - // Emit the operator instruction. - switch (operatorType) { - case TOKEN_MINUS: { - switch (parser.previous.type) { - case TOKEN_LITERAL_NAT: - emit_opcode(vm, OP_NEG_NAT); - case TOKEN_LITERAL_REAL: - emit_opcode(vm, OP_NEG_REAL); - default: - emit_opcode(vm, OP_NEG_INT); + 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); + next = next_token(); + if (next.type == TOKEN_COMMA) { + next = next_token(); + continue; + } else if (next.type == TOKEN_RPAREN) { + break; + } else { + printf("ERROR at line %d: %.*s\n", next.line, next.length, next.start); + exit(1); + } + } + 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, ScopeTable *st) { + Symbol s; + s.scope = LOCAL; + s.type = VOID; + + Token name = next_token_is(TOKEN_IDENTIFIER); + if (name.length > MAX_SYMBOL_NAME_LENGTH) { + printf("BRANCH NAME TOO LONG at line %d: %.*s\n", name.line, name.length, + name.start); + exit(1); + } + memcpy(s.name, name.start, name.length); + s.name_length = name.length; + s.name[name.length] = '\0'; + + s.ref = vm->cp; + symbol_table_add(st, s); +} + +int get_instruction_byte_size(const char *opname) { + + if (strcmp(opname, "return") == 0) { + return 2; + } + + if (strcmp(opname, "neg_int") == 0 || strcmp(opname, "abs_int") == 0 || + strcmp(opname, "neg_nat") == 0 || strcmp(opname, "abs_nat") == 0 || + strcmp(opname, "neg_real") == 0 || strcmp(opname, "abs_real") == 0 || + strcmp(opname, "int_to_string") == 0 || + strcmp(opname, "load_indirect_8") == 0 || + strcmp(opname, "nat_to_string") == 0 || + strcmp(opname, "load_indirect_16") == 0 || + strcmp(opname, "real_to_string") == 0 || + strcmp(opname, "load_indirect_32") == 0 || + strcmp(opname, "int_to_real") == 0 || + strcmp(opname, "store_indirect_8") == 0 || + strcmp(opname, "nat_to_real") == 0 || + strcmp(opname, "store_indirect_16") == 0 || + strcmp(opname, "real_to_int") == 0 || + strcmp(opname, "store_indirect_32") == 0 || + strcmp(opname, "real_to_nat") == 0 || strcmp(opname, "nat_to_int") == 0 || + strcmp(opname, "int_to_nat") == 0 || + strcmp(opname, "string_length") == 0 || strcmp(opname, "memset") == 0 || + strcmp(opname, "memset") == 0 || strcmp(opname, "memset_8") == 0 || + strcmp(opname, "memset_16") == 0 || + strcmp(opname, "register_move") == 0 || strcmp(opname, "malloc") == 0) { + return 3; + } + + if (strcmp(opname, "add_int") == 0 || strcmp(opname, "sub_int") == 0 || + strcmp(opname, "mul_int") == 0 || strcmp(opname, "div_int") == 0 || + strcmp(opname, "add_nat") == 0 || strcmp(opname, "sub_nat") == 0 || + strcmp(opname, "mul_nat") == 0 || strcmp(opname, "div_nat") == 0 || + strcmp(opname, "add_real") == 0 || strcmp(opname, "sub_real") == 0 || + strcmp(opname, "bit_shift_left") == 0 || + strcmp(opname, "bit_shift_right") == 0 || + strcmp(opname, "bit_shift_r_ext") == 0 || + strcmp(opname, "bit_and") == 0 || strcmp(opname, "bit_or") == 0 || + strcmp(opname, "bit_xor") == 0 || strcmp(opname, "mul_real") == 0 || + strcmp(opname, "div_real") == 0) { + return 4; + } + + if (strcmp(opname, "halt") == 0 || strcmp(opname, "jump_if_flag") == 0 || + strcmp(opname, "jump") == 0) { + return 5; + } + + if (strcmp(opname, "load_absolute_32") == 0 || + strcmp(opname, "load_immediate") == 0 || + strcmp(opname, "load_address") == 0 || + strcmp(opname, "load_absolute_16") == 0 || + strcmp(opname, "load_absolute_8") == 0 || + strcmp(opname, "store_absolute_32") == 0 || + strcmp(opname, "store_absolute_8") == 0 || + strcmp(opname, "store_absolute_16") == 0) { + return 6; + } + + if (strcmp(opname, "jump_eq_int") == 0 || + strcmp(opname, "jump_neq_int") == 0 || + strcmp(opname, "jump_gt_int") == 0 || + strcmp(opname, "jump_lt_int") == 0 || + strcmp(opname, "jump_le_int") == 0 || + strcmp(opname, "jump_ge_int") == 0 || + strcmp(opname, "jump_eq_nat") == 0 || + strcmp(opname, "jump_neq_nat") == 0 || + strcmp(opname, "jump_gt_nat") == 0 || + strcmp(opname, "jump_lt_nat") == 0 || + strcmp(opname, "jump_le_nat") == 0 || + strcmp(opname, "jump_ge_nat") == 0 || + strcmp(opname, "jump_eq_real") == 0 || + strcmp(opname, "jump_neq_real") == 0 || + strcmp(opname, "jump_gt_real") == 0 || + strcmp(opname, "jump_lt_real") == 0 || + strcmp(opname, "jump_le_real") == 0 || + strcmp(opname, "jump_ge_real") == 0 || + strcmp(opname, "store_offset_8") == 0 || + strcmp(opname, "store_offset_16") == 0 || + strcmp(opname, "store_offset_32") == 0 || + strcmp(opname, "load_offset_8") == 0 || + strcmp(opname, "load_offset_16") == 0 || + strcmp(opname, "load_offset_32") == 0) { + return 7; + } + + fprintf(stderr, "Unknown opcode for sizing: %s\n", opname); + exit(-1); +} + +#define FAKE_OP(op) \ + } \ + else if (strleq(token.start, op, token.length)) { \ + do { \ + while (token.type != TOKEN_SEMICOLON) { \ + token = next_token(); \ + } \ + /*printf("code[%d]=%s\n %d + %d = %d\n", vm->cp, op, \ + * get_instruction_byte_size(op), vm->cp, vm->cp + \ + * get_instruction_byte_size(op)); */ \ + vm->cp += get_instruction_byte_size(op); \ + } while (0); + +/** + * Build the symbol table and calculate the types/size/offsets of all values. + */ +void build_symbol_table(VM *vm, char *source, ScopeTable *st) { + Token token; + init_lexer(source); + do { + token = next_token(); + if (token.type == TOKEN_ERROR) { + printf("ERROR at line %d: %.*s\n", token.line, token.length, token.start); + exit(1); } - int dest = allocateRegister(); - emit_byte(vm, dest); - emit_byte(vm, dest); - } - default: - return; // Unreachable. - } + 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; + } + + if (token.type == TOKEN_KEYWORD_FN) { + define_function(vm, st); + continue; + } + + if (token.type == TOKEN_KEYWORD_PLEX || token.type == TOKEN_TYPE_I8 || + token.type == TOKEN_TYPE_I16 || token.type == TOKEN_TYPE_INT || + token.type == TOKEN_TYPE_U8 || token.type == TOKEN_TYPE_U16 || + token.type == TOKEN_TYPE_NAT || token.type == TOKEN_TYPE_REAL || + token.type == TOKEN_TYPE_STR || token.type == TOKEN_TYPE_BOOL) { + define_var(st, token); + next_token_is(TOKEN_SEMICOLON); + continue; + } + + if (token.type == TOKEN_KEYWORD_LOOP || token.type == TOKEN_KEYWORD_IF || + token.type == TOKEN_KEYWORD_ELSE || token.type == TOKEN_KEYWORD_DO || + token.type == TOKEN_KEYWORD_FOR) { + define_branch(vm, st); + continue; + } + + if (token.type == TOKEN_KEYWORD_RETURN) { + vm->cp++; + + Token next = next_token(); + if (next.type == TOKEN_SEMICOLON) { + /* put 0xFF as return register */ + vm->cp++; + continue; + } + + get_reg(next, st); + vm->cp++; + next_token_is(TOKEN_SEMICOLON); + continue; + } + +#ifdef DEBUG_PRINT + printf("-- %.*s --\n", token.length, token.start); +#endif + if (token.type == TOKEN_IDENTIFIER) { + /* check to see if it is an opcode first */ + if (strleq(token.start, "exit", token.length)) { + + vm->cp++; + + next_token(); + vm->cp += 4; + +#ifdef DEBUG_PRINT + printf("code[%d] = exit\n", vm->cp); +#endif + + next_token_is(TOKEN_SEMICOLON); + } else if (strleq(token.start, "call", token.length)) { + + vm->cp++; + + next_token_is(TOKEN_IDENTIFIER); + vm->cp += 4; + + vm->cp++; + Token next = next_token_is(TOKEN_LPAREN); + next = next_token(); + while (next.type != TOKEN_RPAREN) { + get_reg(next, st); + vm->cp++; + next = next_token(); + } + + next = next_token(); + if (next.type == TOKEN_SEMICOLON) { + vm->cp++; + } else { + next = next_token(); + get_reg(next, st); + vm->cp++; + } +#ifdef DEBUG_PRINT + printf("code[%d] = call\n", vm->cp); +#endif + continue; + } else if (strleq(token.start, "syscall", token.length)) { + + vm->cp++; + + Token next = next_token(); + vm->cp += 4; + + next = next_token(); + while (next.type != TOKEN_SEMICOLON) { + get_reg(next, st); + vm->cp++; + next = next_token(); + } +#ifdef DEBUG_PRINT + printf("code[%d] = syscall\n", vm->cp); +#endif + continue; + FAKE_OP("load_immediate") + FAKE_OP("load_address") + FAKE_OP("malloc") + FAKE_OP("memset_8") + FAKE_OP("memset_16") + FAKE_OP("memset_32") + FAKE_OP("load_offset_8") + FAKE_OP("load_offset_16") + FAKE_OP("load_offset_32") + FAKE_OP("load_indirect_8") + FAKE_OP("load_indirect_16") + FAKE_OP("load_indirect_32") + FAKE_OP("load_absolute_8") + FAKE_OP("load_absolute_16") + FAKE_OP("load_absolute_32") + FAKE_OP("store_absolute_8") + FAKE_OP("store_absolute_16") + FAKE_OP("store_absolute_32") + FAKE_OP("store_indirect_8") + FAKE_OP("store_indirect_16") + FAKE_OP("store_indirect_32") + FAKE_OP("store_offset_8") + FAKE_OP("store_offset_16") + FAKE_OP("store_offset_32") + FAKE_OP("register_move") + FAKE_OP("add_int") + FAKE_OP("sub_int") + FAKE_OP("mul_int") + FAKE_OP("div_int") + FAKE_OP("abs_int") + FAKE_OP("neg_int") + FAKE_OP("add_nat") + FAKE_OP("sub_nat") + FAKE_OP("mul_nat") + FAKE_OP("div_nat") + FAKE_OP("abs_nat") + FAKE_OP("neg_nat") + FAKE_OP("add_real") + FAKE_OP("sub_real") + FAKE_OP("mul_real") + FAKE_OP("div_real") + FAKE_OP("abs_real") + FAKE_OP("neg_real") + FAKE_OP("int_to_real") + FAKE_OP("nat_to_real") + FAKE_OP("real_to_int") + FAKE_OP("real_to_nat") + FAKE_OP("bit_shift_left") + FAKE_OP("bit_shift_right") + FAKE_OP("bit_shift_r_ext") + FAKE_OP("bit_and") + FAKE_OP("bit_or") + FAKE_OP("bit_xor") + FAKE_OP("jump") + FAKE_OP("jump_if_flag") + FAKE_OP("jump_eq_int") + FAKE_OP("jump_neq_int") + FAKE_OP("jump_gt_int") + FAKE_OP("jump_lt_int") + FAKE_OP("jump_le_int") + FAKE_OP("jump_ge_int") + FAKE_OP("jump_eq_nat") + FAKE_OP("jump_neq_nat") + FAKE_OP("jump_gt_nat") + FAKE_OP("jump_lt_nat") + FAKE_OP("jump_le_nat") + FAKE_OP("jump_ge_nat") + FAKE_OP("jump_eq_real") + FAKE_OP("jump_neq_real") + FAKE_OP("jump_ge_real") + FAKE_OP("jump_gt_real") + FAKE_OP("jump_lt_real") + FAKE_OP("jump_le_real") + FAKE_OP("string_length") + FAKE_OP("int_to_string") + FAKE_OP("nat_to_string") + FAKE_OP("real_to_string") + FAKE_OP("string_eq") + FAKE_OP("string_concat") + FAKE_OP("string_get_char") + FAKE_OP("string_find_char") + FAKE_OP("string_slice") + FAKE_OP("string_to_int") + FAKE_OP("string_to_nat") + FAKE_OP("string_to_real") + } else { + /* some other identifier */ + printf("Unknown id at line %d: %.*s\n", token.line, token.length, + token.start); + exit(1); + } + } + } + } while (token.type != TOKEN_EOF); } -static void emitHalt(VM *vm) { - emit_opcode(vm, OP_EXIT); - advance(); - number(vm); +/** + * 2nd pass, emit the bytecode + */ +void emit_bytecode(VM *vm, char *source, ScopeTable *st) { + Token token; + init_lexer(source); + do { + token = next_token(); + if (token.type == TOKEN_ERROR) { + printf("ERROR at line %d: %.*s\n", token.line, token.length, token.start); + break; + } + 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 */ + next_token(); /* var */ + next_token(); /* eq */ + next_token(); /* value */ + next_token(); /* ; */ + continue; + } + + if (token.type == TOKEN_KEYWORD_FN) { + /* ignore, already processed */ + Token next = next_token(); + while (next.type != TOKEN_RPAREN) { + next = next_token(); + } + continue; + } + + if (token.type == TOKEN_KEYWORD_PLEX || token.type == TOKEN_TYPE_I8 || + token.type == TOKEN_TYPE_I16 || token.type == TOKEN_TYPE_INT || + token.type == TOKEN_TYPE_U8 || token.type == TOKEN_TYPE_U16 || + token.type == TOKEN_TYPE_NAT || token.type == TOKEN_TYPE_REAL || + token.type == TOKEN_TYPE_STR) { + /* ignore, already processed */ + next_token(); /* type */ + next_token(); /* var */ + next_token(); /* reg */ + next_token(); /* ; */ + continue; + } + + if (token.type == TOKEN_KEYWORD_LOOP || token.type == TOKEN_KEYWORD_IF || + token.type == TOKEN_KEYWORD_ELSE || token.type == TOKEN_KEYWORD_DO || + token.type == TOKEN_KEYWORD_FOR) { + /* ignore, already processed */ + next_token(); /* id */ + } + + if (token.type == TOKEN_KEYWORD_RETURN) { + emit_op(vm, OP_RETURN); + vm->cp++; + + Token next = next_token(); + if (next.type == TOKEN_SEMICOLON) { + /* put 0xFF as return register */ + emit_byte(vm, 0xFF); + vm->cp++; + continue; + } + + u32 reg = get_reg(next, st); + emit_byte(vm, reg); + vm->cp++; + next_token_is(TOKEN_SEMICOLON); + continue; + } + +#ifdef DEBUG_PRINT + printf("-- %.*s --\n", token.length, token.start); +#endif + if (token.type == TOKEN_IDENTIFIER) { + /* check to see if it is an opcode first */ + if (strleq(token.start, "exit", token.length)) { + + emit_op(vm, OP_EXIT); + vm->cp++; + + Token next = next_token(); + u32 ptr = get_ptr(next, st); + emit_u32(vm, ptr); + vm->cp += 4; + + next_token_is(TOKEN_SEMICOLON); + } else if (strleq(token.start, "call", token.length)) { + + emit_op(vm, OP_CALL); + vm->cp++; + + Token id = next_token_is(TOKEN_IDENTIFIER); + u32 ptr = get_ptr(id, st); + emit_u32(vm, ptr); + vm->cp += 4; + + u8 arg_count = 0; + u32 arg_pos = vm->cp++; + Token next = next_token_is(TOKEN_LPAREN); + next = next_token(); + while (next.type != TOKEN_RPAREN) { + u8 arg = get_reg(next, st); + emit_byte(vm, arg); + vm->cp++; + arg_count++; + next = next_token(); + } + + vm->code[arg_pos] = arg_count; + +#ifdef DEBUG_PRINT + printf("^code[%d] = %d\n", arg_pos, arg_count); +#endif + + next = next_token(); + if (next.type == TOKEN_SEMICOLON) { + emit_byte(vm, 255); + vm->cp++; + } else { + next = next_token(); + u8 arg = get_reg(next, st); + emit_byte(vm, arg); + vm->cp++; + } + + continue; + } else if (strleq(token.start, "syscall", token.length)) { + + emit_op(vm, OP_SYSCALL); + vm->cp++; + + Token next = next_token(); + + u32 syscall_id = 0; + const char *syscall_name = next.start; + if (strleq(syscall_name, "EXIT", next.length)) + syscall_id = SYSCALL_EXIT; + else if (strleq(syscall_name, "OPEN", next.length)) + syscall_id = SYSCALL_DEVICE_OPEN; + else if (strleq(syscall_name, "READ", next.length)) + syscall_id = SYSCALL_DEVICE_READ; + else if (strleq(syscall_name, "WRITE", next.length)) + syscall_id = SYSCALL_DEVICE_WRITE; + else if (strleq(syscall_name, "CLOSE", next.length)) + syscall_id = SYSCALL_DEVICE_CLOSE; + else if (strleq(syscall_name, "IOCTL", next.length)) + syscall_id = SYSCALL_DEVICE_IOCTL; + else if (strleq(syscall_name, "REFRESH", next.length)) + syscall_id = SYSCALL_DEVICE_REFRESH; + + emit_u32(vm, syscall_id); + vm->cp += 4; + + next = next_token(); + while (next.type != TOKEN_SEMICOLON && + next.type != TOKEN_ARROW_RIGHT) { + u8 arg = get_reg(next, st); + emit_byte(vm, arg); + vm->cp++; + next = next_token(); + } + + if (next.type == TOKEN_ARROW_RIGHT) { + next = next_token(); + u8 arg = get_reg(next, st); + emit_byte(vm, arg); + vm->cp++; + } + + } else if (strleq(token.start, "load_immediate", token.length)) { + + emit_op(vm, OP_LOAD_IMM); + vm->cp++; + + Token value = next_token(); + switch (value.type) { + case TOKEN_KEYWORD_TRUE: { + emit_u32(vm, 1); + break; + } + case TOKEN_KEYWORD_FALSE: { + emit_u32(vm, 0); + break; + } + case TOKEN_LITERAL_INT: { + i32 out = atoi(value.start); + emit_u32(vm, out); + break; + } + case TOKEN_LITERAL_NAT: { + char *endptr; + u32 out = (u32)strtoul(value.start, &endptr, 10); + if (endptr == value.start || *endptr != '\0') { + fprintf(stderr, "Invalid 'real' number: '%.*s'\n", token.length, + token.start); + exit(1); + } + emit_u32(vm, out); + break; + } + case TOKEN_LITERAL_REAL: { + fixed_t out = float_to_fixed(atof(value.start)); + emit_u32(vm, out); + break; + } + default: { + fprintf(stderr, "Unknown immediate: '%.*s'\n", token.length, + token.start); + exit(1); + } + } + + vm->cp += 4; + + next_token_is(TOKEN_ARROW_RIGHT); + + Token reg = next_token(); + u8 arg = get_reg(reg, st); + emit_byte(vm, arg); + vm->cp++; + + next_token_is(TOKEN_SEMICOLON); + } else if (strleq(token.start, "load_address", token.length)) { + emit_op(vm, OP_LOAD_IMM); + vm->cp++; + + Token id = next_token(); + u32 ptr = get_ptr(id, st); + emit_u32(vm, ptr); + vm->cp += 4; + + next_token_is(TOKEN_ARROW_RIGHT); + + Token reg = next_token(); + u8 arg = get_reg(reg, st); + emit_byte(vm, arg); + vm->cp++; + + next_token_is(TOKEN_SEMICOLON); + } else if (strleq(token.start, "malloc", token.length)) { + emit_op(vm, OP_MALLOC); + vm->cp++; + Token reg = next_token(); + u8 arg = get_reg(reg, st); + emit_byte(vm, arg); + vm->cp++; + next_token_is(TOKEN_ARROW_RIGHT); + reg = next_token(); + arg = get_reg(reg, st); + emit_byte(vm, arg); + vm->cp++; + next_token_is(TOKEN_SEMICOLON); + } else if (strleq(token.start, "memset_8", token.length)) { + emit_op(vm, OP_MEMSET_8); + vm->cp++; + + Token reg = next_token(); + u8 arg = get_reg(reg, st); + emit_byte(vm, arg); + vm->cp++; + + reg = next_token(); + arg = get_reg(reg, st); + emit_byte(vm, arg); + vm->cp++; + + next_token_is(TOKEN_ARROW_RIGHT); + + reg = next_token(); + arg = get_reg(reg, st); + emit_byte(vm, arg); + vm->cp++; + + next_token_is(TOKEN_SEMICOLON); + } else if (strleq(token.start, "memset_16", token.length)) { + emit_op(vm, OP_MEMSET_16); + vm->cp++; + + Token reg = next_token(); + u8 arg = get_reg(reg, st); + emit_byte(vm, arg); + vm->cp++; + + reg = next_token(); + arg = get_reg(reg, st); + emit_byte(vm, arg); + vm->cp++; + + next_token_is(TOKEN_ARROW_RIGHT); + + reg = next_token(); + arg = get_reg(reg, st); + emit_byte(vm, arg); + vm->cp++; + + next_token_is(TOKEN_SEMICOLON); + } else if (strleq(token.start, "memset_32", token.length)) { + emit_op(vm, OP_MEMSET_32); + vm->cp++; + + Token reg = next_token(); + u8 arg = get_reg(reg, st); + emit_byte(vm, arg); + vm->cp++; + + reg = next_token(); + arg = get_reg(reg, st); + emit_byte(vm, arg); + vm->cp++; + + next_token_is(TOKEN_ARROW_RIGHT); + + reg = next_token(); + arg = get_reg(reg, st); + emit_byte(vm, arg); + vm->cp++; + + next_token_is(TOKEN_SEMICOLON); + } else if (strleq(token.start, "load_offset_8", token.length)) { + emit_op(vm, OP_LOAD_OFF_8); + vm->cp++; + + Token reg = next_token(); + u8 arg = get_reg(reg, st); + emit_byte(vm, arg); + vm->cp++; + + Token id = next_token(); + u32 ptr = get_ptr(id, st); + emit_u32(vm, ptr); + vm->cp += 4; + + next_token_is(TOKEN_ARROW_RIGHT); + + reg = next_token(); + arg = get_reg(reg, st); + emit_byte(vm, arg); + vm->cp++; + + next_token_is(TOKEN_SEMICOLON); + } else if (strleq(token.start, "load_offset_16", token.length)) { + emit_op(vm, OP_LOAD_OFF_16); + vm->cp++; + + Token reg = next_token(); + u8 arg = get_reg(reg, st); + emit_byte(vm, arg); + vm->cp++; + + Token id = next_token(); + u32 ptr = get_ptr(id, st); + emit_u32(vm, ptr); + vm->cp += 4; + + next_token_is(TOKEN_ARROW_RIGHT); + + reg = next_token(); + arg = get_reg(reg, st); + emit_byte(vm, arg); + vm->cp++; + + next_token_is(TOKEN_SEMICOLON); + } else if (strleq(token.start, "load_offset_32", token.length)) { + emit_op(vm, OP_LOAD_OFF_32); + vm->cp++; + + Token reg = next_token(); + u8 arg = get_reg(reg, st); + emit_byte(vm, arg); + vm->cp++; + + Token id = next_token(); + u32 ptr = get_ptr(id, st); + emit_u32(vm, ptr); + vm->cp += 4; + + next_token_is(TOKEN_ARROW_RIGHT); + + reg = next_token(); + arg = get_reg(reg, st); + emit_byte(vm, arg); + vm->cp++; + + next_token_is(TOKEN_SEMICOLON); + } else if (strleq(token.start, "load_indirect_8", token.length)) { + emit_op(vm, OP_LOAD_IND_8); + vm->cp++; + + Token id = next_token(); + u32 ptr = get_ptr(id, st); + emit_u32(vm, ptr); + vm->cp += 4; + + next_token_is(TOKEN_ARROW_RIGHT); + + Token reg = next_token(); + u8 arg = get_reg(reg, st); + emit_byte(vm, arg); + vm->cp++; + + next_token_is(TOKEN_SEMICOLON); + } else if (strleq(token.start, "load_indirect_16", token.length)) { + emit_op(vm, OP_LOAD_IND_16); + vm->cp++; + + Token id = next_token(); + u32 ptr = get_ptr(id, st); + emit_u32(vm, ptr); + vm->cp += 4; + + next_token_is(TOKEN_ARROW_RIGHT); + + Token reg = next_token(); + u8 arg = get_reg(reg, st); + emit_byte(vm, arg); + vm->cp++; + + next_token_is(TOKEN_SEMICOLON); + } else if (strleq(token.start, "load_indirect_32", token.length)) { + emit_op(vm, OP_LOAD_IND_32); + vm->cp++; + + Token id = next_token(); + u32 ptr = get_ptr(id, st); + emit_u32(vm, ptr); + vm->cp += 4; + + next_token_is(TOKEN_ARROW_RIGHT); + + Token reg = next_token(); + u8 arg = get_reg(reg, st); + emit_byte(vm, arg); + vm->cp++; + + next_token_is(TOKEN_SEMICOLON); + } else if (strleq(token.start, "load_absolute_8", token.length)) { + emit_op(vm, OP_LOAD_ABS_8); + vm->cp++; + + Token id = next_token(); + u32 ptr = get_ptr(id, st); + emit_u32(vm, ptr); + vm->cp += 4; + + next_token_is(TOKEN_ARROW_RIGHT); + + Token reg = next_token(); + u8 arg = get_reg(reg, st); + emit_byte(vm, arg); + vm->cp++; + + next_token_is(TOKEN_SEMICOLON); + } else if (strleq(token.start, "load_absolute_16", token.length)) { + emit_op(vm, OP_LOAD_ABS_16); + vm->cp++; + + Token id = next_token(); + u32 ptr = get_ptr(id, st); + emit_u32(vm, ptr); + vm->cp += 4; + + next_token_is(TOKEN_ARROW_RIGHT); + + Token reg = next_token(); + u8 arg = get_reg(reg, st); + emit_byte(vm, arg); + vm->cp++; + + next_token_is(TOKEN_SEMICOLON); + } else if (strleq(token.start, "load_absolute_32", token.length)) { + emit_op(vm, OP_LOAD_ABS_32); + vm->cp++; + + Token id = next_token(); + u32 ptr = get_ptr(id, st); + emit_u32(vm, ptr); + vm->cp += 4; + + next_token_is(TOKEN_ARROW_RIGHT); + + Token reg = next_token(); + u8 arg = get_reg(reg, st); + emit_byte(vm, arg); + vm->cp++; + + next_token_is(TOKEN_SEMICOLON); + } else if (strleq(token.start, "store_absolute_8", token.length)) { + emit_op(vm, OP_STORE_ABS_8); + vm->cp++; + + Token reg = next_token(); + u8 arg = get_reg(reg, st); + emit_byte(vm, arg); + vm->cp++; + + next_token_is(TOKEN_ARROW_RIGHT); + + Token id = next_token(); + u32 ptr = get_ptr(id, st); + emit_u32(vm, ptr); + vm->cp += 4; + + next_token_is(TOKEN_SEMICOLON); + } else if (strleq(token.start, "store_absolute_16", token.length)) { + emit_op(vm, OP_STORE_ABS_16); + vm->cp++; + + Token reg = next_token(); + u8 arg = get_reg(reg, st); + emit_byte(vm, arg); + vm->cp++; + + next_token_is(TOKEN_ARROW_RIGHT); + + Token id = next_token(); + u32 ptr = get_ptr(id, st); + emit_u32(vm, ptr); + vm->cp += 4; + + next_token_is(TOKEN_SEMICOLON); + } else if (strleq(token.start, "store_absolute_32", token.length)) { + emit_op(vm, OP_STORE_ABS_32); + vm->cp++; + + Token reg = next_token(); + u8 arg = get_reg(reg, st); + emit_byte(vm, arg); + vm->cp++; + + next_token_is(TOKEN_ARROW_RIGHT); + + Token id = next_token(); + u32 ptr = get_ptr(id, st); + emit_u32(vm, ptr); + vm->cp += 4; + + next_token_is(TOKEN_SEMICOLON); + } else if (strleq(token.start, "store_indirect_8", token.length)) { + emit_op(vm, OP_STORE_IND_8); + vm->cp++; + + Token reg = next_token(); + u8 arg = get_reg(reg, st); + emit_byte(vm, arg); + vm->cp++; + + next_token_is(TOKEN_ARROW_RIGHT); + + reg = next_token(); + arg = get_reg(reg, st); + emit_byte(vm, arg); + vm->cp++; + + next_token_is(TOKEN_SEMICOLON); + } else if (strleq(token.start, "store_indirect_16", token.length)) { + emit_op(vm, OP_STORE_IND_16); + vm->cp++; + + Token reg = next_token(); + u8 arg = get_reg(reg, st); + emit_byte(vm, arg); + vm->cp++; + + next_token_is(TOKEN_ARROW_RIGHT); + + reg = next_token(); + arg = get_reg(reg, st); + emit_byte(vm, arg); + vm->cp++; + + next_token_is(TOKEN_SEMICOLON); + } else if (strleq(token.start, "store_indirect_32", token.length)) { + emit_op(vm, OP_STORE_IND_32); + vm->cp++; + + Token reg = next_token(); + u8 arg = get_reg(reg, st); + emit_byte(vm, arg); + vm->cp++; + + next_token_is(TOKEN_ARROW_RIGHT); + + reg = next_token(); + arg = get_reg(reg, st); + emit_byte(vm, arg); + vm->cp++; + + next_token_is(TOKEN_SEMICOLON); + } else if (strleq(token.start, "store_offset_8", token.length)) { + emit_op(vm, OP_STORE_OFF_8); + vm->cp++; + + Token reg = next_token(); + u8 arg = get_reg(reg, st); + emit_byte(vm, arg); + vm->cp++; + + Token id = next_token(); + u32 ptr = get_ptr(id, st); + emit_u32(vm, ptr); + vm->cp += 4; + + next_token_is(TOKEN_ARROW_RIGHT); + + reg = next_token(); + arg = get_reg(reg, st); + emit_byte(vm, arg); + vm->cp++; + + next_token_is(TOKEN_SEMICOLON); + } else if (strleq(token.start, "store_offset_16", token.length)) { + emit_op(vm, OP_STORE_OFF_16); + vm->cp++; + + Token reg = next_token(); + u8 arg = get_reg(reg, st); + emit_byte(vm, arg); + vm->cp++; + + Token id = next_token(); + u32 ptr = get_ptr(id, st); + emit_u32(vm, ptr); + vm->cp += 4; + + next_token_is(TOKEN_ARROW_RIGHT); + + reg = next_token(); + arg = get_reg(reg, st); + emit_byte(vm, arg); + vm->cp++; + + next_token_is(TOKEN_SEMICOLON); + } else if (strleq(token.start, "store_offset_32", token.length)) { + emit_op(vm, OP_STORE_OFF_32); + vm->cp++; + + Token reg = next_token(); + u8 arg = get_reg(reg, st); + emit_byte(vm, arg); + vm->cp++; + + Token id = next_token(); + u32 ptr = get_ptr(id, st); + emit_u32(vm, ptr); + vm->cp += 4; + + next_token_is(TOKEN_ARROW_RIGHT); + + reg = next_token(); + arg = get_reg(reg, st); + emit_byte(vm, arg); + vm->cp++; + + next_token_is(TOKEN_SEMICOLON); + } else if (strleq(token.start, "register_move", token.length)) { + emit_op(vm, OP_REG_MOV); + vm->cp++; + Token reg = next_token(); + u8 arg = get_reg(reg, st); + emit_byte(vm, arg); + vm->cp++; + next_token_is(TOKEN_ARROW_RIGHT); + reg = next_token(); + arg = get_reg(reg, st); + emit_byte(vm, arg); + vm->cp++; + next_token_is(TOKEN_SEMICOLON); + } else if (strleq(token.start, "add_int", token.length)) { + emit_op(vm, OP_ADD_INT); + vm->cp++; + Token reg = next_token(); + u8 arg = get_reg(reg, st); + emit_byte(vm, arg); + vm->cp++; + Token next = next_token(); + arg = get_reg(next, st); + emit_byte(vm, arg); + vm->cp++; + next_token_is(TOKEN_ARROW_RIGHT); + next = next_token(); + arg = get_reg(next, st); + emit_byte(vm, arg); + vm->cp++; + next_token_is(TOKEN_SEMICOLON); + } else if (strleq(token.start, "sub_int", token.length)) { + emit_op(vm, OP_SUB_INT); + vm->cp++; + Token reg = next_token(); + u8 arg = get_reg(reg, st); + emit_byte(vm, arg); + vm->cp++; + Token next = next_token(); + arg = get_reg(next, st); + emit_byte(vm, arg); + vm->cp++; + next_token_is(TOKEN_ARROW_RIGHT); + next = next_token(); + arg = get_reg(next, st); + emit_byte(vm, arg); + vm->cp++; + next_token_is(TOKEN_SEMICOLON); + } else if (strleq(token.start, "mul_int", token.length)) { + emit_op(vm, OP_MUL_INT); + vm->cp++; + Token reg = next_token(); + u8 arg = get_reg(reg, st); + emit_byte(vm, arg); + vm->cp++; + Token next = next_token(); + arg = get_reg(next, st); + emit_byte(vm, arg); + vm->cp++; + next_token_is(TOKEN_ARROW_RIGHT); + next = next_token(); + arg = get_reg(next, st); + emit_byte(vm, arg); + vm->cp++; + next_token_is(TOKEN_SEMICOLON); + } else if (strleq(token.start, "div_int", token.length)) { + emit_op(vm, OP_DIV_INT); + vm->cp++; + Token reg = next_token(); + u8 arg = get_reg(reg, st); + emit_byte(vm, arg); + vm->cp++; + Token next = next_token(); + arg = get_reg(next, st); + emit_byte(vm, arg); + vm->cp++; + next_token_is(TOKEN_ARROW_RIGHT); + next = next_token(); + arg = get_reg(next, st); + emit_byte(vm, arg); + vm->cp++; + next_token_is(TOKEN_SEMICOLON); + } else if (strleq(token.start, "abs_int", token.length)) { + emit_op(vm, OP_ABS_INT); + vm->cp++; + Token reg = next_token(); + u8 arg = get_reg(reg, st); + emit_byte(vm, arg); + vm->cp++; + next_token_is(TOKEN_ARROW_RIGHT); + reg = next_token(); + arg = get_reg(reg, st); + emit_byte(vm, arg); + vm->cp++; + next_token_is(TOKEN_SEMICOLON); + } else if (strleq(token.start, "neg_int", token.length)) { + emit_op(vm, OP_NEG_INT); + vm->cp++; + Token reg = next_token(); + u8 arg = get_reg(reg, st); + emit_byte(vm, arg); + vm->cp++; + next_token_is(TOKEN_ARROW_RIGHT); + reg = next_token(); + arg = get_reg(reg, st); + emit_byte(vm, arg); + vm->cp++; + next_token_is(TOKEN_SEMICOLON); + } else if (strleq(token.start, "add_nat", token.length)) { + emit_op(vm, OP_ADD_NAT); + vm->cp++; + Token reg = next_token(); + u8 arg = get_reg(reg, st); + emit_byte(vm, arg); + vm->cp++; + Token next = next_token(); + arg = get_reg(next, st); + emit_byte(vm, arg); + vm->cp++; + next_token_is(TOKEN_ARROW_RIGHT); + next = next_token(); + arg = get_reg(next, st); + emit_byte(vm, arg); + vm->cp++; + next_token_is(TOKEN_SEMICOLON); + } else if (strleq(token.start, "sub_nat", token.length)) { + emit_op(vm, OP_SUB_NAT); + vm->cp++; + Token reg = next_token(); + u8 arg = get_reg(reg, st); + emit_byte(vm, arg); + vm->cp++; + Token next = next_token(); + arg = get_reg(next, st); + emit_byte(vm, arg); + vm->cp++; + next_token_is(TOKEN_ARROW_RIGHT); + next = next_token(); + arg = get_reg(next, st); + emit_byte(vm, arg); + vm->cp++; + next_token_is(TOKEN_SEMICOLON); + } else if (strleq(token.start, "mul_nat", token.length)) { + emit_op(vm, OP_MUL_NAT); + vm->cp++; + Token reg = next_token(); + u8 arg = get_reg(reg, st); + emit_byte(vm, arg); + vm->cp++; + Token next = next_token(); + arg = get_reg(next, st); + emit_byte(vm, arg); + vm->cp++; + next_token_is(TOKEN_ARROW_RIGHT); + next = next_token(); + arg = get_reg(next, st); + emit_byte(vm, arg); + vm->cp++; + next_token_is(TOKEN_SEMICOLON); + } else if (strleq(token.start, "div_nat", token.length)) { + emit_op(vm, OP_DIV_NAT); + vm->cp++; + Token reg = next_token(); + u8 arg = get_reg(reg, st); + emit_byte(vm, arg); + vm->cp++; + Token next = next_token(); + arg = get_reg(next, st); + emit_byte(vm, arg); + vm->cp++; + next_token_is(TOKEN_ARROW_RIGHT); + next = next_token(); + arg = get_reg(next, st); + emit_byte(vm, arg); + vm->cp++; + next_token_is(TOKEN_SEMICOLON); + } else if (strleq(token.start, "abs_nat", token.length)) { + emit_op(vm, OP_ABS_NAT); + vm->cp++; + Token reg = next_token(); + u8 arg = get_reg(reg, st); + emit_byte(vm, arg); + vm->cp++; + next_token_is(TOKEN_ARROW_RIGHT); + reg = next_token(); + arg = get_reg(reg, st); + emit_byte(vm, arg); + vm->cp++; + next_token_is(TOKEN_SEMICOLON); + } else if (strleq(token.start, "neg_nat", token.length)) { + emit_op(vm, OP_NEG_NAT); + vm->cp++; + Token reg = next_token(); + u8 arg = get_reg(reg, st); + emit_byte(vm, arg); + vm->cp++; + next_token_is(TOKEN_ARROW_RIGHT); + reg = next_token(); + arg = get_reg(reg, st); + emit_byte(vm, arg); + vm->cp++; + next_token_is(TOKEN_SEMICOLON); + } else if (strleq(token.start, "add_real", token.length)) { + emit_op(vm, OP_ADD_REAL); + vm->cp++; + Token reg = next_token(); + u8 arg = get_reg(reg, st); + emit_byte(vm, arg); + vm->cp++; + Token next = next_token(); + arg = get_reg(next, st); + emit_byte(vm, arg); + vm->cp++; + next_token_is(TOKEN_ARROW_RIGHT); + next = next_token(); + arg = get_reg(next, st); + emit_byte(vm, arg); + vm->cp++; + next_token_is(TOKEN_SEMICOLON); + ; + } else if (strleq(token.start, "sub_real", token.length)) { + emit_op(vm, OP_SUB_REAL); + vm->cp++; + Token reg = next_token(); + u8 arg = get_reg(reg, st); + emit_byte(vm, arg); + vm->cp++; + Token next = next_token(); + arg = get_reg(next, st); + emit_byte(vm, arg); + vm->cp++; + next_token_is(TOKEN_ARROW_RIGHT); + next = next_token(); + arg = get_reg(next, st); + emit_byte(vm, arg); + vm->cp++; + next_token_is(TOKEN_SEMICOLON); + } else if (strleq(token.start, "mul_real", token.length)) { + emit_op(vm, OP_MUL_REAL); + vm->cp++; + Token reg = next_token(); + u8 arg = get_reg(reg, st); + emit_byte(vm, arg); + vm->cp++; + Token next = next_token(); + arg = get_reg(next, st); + emit_byte(vm, arg); + vm->cp++; + next_token_is(TOKEN_ARROW_RIGHT); + next = next_token(); + arg = get_reg(next, st); + emit_byte(vm, arg); + vm->cp++; + next_token_is(TOKEN_SEMICOLON); + } else if (strleq(token.start, "div_real", token.length)) { + emit_op(vm, OP_DIV_REAL); + vm->cp++; + Token reg = next_token(); + u8 arg = get_reg(reg, st); + emit_byte(vm, arg); + vm->cp++; + Token next = next_token(); + arg = get_reg(next, st); + emit_byte(vm, arg); + vm->cp++; + next_token_is(TOKEN_ARROW_RIGHT); + next = next_token(); + arg = get_reg(next, st); + emit_byte(vm, arg); + vm->cp++; + next_token_is(TOKEN_SEMICOLON); + } else if (strleq(token.start, "abs_real", token.length)) { + emit_op(vm, OP_ABS_REAL); + vm->cp++; + Token reg = next_token(); + u8 arg = get_reg(reg, st); + emit_byte(vm, arg); + vm->cp++; + next_token_is(TOKEN_ARROW_RIGHT); + reg = next_token(); + arg = get_reg(reg, st); + emit_byte(vm, arg); + vm->cp++; + next_token_is(TOKEN_SEMICOLON); + } else if (strleq(token.start, "neg_real", token.length)) { + emit_op(vm, OP_NEG_REAL); + vm->cp++; + Token reg = next_token(); + u8 arg = get_reg(reg, st); + emit_byte(vm, arg); + vm->cp++; + next_token_is(TOKEN_ARROW_RIGHT); + reg = next_token(); + arg = get_reg(reg, st); + emit_byte(vm, arg); + vm->cp++; + next_token_is(TOKEN_SEMICOLON); + } else if (strleq(token.start, "int_to_real", token.length)) { + emit_op(vm, OP_INT_TO_REAL); + vm->cp++; + Token reg = next_token(); + u8 arg = get_reg(reg, st); + emit_byte(vm, arg); + vm->cp++; + next_token_is(TOKEN_ARROW_RIGHT); + reg = next_token(); + arg = get_reg(reg, st); + emit_byte(vm, arg); + vm->cp++; + next_token_is(TOKEN_SEMICOLON); + } else if (strleq(token.start, "nat_to_real", token.length)) { + emit_op(vm, OP_NAT_TO_REAL); + vm->cp++; + Token reg = next_token(); + u8 arg = get_reg(reg, st); + emit_byte(vm, arg); + vm->cp++; + next_token_is(TOKEN_ARROW_RIGHT); + reg = next_token(); + arg = get_reg(reg, st); + emit_byte(vm, arg); + vm->cp++; + next_token_is(TOKEN_SEMICOLON); + } else if (strleq(token.start, "real_to_int", token.length)) { + emit_op(vm, OP_REAL_TO_INT); + vm->cp++; + Token reg = next_token(); + u8 arg = get_reg(reg, st); + emit_byte(vm, arg); + vm->cp++; + next_token_is(TOKEN_ARROW_RIGHT); + reg = next_token(); + arg = get_reg(reg, st); + emit_byte(vm, arg); + vm->cp++; + next_token_is(TOKEN_SEMICOLON); + } else if (strleq(token.start, "real_to_nat", token.length)) { + emit_op(vm, OP_REAL_TO_NAT); + vm->cp++; + Token reg = next_token(); + u8 arg = get_reg(reg, st); + emit_byte(vm, arg); + vm->cp++; + next_token_is(TOKEN_ARROW_RIGHT); + reg = next_token(); + arg = get_reg(reg, st); + emit_byte(vm, arg); + vm->cp++; + next_token_is(TOKEN_SEMICOLON); + } else if (strleq(token.start, "bit_shift_left", token.length)) { + emit_op(vm, OP_BIT_SHIFT_LEFT); + vm->cp++; + Token reg = next_token(); + u8 arg = get_reg(reg, st); + emit_byte(vm, arg); + vm->cp++; + Token next = next_token(); + arg = get_reg(next, st); + emit_byte(vm, arg); + vm->cp++; + next_token_is(TOKEN_ARROW_RIGHT); + next = next_token(); + arg = get_reg(next, st); + emit_byte(vm, arg); + vm->cp++; + next_token_is(TOKEN_SEMICOLON); + } else if (strleq(token.start, "bit_shift_right", token.length)) { + emit_op(vm, OP_BIT_SHIFT_RIGHT); + vm->cp++; + Token reg = next_token(); + u8 arg = get_reg(reg, st); + emit_byte(vm, arg); + vm->cp++; + Token next = next_token(); + arg = get_reg(next, st); + emit_byte(vm, arg); + vm->cp++; + next_token_is(TOKEN_ARROW_RIGHT); + next = next_token(); + arg = get_reg(next, st); + emit_byte(vm, arg); + vm->cp++; + next_token_is(TOKEN_SEMICOLON); + } else if (strleq(token.start, "bit_shift_r_ext", token.length)) { + emit_op(vm, OP_BIT_SHIFT_R_EXT); + vm->cp++; + Token reg = next_token(); + u8 arg = get_reg(reg, st); + emit_byte(vm, arg); + vm->cp++; + Token next = next_token(); + arg = get_reg(next, st); + emit_byte(vm, arg); + vm->cp++; + next_token_is(TOKEN_ARROW_RIGHT); + next = next_token(); + arg = get_reg(next, st); + emit_byte(vm, arg); + vm->cp++; + next_token_is(TOKEN_SEMICOLON); + } else if (strleq(token.start, "bit_and", token.length)) { + emit_op(vm, OP_BAND); + vm->cp++; + Token reg = next_token(); + u8 arg = get_reg(reg, st); + emit_byte(vm, arg); + vm->cp++; + Token next = next_token(); + arg = get_reg(next, st); + emit_byte(vm, arg); + vm->cp++; + next_token_is(TOKEN_ARROW_RIGHT); + next = next_token(); + arg = get_reg(next, st); + emit_byte(vm, arg); + vm->cp++; + next_token_is(TOKEN_SEMICOLON); + } else if (strleq(token.start, "bit_or", token.length)) { + emit_op(vm, OP_BOR); + vm->cp++; + Token reg = next_token(); + u8 arg = get_reg(reg, st); + emit_byte(vm, arg); + vm->cp++; + Token next = next_token(); + arg = get_reg(next, st); + emit_byte(vm, arg); + vm->cp++; + next_token_is(TOKEN_ARROW_RIGHT); + next = next_token(); + arg = get_reg(next, st); + emit_byte(vm, arg); + vm->cp++; + next_token_is(TOKEN_SEMICOLON); + } else if (strleq(token.start, "bit_xor", token.length)) { + emit_op(vm, OP_BXOR); + vm->cp++; + Token reg = next_token(); + u8 arg = get_reg(reg, st); + emit_byte(vm, arg); + vm->cp++; + Token next = next_token(); + arg = get_reg(next, st); + emit_byte(vm, arg); + vm->cp++; + next_token_is(TOKEN_ARROW_RIGHT); + next = next_token(); + arg = get_reg(next, st); + emit_byte(vm, arg); + vm->cp++; + next_token_is(TOKEN_SEMICOLON); + } else if (strleq(token.start, "jump", token.length)) { + emit_op(vm, OP_JMP); + vm->cp++; + + Token id = next_token(); + u32 ptr = get_ptr(id, st); + emit_u32(vm, ptr); + vm->cp += 4; + + next_token_is(TOKEN_SEMICOLON); + } else if (strleq(token.start, "jump_if_flag", token.length)) { + emit_op(vm, OP_JMPF); + vm->cp++; + + Token id = next_token(); + u32 ptr = get_ptr(id, st); + emit_u32(vm, ptr); + vm->cp += 4; + + next_token_is(TOKEN_SEMICOLON); + } else if (strleq(token.start, "jump_eq_int", token.length)) { + emit_op(vm, OP_JEQ_INT); + vm->cp++; + Token id = next_token(); + u32 ptr = get_ptr(id, st); + emit_u32(vm, ptr); + vm->cp += 4; + Token reg = next_token(); + u8 arg = get_reg(reg, st); + emit_byte(vm, arg); + vm->cp++; + reg = next_token(); + arg = get_reg(reg, st); + emit_byte(vm, arg); + vm->cp++; + next_token_is(TOKEN_SEMICOLON); + } else if (strleq(token.start, "jump_neq_int", token.length)) { + emit_op(vm, OP_JNEQ_INT); + vm->cp++; + Token id = next_token(); + u32 ptr = get_ptr(id, st); + emit_u32(vm, ptr); + vm->cp += 4; + Token reg = next_token(); + u8 arg = get_reg(reg, st); + emit_byte(vm, arg); + vm->cp++; + reg = next_token(); + arg = get_reg(reg, st); + emit_byte(vm, arg); + vm->cp++; + next_token_is(TOKEN_SEMICOLON); + } else if (strleq(token.start, "jump_gt_int", token.length)) { + emit_op(vm, OP_JGT_INT); + vm->cp++; + Token id = next_token(); + u32 ptr = get_ptr(id, st); + emit_u32(vm, ptr); + vm->cp += 4; + Token reg = next_token(); + u8 arg = get_reg(reg, st); + emit_byte(vm, arg); + vm->cp++; + reg = next_token(); + arg = get_reg(reg, st); + emit_byte(vm, arg); + vm->cp++; + next_token_is(TOKEN_SEMICOLON); + } else if (strleq(token.start, "jump_lt_int", token.length)) { + emit_op(vm, OP_JLT_INT); + vm->cp++; + Token id = next_token(); + u32 ptr = get_ptr(id, st); + emit_u32(vm, ptr); + vm->cp += 4; + Token reg = next_token(); + u8 arg = get_reg(reg, st); + emit_byte(vm, arg); + vm->cp++; + reg = next_token(); + arg = get_reg(reg, st); + emit_byte(vm, arg); + vm->cp++; + next_token_is(TOKEN_SEMICOLON); + } else if (strleq(token.start, "jump_le_int", token.length)) { + emit_op(vm, OP_JLE_INT); + vm->cp++; + Token id = next_token(); + u32 ptr = get_ptr(id, st); + emit_u32(vm, ptr); + vm->cp += 4; + Token reg = next_token(); + u8 arg = get_reg(reg, st); + emit_byte(vm, arg); + vm->cp++; + reg = next_token(); + arg = get_reg(reg, st); + emit_byte(vm, arg); + vm->cp++; + next_token_is(TOKEN_SEMICOLON); + } else if (strleq(token.start, "jump_ge_int", token.length)) { + emit_op(vm, OP_JGE_INT); + vm->cp++; + Token id = next_token(); + u32 ptr = get_ptr(id, st); + emit_u32(vm, ptr); + vm->cp += 4; + Token reg = next_token(); + u8 arg = get_reg(reg, st); + emit_byte(vm, arg); + vm->cp++; + reg = next_token(); + arg = get_reg(reg, st); + emit_byte(vm, arg); + vm->cp++; + next_token_is(TOKEN_SEMICOLON); + } else if (strleq(token.start, "jump_eq_nat", token.length)) { + emit_op(vm, OP_JEQ_NAT); + vm->cp++; + Token id = next_token(); + u32 ptr = get_ptr(id, st); + emit_u32(vm, ptr); + vm->cp += 4; + Token reg = next_token(); + u8 arg = get_reg(reg, st); + emit_byte(vm, arg); + vm->cp++; + reg = next_token(); + arg = get_reg(reg, st); + emit_byte(vm, arg); + vm->cp++; + next_token_is(TOKEN_SEMICOLON); + } else if (strleq(token.start, "jump_neq_nat", token.length)) { + emit_op(vm, OP_JNEQ_NAT); + vm->cp++; + Token id = next_token(); + u32 ptr = get_ptr(id, st); + emit_u32(vm, ptr); + vm->cp += 4; + Token reg = next_token(); + u8 arg = get_reg(reg, st); + emit_byte(vm, arg); + vm->cp++; + reg = next_token(); + arg = get_reg(reg, st); + emit_byte(vm, arg); + vm->cp++; + next_token_is(TOKEN_SEMICOLON); + } else if (strleq(token.start, "jump_gt_nat", token.length)) { + emit_op(vm, OP_JGT_NAT); + vm->cp++; + Token id = next_token(); + u32 ptr = get_ptr(id, st); + emit_u32(vm, ptr); + vm->cp += 4; + Token reg = next_token(); + u8 arg = get_reg(reg, st); + emit_byte(vm, arg); + vm->cp++; + reg = next_token(); + arg = get_reg(reg, st); + emit_byte(vm, arg); + vm->cp++; + next_token_is(TOKEN_SEMICOLON); + } else if (strleq(token.start, "jump_lt_nat", token.length)) { + emit_op(vm, OP_JLT_NAT); + vm->cp++; + Token id = next_token(); + u32 ptr = get_ptr(id, st); + emit_u32(vm, ptr); + vm->cp += 4; + Token reg = next_token(); + u8 arg = get_reg(reg, st); + emit_byte(vm, arg); + vm->cp++; + reg = next_token(); + arg = get_reg(reg, st); + emit_byte(vm, arg); + vm->cp++; + next_token_is(TOKEN_SEMICOLON); + } else if (strleq(token.start, "jump_le_nat", token.length)) { + emit_op(vm, OP_JLE_NAT); + vm->cp++; + Token id = next_token(); + u32 ptr = get_ptr(id, st); + emit_u32(vm, ptr); + vm->cp += 4; + Token reg = next_token(); + u8 arg = get_reg(reg, st); + emit_byte(vm, arg); + vm->cp++; + reg = next_token(); + arg = get_reg(reg, st); + emit_byte(vm, arg); + vm->cp++; + next_token_is(TOKEN_SEMICOLON); + } else if (strleq(token.start, "jump_ge_nat", token.length)) { + emit_op(vm, OP_JGE_NAT); + vm->cp++; + Token id = next_token(); + u32 ptr = get_ptr(id, st); + emit_u32(vm, ptr); + vm->cp += 4; + Token reg = next_token(); + u8 arg = get_reg(reg, st); + emit_byte(vm, arg); + vm->cp++; + reg = next_token(); + arg = get_reg(reg, st); + emit_byte(vm, arg); + vm->cp++; + next_token_is(TOKEN_SEMICOLON); + } else if (strleq(token.start, "jump_eq_real", token.length)) { + emit_op(vm, OP_JEQ_REAL); + vm->cp++; + Token id = next_token(); + u32 ptr = get_ptr(id, st); + emit_u32(vm, ptr); + vm->cp += 4; + Token reg = next_token(); + u8 arg = get_reg(reg, st); + emit_byte(vm, arg); + vm->cp++; + reg = next_token(); + arg = get_reg(reg, st); + emit_byte(vm, arg); + vm->cp++; + next_token_is(TOKEN_SEMICOLON); + } else if (strleq(token.start, "jump_neq_real", token.length)) { + emit_op(vm, OP_JNEQ_REAL); + vm->cp++; + Token id = next_token(); + u32 ptr = get_ptr(id, st); + emit_u32(vm, ptr); + vm->cp += 4; + Token reg = next_token(); + u8 arg = get_reg(reg, st); + emit_byte(vm, arg); + vm->cp++; + reg = next_token(); + arg = get_reg(reg, st); + emit_byte(vm, arg); + vm->cp++; + next_token_is(TOKEN_SEMICOLON); + } else if (strleq(token.start, "jump_ge_real", token.length)) { + emit_op(vm, OP_JGE_REAL); + vm->cp++; + Token id = next_token(); + u32 ptr = get_ptr(id, st); + emit_u32(vm, ptr); + vm->cp += 4; + Token reg = next_token(); + u8 arg = get_reg(reg, st); + emit_byte(vm, arg); + vm->cp++; + reg = next_token(); + arg = get_reg(reg, st); + emit_byte(vm, arg); + vm->cp++; + next_token_is(TOKEN_SEMICOLON); + } else if (strleq(token.start, "jump_gt_real", token.length)) { + emit_op(vm, OP_JGT_REAL); + vm->cp++; + Token id = next_token(); + u32 ptr = get_ptr(id, st); + emit_u32(vm, ptr); + vm->cp += 4; + Token reg = next_token(); + u8 arg = get_reg(reg, st); + emit_byte(vm, arg); + vm->cp++; + reg = next_token(); + arg = get_reg(reg, st); + emit_byte(vm, arg); + vm->cp++; + next_token_is(TOKEN_SEMICOLON); + } else if (strleq(token.start, "jump_lt_real", token.length)) { + emit_op(vm, OP_JLT_REAL); + vm->cp++; + Token id = next_token(); + u32 ptr = get_ptr(id, st); + emit_u32(vm, ptr); + vm->cp += 4; + Token reg = next_token(); + u8 arg = get_reg(reg, st); + emit_byte(vm, arg); + vm->cp++; + reg = next_token(); + arg = get_reg(reg, st); + emit_byte(vm, arg); + vm->cp++; + next_token_is(TOKEN_SEMICOLON); + } else if (strleq(token.start, "jump_le_real", token.length)) { + emit_op(vm, OP_JLE_REAL); + vm->cp++; + Token id = next_token(); + u32 ptr = get_ptr(id, st); + emit_u32(vm, ptr); + vm->cp += 4; + Token reg = next_token(); + u8 arg = get_reg(reg, st); + emit_byte(vm, arg); + vm->cp++; + reg = next_token(); + arg = get_reg(reg, st); + emit_byte(vm, arg); + vm->cp++; + next_token_is(TOKEN_SEMICOLON); + } else if (strleq(token.start, "string_length", token.length)) { + emit_op(vm, OP_STRLEN); + vm->cp++; + Token reg = next_token(); + u8 arg = get_reg(reg, st); + emit_byte(vm, arg); + vm->cp++; + next_token_is(TOKEN_ARROW_RIGHT); + reg = next_token(); + arg = get_reg(reg, st); + emit_byte(vm, arg); + vm->cp++; + next_token_is(TOKEN_SEMICOLON); + } else if (strleq(token.start, "int_to_string", token.length)) { + emit_op(vm, OP_INT_TO_STRING); + vm->cp++; + Token reg = next_token(); + u8 arg = get_reg(reg, st); + emit_byte(vm, arg); + vm->cp++; + next_token_is(TOKEN_ARROW_RIGHT); + reg = next_token(); + arg = get_reg(reg, st); + emit_byte(vm, arg); + vm->cp++; + next_token_is(TOKEN_SEMICOLON); + } else if (strleq(token.start, "nat_to_string", token.length)) { + emit_op(vm, OP_NAT_TO_STRING); + vm->cp++; + Token reg = next_token(); + u8 arg = get_reg(reg, st); + emit_byte(vm, arg); + vm->cp++; + next_token_is(TOKEN_ARROW_RIGHT); + reg = next_token(); + arg = get_reg(reg, st); + emit_byte(vm, arg); + vm->cp++; + next_token_is(TOKEN_SEMICOLON); + } else if (strleq(token.start, "real_to_string", token.length)) { + emit_op(vm, OP_REAL_TO_STRING); + vm->cp++; + Token reg = next_token(); + u8 arg = get_reg(reg, st); + emit_byte(vm, arg); + vm->cp++; + next_token_is(TOKEN_ARROW_RIGHT); + reg = next_token(); + arg = get_reg(reg, st); + emit_byte(vm, arg); + vm->cp++; + next_token_is(TOKEN_SEMICOLON); + ; + } else if (strleq(token.start, "string_eq", token.length)) { + } else if (strleq(token.start, "string_concat", token.length)) { + } else if (strleq(token.start, "string_get_char", token.length)) { + } else if (strleq(token.start, "string_find_char", token.length)) { + } else if (strleq(token.start, "string_slice", token.length)) { + } else if (strleq(token.start, "string_to_int", token.length)) { + } else if (strleq(token.start, "string_to_nat", token.length)) { + } else if (strleq(token.start, "string_to_real", token.length)) { + } else { + /* some other identifier */ + printf("Unknown id at line %d: %.*s\n", token.line, token.length, + token.start); + exit(1); + } + } + } + } while (token.type != TOKEN_EOF); } -static void endCompiler(VM *vm) { emitHalt(vm); } - -static void grouping(VM *vm) { - expression(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; - - advance(); - expression(vm); - consume(TOKEN_EOF, "Expect end of expression."); - endCompiler(vm); - - return parser.hadError; +/** + * Compile. + */ +bool compile(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); } diff --git a/src/tools/compiler/compiler.h b/src/tools/compiler/compiler.h index 59e420b..c921029 100644 --- a/src/tools/compiler/compiler.h +++ b/src/tools/compiler/compiler.h @@ -2,7 +2,9 @@ #define UNDAR_COMPILER_H #import "../../vm/common.h" +#include "../../vm/opcodes.h" +typedef enum { GLOBAL, LOCAL, VAR } ScopeType; typedef enum { VOID, BOOL, @@ -21,17 +23,12 @@ typedef enum { FUNCTION } SymbolType; -typedef struct value_type_s ValueType; -typedef struct function_def_s FunctionDef; -typedef struct function_tab_s FunctionTable; -typedef struct plex_def_s PlexDef; -typedef struct plex_tab_s PlexTable; -typedef struct array_def_s ArrayDef; -typedef struct array_tab_s ArrayTable; typedef struct symbol_s Symbol; typedef struct symbol_tab_s SymbolTable; -typedef struct names_tab_s NamesTable; +typedef struct value_type_s ValueType; typedef struct plex_fields_tab_s PlexFieldsTable; +typedef struct plex_def_s PlexDef; +typedef struct plex_tab_s PlexTable; typedef struct scope_s Scope; typedef struct scope_tab_s ScopeTable; @@ -42,13 +39,6 @@ struct value_type_s { u32 table_ref; // if it is a heap object }; -struct function_def_s { - u32 name; - ValueType args[8]; - u8 arg_count; - ValueType return_type; -}; - struct plex_def_s { u32 name; u32 size; @@ -56,22 +46,6 @@ struct plex_def_s { u32 field_count; }; -struct array_def_s { - ValueType type; - u32 length; - u32 logical_size; // length of the array - u32 physical_size; // logical_size * type_size + fat pointer -}; - -struct symbol_s { - u32 name; - ValueType type; - union { - u32 local; // register - u32 global; // address - } ref; -}; - struct plex_fields_tab_s { u32 *plex_refs; ValueType *fields; @@ -85,38 +59,30 @@ struct plex_tab_s { u32 capacity; }; -struct array_tab_s { - ArrayDef *symbols; - u32 count; - u32 capacity; -}; - -struct function_tab_s { - FunctionDef *symbols; - u32 count; - u32 capacity; -}; - -struct names_tab_s { - char **names; - u32 count; - u32 capacity; +#define MAX_SYMBOL_NAME_LENGTH 64 +struct symbol_s { + char name[MAX_SYMBOL_NAME_LENGTH]; + u8 name_length; + SymbolType type; + ScopeType scope; + u32 ref; // vm->mp if global, vm->pc local, register if var + u32 size; // size of symbol }; struct symbol_tab_s { - Symbol *symbols; - u32 count; - u32 capacity; -}; - -struct scope_s { - SymbolTable table; + Symbol symbols[256]; + u8 count; + i32 parent; }; struct scope_tab_s { - Scope *scopes; + SymbolTable *scopes; u32 count; u32 capacity; + i32 scope_ref; }; +bool compile(VM *vm, ScopeTable *st, char *source); +extern bool table_realloc(ScopeTable *table);/* implement this in arch/ not here */ + #endif diff --git a/test/add.uir.ul b/test/add.uir.ul new file mode 100644 index 0000000..4e33824 --- /dev/null +++ b/test/add.uir.ul @@ -0,0 +1,47 @@ +/** + * Constants + */ +str term_namespace = "/dev/term/0"; +str nl = "\n"; +int x = 0; +int y = 1; + +plex Terminal { + nat handle; +} + +/** + * Main function + */ +function main() { + int tmp0 = x; + int tmp1 = y; + int tmp2 = add(tmp0, tmp1); + str tmp3 = tmp2 as str; + pln(tmp3); +} + +/** + * Add two numbers together + */ +function add(int a, int b) int { + int tmp0 = a + b; + return tmp0; +} + +/** + * Print with a newline + */ +function pln(str message) { + str term_ns = term_namespace; + int mode = 0; + + Terminal term = open(term_ns, mode); + + int msg_len = message.length; + write(term, message, msg_len); + + str nl_local = nl; + int nl_len = nl.length; + write(term, nl_local, nl_len); +} diff --git a/test/fib.uir.ul b/test/fib.uir.ul new file mode 100644 index 0000000..4cb6d6e --- /dev/null +++ b/test/fib.uir.ul @@ -0,0 +1,60 @@ +/** + * Constants + */ +str term_namespace = "/dev/term/0"; +str nl = "\n"; + +plex Terminal { + nat handle; +} + +/** + * Main function + */ +function main() { + int fib = 35; + int ans = fib(35); + str ans_s = ans as str; + pln(ans_s); +} + +/** + * Recursively calculate fibonacci + */ +function fib(int n) int { + int base_check = 2; + + jump_lt_int base_case n base_check; + jump end1; + do base_case; + return n; + else base_case_end; + + int tmp_c2 = 2; + int tmp_c2_n = n - tmp_c2; + int ans_c2 = fib(tmp_c2_n); + + int tmp_c1 = 1; + int tmp_c1_n = tmp_c1 - n; + int ans_c1 = fib(tmp_c1_n); + + int ans = tmp_c1_n + tmp_c2_n; + return ans; +} + +/** + * Print with a newline + */ +function pln(str message) { + str term_ns = term_namespace; + int mode = 0; + + Terminal term = open(term_ns, mode); + + int msg_len = message.length; + write(term, message, msg_len); + + str nl_local = nl; + int nl_len = nl.length; + write(term, nl_local, nl_len); +} diff --git a/test/hello.uir.ul b/test/hello.uir.ul new file mode 100644 index 0000000..e54ea7e --- /dev/null +++ b/test/hello.uir.ul @@ -0,0 +1,32 @@ +str term_namespace = "/dev/term/0"; +str hello = "nuqneH 'u'?"; +str nl = "\n"; + +plex Terminal { + nat handle; +} + +/** + * Main function + */ +function main() { + str msg = hello; + pln(msg); +} + +/** + * Print with a newline + */ +function pln(str message) { + str term_ns = term_namespace; + int mode = 0; + + Terminal term = open(term_ns, mode); + + int msg_len = message.length; + write(term, message, msg_len); + + str nl_local = nl; + int nl_len = nl.length; + write(term, nl_local, nl_len); +} diff --git a/test/hello.ul b/test/hello.ul index 396daf5..31553f8 100644 --- a/test/hello.ul +++ b/test/hello.ul @@ -1,8 +1,6 @@ /** - * Constants + * Plexes */ -const str nl = "\n"; - plex Terminal { nat handle; } @@ -20,5 +18,6 @@ function main() { function pln(str message) { Terminal term = open("/dev/term/0", 0); write(term, message, message.length); + const str nl = "\n"; write(term, nl, nl.length); } diff --git a/test/loop.uir.ul b/test/loop.uir.ul new file mode 100644 index 0000000..8a37d99 --- /dev/null +++ b/test/loop.uir.ul @@ -0,0 +1,65 @@ +str term_namespace = "/dev/term/0"; +str prompt = "Enter a string:"; +str nl = "\n"; + + +plex Terminal { + nat handle; +} + +/** + * Main function + */ +function main() { + str term_ns = term_namespace; + int mode = 0; + + Terminal term = open(term_ns, mode); + + real a = 5.0; + + // do (int i = 5000; i >= 0, i = i - 1) + int i = 5000; + int tmp0 = 0; + int tmp1 = 1; + int tmp2 = 5.0; + loop loop_body { + a = a + tmp2; + i = i - tmp1; + jump_ge_int loop_body i tmp0; + } + + nat b = a as nat; + str local_prompt = prompt; + pln(local_prompt); + + nat size = 32; + str user_string = malloc(size); + read(term, user_string, size); + + str a_str = a as str; + pln(a_str); + + str b_str = b as str; + pln(b_str); + + pln(user_string); +} + +/** + * Print with a newline + */ +function pln(str message) { + str term_ns = term_namespace; + int mode = 0; + + Terminal term = open(term_ns, mode); + + int msg_len = message.length; + write(term, message, msg_len); + + str nl_local = nl; + int nl_len = nl.length; + write(term, nl_local, nl_len); +} + diff --git a/test/malloc.uir.ul b/test/malloc.uir.ul new file mode 100644 index 0000000..6c81ea3 --- /dev/null +++ b/test/malloc.uir.ul @@ -0,0 +1,26 @@ +/** + * Constants + */ +const str nl = "\n"; + +plex Terminal { + nat handle; +} + +/** + * Main function + */ +function main() { + Terminal term = open("/dev/term/0", 0); + pln(term, "Enter a string: "); + pln(term, term.read(32)); + return 0; +} + +/** + * Print with a newline + */ +function pln(Terminal term, str message) { + write(term, message, message.length); + write(term, nl, nl.length); +} diff --git a/test/paint.uir.ul b/test/paint.uir.ul new file mode 100644 index 0000000..55a017d --- /dev/null +++ b/test/paint.uir.ul @@ -0,0 +1,278 @@ +str screen_namespace = "/dev/screen/0"; +str mouse_namespace = "/dev/mouse/0"; +byte BLACK = 0; +byte WHITE = 255; +byte DARK_GRAY = 73; +byte GRAY = 146; +byte LIGHT_GRAY = 182; +byte CHARCOAL = 36; +byte DARK_RED = 128; +byte RED = 224; +byte DARK_YELLOW = 144; +byte YELLOW = 252; +byte DARK_TEAL = 9; +byte TEAL = 18; +byte DARK_GREEN = 12; +byte GREEN = 16; +byte LIME = 28; +byte LIGHT_CYAN = 159; +byte NAVY = 2; +byte BLUE = 3; +byte DEEP_SKY_BLUE = 10; +byte LIGHT_BLUE = 19; +byte PURPLE = 131; +byte LIGHT_PURPLE = 147; +byte DARK_MAGENTA = 130; +byte MAGENTA = 227; +byte PLUM = 129; +byte PINK = 226; +byte SADDLE_BROWN = 72; +byte PERU = 141; +byte SIENNA = 136; +byte ORANGE = 241; +byte DARK_ORANGE = 208; +byte GOLD = 244; +byte SELECTED_COLOR = 255; + +plex Screen { + nat handle; + nat width; + nat height; + byte[] buffer; +} + +plex Mouse { + nat handle; + nat x; + nat y; + bool left; + bool right; + bool middle; + bool btn4; +} + +function main () { + str screen_name = screen_namespace; + int mode = 0; + Screen screen = open(screen_name, mode); + + nat width = screen.width; + nat size = screen.size; + nat screen_offset = 16; + nat screen_buffer = screen_buffer + screen_offset; + + // open mouse + str mouse_name = mouse_namespace; + Mouse mouse = open(mouse_name, mode); + + byte color = BLACK; + nat x_pos = 1; + nat y_pos = 1; + draw_outlined_swatch(screen_buffer, color, x_pos, y_pos, width); + + color = WHITE; + x_pos = 21; + y_pos = 1; + draw_outlined_swatch(screen_buffer, color, x_pos, y_pos, width); + + color = CHARCOAL; + x_pos = 1; + y_pos = 21; + draw_outlined_swatch(screen_buffer, color, x_pos, y_pos, width); + + color = DARK_GRAY; + x_pos = 21; + y_pos = 21; + draw_outlined_swatch(screen_buffer, color, x_pos, y_pos, width); + + color = RED; + x_pos = 1; + y_pos = 41; + draw_outlined_swatch(screen_buffer, color, x_pos, y_pos, width); + + color = ORANGE; + x_pos = 21; + y_pos = 41; + draw_outlined_swatch(screen_buffer, color, x_pos, y_pos, width); + + color = YELLOW; + x_pos = 1; + y_pos = 61; + draw_outlined_swatch(screen_buffer, color, x_pos, y_pos, width); + + color = GREEN; + x_pos = 21; + y_pos = 61; + draw_outlined_swatch(screen_buffer, color, x_pos, y_pos, width); + + color = BLUE; + x_pos = 1; + y_pos = 81; + draw_outlined_swatch(screen_buffer, color, x_pos, y_pos, width); + + color = PURPLE; + x_pos = 21; + y_pos = 81; + draw_outlined_swatch(screen_buffer, color, x_pos, y_pos, width); + + // screen.draw + write(screen, screen_buffer, size); + + nat zero = 0; + + loop draw { + // load mouse click data + refresh(mouse); + + byte left_down = mouse.down; + + jump_eq_nat draw left_down zero; // if (!btn1.left) continue; + + nat mouse_x = mouse.x; + nat mouse_y = mouse.y; + + nat box_size = 20; + + // first row + color = BLACK; + x_pos = 1; + y_pos = 1; + draw_outlined_swatch(screen_buffer, color, x_pos, y_pos, width); + set_color(mouse_x, mouse_y, x_pos, y_pos, color, box_size); + + color = WHITE; + x_pos = 21; + y_pos = 1; + draw_outlined_swatch(screen_buffer, color, x_pos, y_pos, width); + set_color(mouse_x, mouse_y, x_pos, y_pos, color, box_size); + + color = CHARCOAL; + x_pos = 1; + y_pos = 21; + draw_outlined_swatch(screen_buffer, color, x_pos, y_pos, width); + set_color(mouse_x, mouse_y, x_pos, y_pos, color, box_size); + + DARK_GRAY -> color; + x_pos = 21; + y_pos = 21; + draw_outlined_swatch(screen_buffer, color, x_pos, y_pos, width); + set_color(mouse_x, mouse_y, x_pos, y_pos, color, box_size); + + color = RED; + x_pos = 1; + y_pos = 41; + draw_outlined_swatch(screen_buffer, color, x_pos, y_pos, width); + set_color(mouse_x, mouse_y, x_pos, y_pos, color, box_size); + + color = ORANGE; + x_pos = 21; + y_pos = 41; + draw_outlined_swatch(screen_buffer, color, x_pos, y_pos, width); + set_color(mouse_x, mouse_y, x_pos, y_pos, color, box_size); + + color = YELLOW; + x_pos = 1; + y_pos = 61; + draw_outlined_swatch(screen_buffer, color, x_pos, y_pos, width); + set_color(mouse_x, mouse_y, x_pos, y_pos, color, box_size); + + color = GREEN; + x_pos = 21; + y_pos = 61; + draw_outlined_swatch(screen_buffer, color, x_pos, y_pos, width); + set_color(mouse_x, mouse_y, x_pos, y_pos, color, box_size); + + color = BLUE; + x_pos = 1; + y_pos = 81; + draw_outlined_swatch(screen_buffer, color, x_pos, y_pos, width); + set_color(mouse_x, mouse_y, x_pos, y_pos, color, box_size); + + color = PURPLE; + x_pos = 21; + y_pos = 81; + draw_outlined_swatch(screen_buffer, color, x_pos, y_pos, width); + set_color(mouse_x, mouse_y, x_pos, y_pos, color, box_size); + + write(screen, screen_buffer, size); + + byte selected_color = SELECTED_COLOR; + + nat brush_size = 5; + + draw_box(screen_buffer, width, selected_color, mouse_x, mouse_y, brush_size, brush_size); + + jump draw; + } + + // Flush and exit + exit 0; +} + +function set_color (int click_x, int click_y, int box_x, int box_y, byte check_color, int size) { + + // Compute right + int right_edge = box_x + size; + + // Compute bottom = box_y + size + int bottom_edge = box_y + size; + + // Bounds check: x in [box_x, right] and y in [box_y, bottom] + jump_lt_int fail click_x box_x; + jump_gt_int fail click_x right_edge; + jump_lt_int fail click_y box_y; + jump_gt_int fail click_y bottom_edge; + + SELECTED_COLOR = check_color; + + else fail + return; +} + +function draw_outlined_swatch(nat base, byte swatch_color, int x, int y, int width) { + + nat background_color = GRAY; + byte selected_color = SELECTED_COLOR; + + jump_eq_int set_selected swatch_color selected_color; + jump end_set_selected; + do set_selected + background_color = DARK_GRAY; + else end_set_selected + + nat outline_size = 20; + nat fill_size = 17; + + draw_box(base, width, background_color, x, y, outline_size, outline_size); + + nat offset = 2; + int xO = x + offset; // x + 2 + int yO = y + offset; // y + 2 + + draw_box(base, width, swatch_color, xO, yO, fill_size, fill_size); + + return; +} + +function draw_box (nat base, nat screen_width, byte box_color, + nat x, nat y, nat width, nat height) { + + nat fat_ptr_size = 4; + + // Compute start address: base + y*640 + x + nat offset = y * screen_width; + offset = offset + x; + offset = offset + base; + offset = offset + fat_ptr_size; // need to add offset for fat pointer size + + int i = 1; + int zero = 0; + + loop draw_box_outer { + memset(offset, width, box_color); // draw row + offset = offset + screen_width; // next row += 640 + height = height - i; // decrement row count + jump_gt_int draw_box_outer height zero; + } + return; +}