#include "assembler.h" #include "../../vm/common.h" #include "../../vm/fixed.h" #include "../../vm/libc.h" #include "../../vm/opcodes.h" #include "lexer.h" #include #include #include const char *opcode_to_string(Opcode op) { static const char *names[] = { [OP_EXIT] = "exit", [OP_JMP] = "jump", [OP_JMPF] = "jump-if-flag", [OP_CALL] = "call", [OP_RETURN] = "return", /* Immediate loads (only 32-bit variant needed) */ [OP_LOAD_IMM] = "load-immediate", /* Register-indirect loads */ [OP_LOAD_IND_8] = "load-indirect-8", [OP_LOAD_IND_16] = "load-indirect-16", [OP_LOAD_IND_32] = "load-indirect-32", /* Absolute address loads */ [OP_LOAD_ABS_8] = "load-absolute-8", [OP_LOAD_ABS_16] = "load-absolute-16", [OP_LOAD_ABS_32] = "load-absolute-32", /* Base+offset loads */ [OP_LOAD_OFF_8] = "load-offset-8", [OP_LOAD_OFF_16] = "load-offset-16", [OP_LOAD_OFF_32] = "load-offset-32", /* Absolute address stores */ [OP_STORE_ABS_8] = "store-absolute-8", [OP_STORE_ABS_16] = "store-absolute-16", [OP_STORE_ABS_32] = "store-absolute-32", /* Register-indirect stores */ [OP_STORE_IND_8] = "store-indirect-8", [OP_STORE_IND_16] = "store-indirect-16", [OP_STORE_IND_32] = "store-indirect-32", /* Base+offset stores */ [OP_STORE_OFF_8] = "store-offset-8", [OP_STORE_OFF_16] = "store-offset-16", [OP_STORE_OFF_32] = "store-offset-32", /* Memory operations */ [OP_MALLOC] = "malloc", [OP_MEMSET_8] = "memset-8", [OP_MEMSET_16] = "memset-16", [OP_MEMSET_32] = "memset-32", /* Register operations */ [OP_REG_MOV] = "register-move", [OP_SYSCALL] = "syscall", /* Bit operations */ [OP_BIT_SHIFT_LEFT] = "bit-shift-left", [OP_BIT_SHIFT_RIGHT] = "bit-shift-right", [OP_BIT_SHIFT_R_EXT] = "bit-shift-re", [OP_BAND] = "bit-and", [OP_BOR] = "bit-or", [OP_BXOR] = "bit-xor", /* Integer arithmetic */ [OP_ADD_INT] = "add-int", [OP_SUB_INT] = "sub-int", [OP_MUL_INT] = "mul-int", [OP_DIV_INT] = "div-int", /* Natural number arithmetic */ [OP_ADD_NAT] = "add-nat", [OP_SUB_NAT] = "sub-nat", [OP_MUL_NAT] = "mul-nat", [OP_DIV_NAT] = "div-nat", /* Floating point operations */ [OP_ADD_REAL] = "add-real", [OP_SUB_REAL] = "sub-real", [OP_MUL_REAL] = "mul-real", [OP_DIV_REAL] = "div-real", /* Type conversions */ [OP_INT_TO_REAL] = "int-to-real", [OP_NAT_TO_REAL] = "nat-to-real", [OP_REAL_TO_INT] = "real-to-int", [OP_REAL_TO_NAT] = "real-to-nat", /* Integer comparisons */ [OP_JEQ_INT] = "jump-eq-int", [OP_JNEQ_INT] = "jump-neq-int", [OP_JGT_INT] = "jump-gt-int", [OP_JLT_INT] = "jump-lt-int", [OP_JLE_INT] = "jump-le-int", [OP_JGE_INT] = "jump-ge-int", /* Natural number comparisons */ [OP_JEQ_NAT] = "jump-eq-nat", [OP_JNEQ_NAT] = "jump-neq-nat", [OP_JGT_NAT] = "jump-gt-nat", [OP_JLT_NAT] = "jump-lt-nat", [OP_JLE_NAT] = "jump-le-nat", [OP_JGE_NAT] = "jump-ge-nat", /* Floating point comparisons */ [OP_JEQ_REAL] = "jump-eq-real", [OP_JNEQ_REAL] = "jump-neq-real", [OP_JGE_REAL] = "jump-ge-real", [OP_JGT_REAL] = "jump-gt-real", [OP_JLT_REAL] = "jump-lt-real", [OP_JLE_REAL] = "jump-le-real", /* String operations */ [OP_STRLEN] = "string-length", [OP_STREQ] = "string-eq", [OP_STRCAT] = "string-concat", [OP_STR_GET_CHAR] = "string-get-char", [OP_STR_FIND_CHAR] = "string-find-char", [OP_STR_SLICE] = "string-slice", /* String conversions */ [OP_INT_TO_STRING] = "int-to-string", [OP_NAT_TO_STRING] = "nat-to-string", [OP_REAL_TO_STRING] = "real-to-string", [OP_STRING_TO_INT] = "string-to-int", [OP_STRING_TO_NAT] = "string-to-nat", [OP_STRING_TO_REAL] = "string-to-real" }; if (op < 0 || op >= (int)(sizeof(names) / sizeof(names[0]))) { return ""; } const char *name = names[op]; return name ? name : ""; } void emit_op(VM *vm, u8 byte) { printf("vm->code[%d] = %s\n", vm->cp, opcode_to_string(byte)); vm->code[vm->cp] = byte; } void emit_byte(VM *vm, u8 byte) { printf("vm->code[%d] = %d\n", vm->cp, byte); vm->code[vm->cp] = byte; } void emit_u32(VM *vm, u32 value) { printf("vm->code[%d..%d] = %d\n", vm->cp, vm->cp+3, value); write_u32(vm, code, vm->cp, value); } void symbol_table_init(SymbolTable *table) { table->symbols = calloc(16, sizeof(Symbol)); table->count = 0; table->capacity = 16; } u32 symbol_table_add(SymbolTable *table, Symbol s) { if (table->count >= table->capacity) { table->capacity *= 2; table->symbols = realloc(table->symbols, table->capacity * sizeof(Symbol)); } if (s.scope == VAR) { // ignore for now // 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); } table->symbols[table->count] = s; u32 index = table->count; table->count++; return index; } 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]; } } } return nil; } u32 get_ref(SymbolTable *st, const char *name, u32 length) { Symbol *sym = symbol_table_lookup(st, name, length); if (!sym) { fprintf(stderr, "Error: Undefined Symbol '%.*s'\n", length, name); exit(1); return 0; } return sym->ref; } u32 get_ptr(Token token, SymbolTable *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: '%.*s'\n", token.length, token.start); exit(1); } return out; } fprintf(stderr, "Error: Not a register or symbol '%.*s'\n", token.length, token.start); exit(1); } u32 get_reg(Token token, SymbolTable *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 '%.*s'\n", 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, SymbolTable *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; } 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; // Keep as-is 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; } /** * Var . */ void define_var(SymbolTable *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_TYPE_I8: { s.type = I8; s.size = 1; break; } 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: printf("ERROR at line %d: %.*s\n", regType.line, regType.length, regType.start); exit(1); } 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); } /** * function . */ void define_function(VM *vm, SymbolTable *st) { Symbol s; s.scope = LOCAL; s.type = FUNCTION; 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; next_token_is(TOKEN_LPAREN); 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; symbol_table_add(st, s); } /** * Branch. */ void define_branch(VM *vm, SymbolTable *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.ref = vm->cp; symbol_table_add(st, s); } /** * Build the symbol table and calculate the types/size/offsets of all values. */ void build_symbol_table(VM *vm, char *source, SymbolTable *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); } printf("Line %d [%s]: %.*s cp=%d mp=%d\n", token.line, token_type_to_string(token.type), token.length, token.start, vm->cp, vm->mp); 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; } 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; next_token_is(TOKEN_SEMICOLON); } else if (strleq(token.start, "call", token.length)) { vm->cp++; next_token_is(TOKEN_IDENTIFIER); vm->cp += 4; bool has_return = false; vm->cp++; Token next = next_token(); while (next.type != TOKEN_SEMICOLON) { if (next.type != TOKEN_ARROW_RIGHT) { get_reg(next, st); vm->cp++; } else { has_return = true; } next = next_token(); } if (!has_return) { vm->cp+=2; 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) { if (next.type != TOKEN_ARROW_RIGHT) { vm->cp++; } next = next_token(); } } else if (strleq(token.start, "load_immediate", token.length)) { while (token.type != TOKEN_SEMICOLON) token = next_token(); vm->cp++; vm->cp += 4; vm->cp++; } else if (strleq(token.start, "load_address", token.length)) { while (token.type != TOKEN_SEMICOLON) token = next_token(); vm->cp++; vm->cp += 4; vm->cp++; } else if (strleq(token.start, "malloc", token.length)) { while (token.type != TOKEN_SEMICOLON) token = next_token(); vm->cp++; vm->cp++; vm->cp++; } else if (strleq(token.start, "memset_8", token.length)) { while (token.type != TOKEN_SEMICOLON) token = next_token(); vm->cp++; vm->cp++; vm->cp++; vm->cp++; } else if (strleq(token.start, "memset_16", token.length)) { while (token.type != TOKEN_SEMICOLON) token = next_token(); vm->cp++; vm->cp++; vm->cp++; vm->cp++; } else if (strleq(token.start, "memset_32", token.length)) { while (token.type != TOKEN_SEMICOLON) token = next_token(); vm->cp++; vm->cp++; vm->cp++; vm->cp++; } else if (strleq(token.start, "load_offset_8", token.length)) { while (token.type != TOKEN_SEMICOLON) token = next_token(); vm->cp++; vm->cp++; vm->cp += 4; vm->cp++; } else if (strleq(token.start, "load_offset_16", token.length)) { while (token.type != TOKEN_SEMICOLON) token = next_token(); vm->cp++; vm->cp++; vm->cp += 4; vm->cp++; } else if (strleq(token.start, "load_offset_32", token.length)) { while (token.type != TOKEN_SEMICOLON) token = next_token(); vm->cp++; vm->cp++; vm->cp += 4; vm->cp++; } else if (strleq(token.start, "load_indirect_8", token.length)) { while (token.type != TOKEN_SEMICOLON) token = next_token(); vm->cp++; vm->cp+=4; vm->cp++; } else if (strleq(token.start, "load_indirect_16", token.length)) { while (token.type != TOKEN_SEMICOLON) token = next_token(); vm->cp++; vm->cp+=4; vm->cp++; } else if (strleq(token.start, "load_indirect_32", token.length)) { while (token.type != TOKEN_SEMICOLON) token = next_token(); vm->cp++; vm->cp += 4; vm->cp++; } else if (strleq(token.start, "load_absolute_8", token.length)) { while (token.type != TOKEN_SEMICOLON) token = next_token(); vm->cp++; vm->cp += 4; vm->cp++; } else if (strleq(token.start, "load_absolute_16", token.length)) { while (token.type != TOKEN_SEMICOLON) token = next_token(); vm->cp++; vm->cp += 4; vm->cp++; } else if (strleq(token.start, "load_absolute_32", token.length)) { while (token.type != TOKEN_SEMICOLON) token = next_token(); vm->cp++; vm->cp += 4; vm->cp++; } else if (strleq(token.start, "store_absolute_8", token.length)) { while (token.type != TOKEN_SEMICOLON) token = next_token(); vm->cp++; vm->cp++; vm->cp += 4; } else if (strleq(token.start, "store_absolute_16", token.length)) { while (token.type != TOKEN_SEMICOLON) token = next_token(); vm->cp++; vm->cp++; vm->cp += 4; } else if (strleq(token.start, "store_absolute_32", token.length)) { while (token.type != TOKEN_SEMICOLON) token = next_token(); vm->cp++; vm->cp++; vm->cp += 4; } else if (strleq(token.start, "store_indirect_8", token.length)) { while (token.type != TOKEN_SEMICOLON) token = next_token(); vm->cp++; vm->cp++; vm->cp += 4; } else if (strleq(token.start, "store_indirect_16", token.length)) { while (token.type != TOKEN_SEMICOLON) token = next_token(); vm->cp++; vm->cp++; vm->cp += 4; } else if (strleq(token.start, "store_indirect_32", token.length)) { while (token.type != TOKEN_SEMICOLON) token = next_token(); vm->cp++; vm->cp++; vm->cp += 4; } else if (strleq(token.start, "store_offset_8", token.length)) { while (token.type != TOKEN_SEMICOLON) token = next_token(); vm->cp++; vm->cp++; vm->cp += 4; vm->cp++; } else if (strleq(token.start, "store_offset_16", token.length)) { while (token.type != TOKEN_SEMICOLON) token = next_token(); vm->cp++; vm->cp++; vm->cp += 4; vm->cp++; } else if (strleq(token.start, "store_offset_32", token.length)) { while (token.type != TOKEN_SEMICOLON) token = next_token(); vm->cp++; vm->cp++; vm->cp += 4; vm->cp++; } else if (strleq(token.start, "register_move", token.length)) { while (token.type != TOKEN_SEMICOLON) token = next_token(); vm->cp++; vm->cp++; vm->cp++; } else if (strleq(token.start, "add_int", token.length)) { while (token.type != TOKEN_SEMICOLON) token = next_token(); vm->cp++; vm->cp++; vm->cp++; vm->cp++; } else if (strleq(token.start, "sub_int", token.length)) { while (token.type != TOKEN_SEMICOLON) token = next_token(); vm->cp++; vm->cp++; vm->cp++; vm->cp++; } else if (strleq(token.start, "mul_int", token.length)) { while (token.type != TOKEN_SEMICOLON) token = next_token(); vm->cp++; vm->cp++; vm->cp++; vm->cp++; } else if (strleq(token.start, "div_int", token.length)) { while (token.type != TOKEN_SEMICOLON) token = next_token(); vm->cp++; vm->cp++; vm->cp++; vm->cp++; } else if (strleq(token.start, "abs_int", token.length)) { while (token.type != TOKEN_SEMICOLON) token = next_token(); vm->cp++; vm->cp++; vm->cp++; } else if (strleq(token.start, "neg_int", token.length)) { while (token.type != TOKEN_SEMICOLON) token = next_token(); vm->cp++; vm->cp++; vm->cp++; } else if (strleq(token.start, "add_nat", token.length)) { while (token.type != TOKEN_SEMICOLON) token = next_token(); vm->cp++; vm->cp++; vm->cp++; vm->cp++; } else if (strleq(token.start, "sub_nat", token.length)) { while (token.type != TOKEN_SEMICOLON) token = next_token(); vm->cp++; vm->cp++; vm->cp++; vm->cp++; } else if (strleq(token.start, "mul_nat", token.length)) { while (token.type != TOKEN_SEMICOLON) token = next_token(); vm->cp++; vm->cp++; vm->cp++; vm->cp++; } else if (strleq(token.start, "div_nat", token.length)) { while (token.type != TOKEN_SEMICOLON) token = next_token(); vm->cp++; vm->cp++; vm->cp++; vm->cp++; } else if (strleq(token.start, "abs_nat", token.length)) { while (token.type != TOKEN_SEMICOLON) token = next_token(); vm->cp++; vm->cp++; vm->cp++; } else if (strleq(token.start, "neg_nat", token.length)) { while (token.type != TOKEN_SEMICOLON) token = next_token(); vm->cp++; vm->cp++; vm->cp++; } else if (strleq(token.start, "add_real", token.length)) { while (token.type != TOKEN_SEMICOLON) token = next_token(); vm->cp++; vm->cp++; vm->cp++; vm->cp++; } else if (strleq(token.start, "sub_real", token.length)) { while (token.type != TOKEN_SEMICOLON) token = next_token(); vm->cp++; vm->cp++; vm->cp++; vm->cp++; } else if (strleq(token.start, "mul_real", token.length)) { while (token.type != TOKEN_SEMICOLON) token = next_token(); vm->cp++; vm->cp++; vm->cp++; vm->cp++; } else if (strleq(token.start, "div_real", token.length)) { while (token.type != TOKEN_SEMICOLON) token = next_token(); vm->cp++; vm->cp++; vm->cp++; vm->cp++; } else if (strleq(token.start, "abs_real", token.length)) { while (token.type != TOKEN_SEMICOLON) token = next_token(); vm->cp++; vm->cp++; vm->cp++; } else if (strleq(token.start, "neg_real", token.length)) { while (token.type != TOKEN_SEMICOLON) token = next_token(); vm->cp++; vm->cp++; vm->cp++; } else if (strleq(token.start, "int_to_real", token.length)) { while (token.type != TOKEN_SEMICOLON) token = next_token(); vm->cp++; vm->cp++; vm->cp++; } else if (strleq(token.start, "nat_to_real", token.length)) { while (token.type != TOKEN_SEMICOLON) token = next_token(); vm->cp++; vm->cp++; vm->cp++; } else if (strleq(token.start, "real_to_int", token.length)) { while (token.type != TOKEN_SEMICOLON) token = next_token(); vm->cp++; vm->cp++; vm->cp++; } else if (strleq(token.start, "real_to_nat", token.length)) { while (token.type != TOKEN_SEMICOLON) token = next_token(); vm->cp++; vm->cp++; vm->cp++; } else if (strleq(token.start, "bit_shift_left", token.length)) { while (token.type != TOKEN_SEMICOLON) token = next_token(); vm->cp++; vm->cp++; vm->cp++; vm->cp++; } else if (strleq(token.start, "bit_shift_right", token.length)) { while (token.type != TOKEN_SEMICOLON) token = next_token(); vm->cp++; vm->cp++; vm->cp++; vm->cp++; } else if (strleq(token.start, "bit_shift_r_ext", token.length)) { while (token.type != TOKEN_SEMICOLON) token = next_token(); vm->cp++; vm->cp++; vm->cp++; vm->cp++; } else if (strleq(token.start, "bit_and", token.length)) { while (token.type != TOKEN_SEMICOLON) token = next_token(); vm->cp++; vm->cp++; vm->cp++; vm->cp++; } else if (strleq(token.start, "bit_or", token.length)) { while (token.type != TOKEN_SEMICOLON) token = next_token(); vm->cp++; vm->cp++; vm->cp++; vm->cp++; } else if (strleq(token.start, "bit_xor", token.length)) { while (token.type != TOKEN_SEMICOLON) token = next_token(); vm->cp++; vm->cp++; vm->cp++; vm->cp++; } else if (strleq(token.start, "jump", token.length)) { while (token.type != TOKEN_SEMICOLON) token = next_token(); vm->cp++; vm->cp+=4; } else if (strleq(token.start, "jump_if_flag", token.length)) { while (token.type != TOKEN_SEMICOLON) token = next_token(); vm->cp++; vm->cp+=4; } else if (strleq(token.start, "jump_eq_int", token.length)) { while (token.type != TOKEN_SEMICOLON) token = next_token(); vm->cp++; vm->cp+=4; vm->cp++; vm->cp++; } else if (strleq(token.start, "jump_neq_int", token.length)) { while (token.type != TOKEN_SEMICOLON) token = next_token(); vm->cp++; vm->cp+=4; vm->cp++; vm->cp++; } else if (strleq(token.start, "jump_gt_int", token.length)) { while (token.type != TOKEN_SEMICOLON) token = next_token(); vm->cp++; vm->cp+=4; vm->cp++; vm->cp++; } else if (strleq(token.start, "jump_lt_int", token.length)) { while (token.type != TOKEN_SEMICOLON) token = next_token(); vm->cp++; vm->cp+=4; vm->cp++; vm->cp++; } else if (strleq(token.start, "jump_le_int", token.length)) { while (token.type != TOKEN_SEMICOLON) token = next_token(); vm->cp++; vm->cp+=4; vm->cp++; vm->cp++; } else if (strleq(token.start, "jump_ge_int", token.length)) { while (token.type != TOKEN_SEMICOLON) token = next_token(); vm->cp++; vm->cp+=4; vm->cp++; vm->cp++; } else if (strleq(token.start, "jump_eq_nat", token.length)) { while (token.type != TOKEN_SEMICOLON) token = next_token(); vm->cp++; vm->cp+=4; vm->cp++; vm->cp++; } else if (strleq(token.start, "jump_neq_nat", token.length)) { while (token.type != TOKEN_SEMICOLON) token = next_token(); vm->cp++; vm->cp+=4; vm->cp++; vm->cp++; } else if (strleq(token.start, "jump_gt_nat", token.length)) { while (token.type != TOKEN_SEMICOLON) token = next_token(); vm->cp++; vm->cp+=4; vm->cp++; vm->cp++; } else if (strleq(token.start, "jump_lt_nat", token.length)) { while (token.type != TOKEN_SEMICOLON) token = next_token(); vm->cp++; vm->cp+=4; vm->cp++; vm->cp++; } else if (strleq(token.start, "jump_le_nat", token.length)) { while (token.type != TOKEN_SEMICOLON) token = next_token(); vm->cp++; vm->cp+=4; vm->cp++; vm->cp++; } else if (strleq(token.start, "jump_ge_nat", token.length)) { while (token.type != TOKEN_SEMICOLON) token = next_token(); vm->cp++; vm->cp+=4; vm->cp++; vm->cp++; } else if (strleq(token.start, "jump_eq_real", token.length)) { while (token.type != TOKEN_SEMICOLON) token = next_token(); vm->cp++; vm->cp+=4; vm->cp++; vm->cp++; } else if (strleq(token.start, "jump_neq_real", token.length)) { while (token.type != TOKEN_SEMICOLON) token = next_token(); vm->cp++; vm->cp+=4; vm->cp++; vm->cp++; } else if (strleq(token.start, "jump_ge_real", token.length)) { while (token.type != TOKEN_SEMICOLON) token = next_token(); vm->cp++; vm->cp+=4; vm->cp++; vm->cp++; } else if (strleq(token.start, "jump_gt_real", token.length)) { while (token.type != TOKEN_SEMICOLON) token = next_token(); vm->cp++; vm->cp+=4; vm->cp++; vm->cp++; } else if (strleq(token.start, "jump_lt_real", token.length)) { while (token.type != TOKEN_SEMICOLON) token = next_token(); vm->cp++; vm->cp+=4; vm->cp++; vm->cp++; } else if (strleq(token.start, "jump_le_real", token.length)) { while (token.type != TOKEN_SEMICOLON) token = next_token(); vm->cp++; vm->cp+=4; vm->cp++; vm->cp++; } else if (strleq(token.start, "string_length", token.length)) { while (token.type != TOKEN_SEMICOLON) token = next_token(); vm->cp++; vm->cp++; vm->cp++; } else if (strleq(token.start, "int_to_string", token.length)) { while (token.type != TOKEN_SEMICOLON) token = next_token(); vm->cp++; vm->cp++; vm->cp++; } else if (strleq(token.start, "nat_to_string", token.length)) { while (token.type != TOKEN_SEMICOLON) token = next_token(); vm->cp++; vm->cp++; vm->cp++; } else if (strleq(token.start, "real_to_string", token.length)) { while (token.type != TOKEN_SEMICOLON) token = next_token(); vm->cp++; vm->cp++; vm->cp++; } 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); } /** * 2nd pass, emit the bytecode */ void emit_bytecode(VM *vm, char *source, SymbolTable *st) { USED(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) { //printf("[Generate Bytecode cp=%d mp=%d ] Line %d [%s]: %.*s\n", vm->cp, // vm->mp, token.line, token_type_to_string(token.type), token.length, // token.start); 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; } 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; bool has_return = false; u8 arg_count = 0; u32 arg_pos = vm->cp++; printf("vm->code[%d] = ?\n", arg_pos); Token next = next_token(); while (next.type != TOKEN_SEMICOLON) { if (next.type != TOKEN_ARROW_RIGHT) { u8 arg = get_reg(next, st); emit_byte(vm, arg); vm->cp++; arg_count++; } else { has_return = true; arg_count--; // is a return not an arg } next = next_token(); } /* patch number of args */ vm->code[arg_pos] = arg_count; printf("^vm->code[%d] = %d\n", arg_pos, arg_count); if (!has_return) { vm->cp+=2; emit_byte(vm, 255); 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) { if (next.type != TOKEN_ARROW_RIGHT) { u8 arg = get_reg(next, st); emit_byte(vm, arg); vm->cp++; } next = next_token(); } } 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++; 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++; 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++; 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); 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_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); 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_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); 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_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); } /** * Emit bytecode to the VM from the source string. */ void assemble(VM *vm, char *source) { SymbolTable st = {0}; symbol_table_init(&st); build_symbol_table(vm, source, &st); vm->cp = 0; /* actuall start emitting code */ emit_bytecode(vm, source, &st); free(st.symbols); }