2633 lines
78 KiB
C
2633 lines
78 KiB
C
#include "assembler.h"
|
|
#include "../../vm/common.h"
|
|
#include "../../vm/fixed.h"
|
|
#include "../../vm/libc.h"
|
|
#include "../../vm/opcodes.h"
|
|
#include "lexer.h"
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
|
|
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 "<invalid-opcode>";
|
|
}
|
|
|
|
const char *name = names[op];
|
|
return name ? name : "<unknown-opcode>";
|
|
}
|
|
|
|
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);
|
|
}
|