WIP function calls
This commit is contained in:
parent
aab4c887ca
commit
0263d1511d
162
src/compiler.c
162
src/compiler.c
|
@ -33,141 +33,39 @@ void demo_add_compile(Value *memory) {
|
||||||
memory[i++].u = OP(OP_HALT, 0, 0, 0);
|
memory[i++].u = OP(OP_HALT, 0, 0, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static void letDeclaration() {
|
||||||
|
/* uint8_t global = parseVariable("Expect variable name."); */
|
||||||
|
|
||||||
|
/* if (match(TOKEN_EQUAL)) { */
|
||||||
|
/* expression(); */
|
||||||
|
/* } else { */
|
||||||
|
/* emitByte(OP_NIL); */
|
||||||
|
/* } */
|
||||||
|
/* consume(TOKEN_SEMICOLON, */
|
||||||
|
/* "Expect ';' after variable declaration."); */
|
||||||
|
|
||||||
|
/* defineVariable(global); */
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static void declaration(Token t) {
|
||||||
|
if (t.type == TOKEN_LET) {
|
||||||
|
letDeclaration();
|
||||||
|
} else {
|
||||||
|
/* statement(); */
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Compile.
|
||||||
|
*/
|
||||||
void compile(Value *memory, char *buffer) {
|
void compile(Value *memory, char *buffer) {
|
||||||
initTokenizer(buffer);
|
initTokenizer(buffer);
|
||||||
Token t = nextToken();
|
Token t = nextToken();
|
||||||
do {
|
while (t.type != TOKEN_EOF) {
|
||||||
printToken(t);
|
printToken(t);
|
||||||
switch (t.type) {
|
declaration(t);
|
||||||
case TOKEN_LEFT_PAREN:
|
|
||||||
break;
|
|
||||||
case TOKEN_RIGHT_PAREN:
|
|
||||||
break;
|
|
||||||
case TOKEN_LEFT_BRACE:
|
|
||||||
break;
|
|
||||||
case TOKEN_RIGHT_BRACE:
|
|
||||||
break;
|
|
||||||
case TOKEN_SEMICOLON:
|
|
||||||
break;
|
|
||||||
case TOKEN_IDENTIFIER:
|
|
||||||
break;
|
|
||||||
case TOKEN_STRING:
|
|
||||||
break;
|
|
||||||
case TOKEN_FLOAT:
|
|
||||||
break;
|
|
||||||
case TOKEN_U8:
|
|
||||||
break;
|
|
||||||
case TOKEN_I8:
|
|
||||||
break;
|
|
||||||
case TOKEN_U16:
|
|
||||||
break;
|
|
||||||
case TOKEN_I16:
|
|
||||||
break;
|
|
||||||
case TOKEN_U64:
|
|
||||||
break;
|
|
||||||
case TOKEN_I64:
|
|
||||||
break;
|
|
||||||
case TOKEN_INT:
|
|
||||||
break;
|
|
||||||
case TOKEN_UINT:
|
|
||||||
break;
|
|
||||||
case TOKEN_FALSE:
|
|
||||||
break;
|
|
||||||
case TOKEN_TRUE:
|
|
||||||
break;
|
|
||||||
case TOKEN_NULL:
|
|
||||||
break;
|
|
||||||
case TOKEN_EOF:
|
|
||||||
break;
|
|
||||||
case TOKEN_ERROR:
|
|
||||||
break;
|
|
||||||
case TOKEN_ADD:
|
|
||||||
break;
|
|
||||||
case TOKEN_SUB:
|
|
||||||
break;
|
|
||||||
case TOKEN_MUL:
|
|
||||||
break;
|
|
||||||
case TOKEN_DIV:
|
|
||||||
break;
|
|
||||||
case TOKEN_MOD:
|
|
||||||
break;
|
|
||||||
case TOKEN_GT:
|
|
||||||
break;
|
|
||||||
case TOKEN_LT:
|
|
||||||
break;
|
|
||||||
case TOKEN_EQ:
|
|
||||||
break;
|
|
||||||
case TOKEN_GE:
|
|
||||||
break;
|
|
||||||
case TOKEN_LE:
|
|
||||||
break;
|
|
||||||
case TOKEN_NE:
|
|
||||||
break;
|
|
||||||
case TOKEN_AND:
|
|
||||||
break;
|
|
||||||
case TOKEN_OR:
|
|
||||||
break;
|
|
||||||
case TOKEN_XOR:
|
|
||||||
break;
|
|
||||||
case TOKEN_SHIFTRIGHT:
|
|
||||||
break;
|
|
||||||
case TOKEN_SHIFTLEFT:
|
|
||||||
break;
|
|
||||||
case TOKEN_FN:
|
|
||||||
break;
|
|
||||||
case TOKEN_TO:
|
|
||||||
break;
|
|
||||||
case TOKEN_IN:
|
|
||||||
break;
|
|
||||||
case TOKEN_IS:
|
|
||||||
break;
|
|
||||||
case TOKEN_AS:
|
|
||||||
break;
|
|
||||||
case TOKEN_USE:
|
|
||||||
break;
|
|
||||||
case TOKEN_IF:
|
|
||||||
break;
|
|
||||||
case TOKEN_ELSE:
|
|
||||||
break;
|
|
||||||
case TOKEN_DEFAULT:
|
|
||||||
break;
|
|
||||||
case TOKEN_FOR:
|
|
||||||
break;
|
|
||||||
case TOKEN_TRY:
|
|
||||||
break;
|
|
||||||
case TOKEN_CATCH:
|
|
||||||
break;
|
|
||||||
case TOKEN_WHILE:
|
|
||||||
break;
|
|
||||||
case TOKEN_DO:
|
|
||||||
break;
|
|
||||||
case TOKEN_EXIT:
|
|
||||||
break;
|
|
||||||
case TOKEN_SWITCH:
|
|
||||||
break;
|
|
||||||
case TOKEN_RETURN:
|
|
||||||
break;
|
|
||||||
case TOKEN_CONST:
|
|
||||||
break;
|
|
||||||
case TOKEN_TYPE:
|
|
||||||
break;
|
|
||||||
case TOKEN_THIS:
|
|
||||||
break;
|
|
||||||
case TOKEN_YIELD:
|
|
||||||
break;
|
|
||||||
case TOKEN_CASE:
|
|
||||||
break;
|
|
||||||
case TOKEN_ASSERT:
|
|
||||||
break;
|
|
||||||
case TOKEN_BREAK:
|
|
||||||
break;
|
|
||||||
case TOKEN_LET:
|
|
||||||
break;
|
|
||||||
case TOKEN_PRINT:
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
t = nextToken();
|
t = nextToken();
|
||||||
} while (t.type != TOKEN_EOF);
|
}
|
||||||
}
|
}
|
||||||
|
|
14
src/main.c
14
src/main.c
|
@ -1,6 +1,6 @@
|
||||||
#include "parser.h"
|
|
||||||
#include "compiler.h"
|
#include "compiler.h"
|
||||||
#include "debug.h"
|
#include "debug.h"
|
||||||
|
#include "parser.h"
|
||||||
#include "vm.h"
|
#include "vm.h"
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
#include <fcntl.h>
|
#include <fcntl.h>
|
||||||
|
@ -16,14 +16,14 @@
|
||||||
#include <emscripten.h>
|
#include <emscripten.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
VM *vm;
|
VM vm = {0};
|
||||||
|
|
||||||
void mainloop() {
|
void mainloop() {
|
||||||
if (!step_vm(vm)) {
|
if (!step_vm(&vm)) {
|
||||||
#ifdef __EMSCRIPTEN__
|
#ifdef __EMSCRIPTEN__
|
||||||
emscripten_cancel_main_loop(); /* this should "kill" the app. */
|
emscripten_cancel_main_loop(); /* this should "kill" the app. */
|
||||||
#else
|
#else
|
||||||
core_dump(vm);
|
core_dump(&vm);
|
||||||
exit(0);
|
exit(0);
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
@ -50,10 +50,8 @@ int main(int argc, char **argv) {
|
||||||
}
|
}
|
||||||
|
|
||||||
initTokenMap();
|
initTokenMap();
|
||||||
vm = init_vm();
|
compile(vm.memory, buffer);
|
||||||
vm->frame = (Frame*)malloc(sizeof(Frame));
|
/* demo_add_compile(vm.memory); */
|
||||||
compile(vm->memory, buffer);
|
|
||||||
demo_add_compile(vm->memory);
|
|
||||||
|
|
||||||
#ifdef __EMSCRIPTEN__
|
#ifdef __EMSCRIPTEN__
|
||||||
emscripten_set_main_loop(mainloop, 0, 1);
|
emscripten_set_main_loop(mainloop, 0, 1);
|
||||||
|
|
121
src/opcodes.h
121
src/opcodes.h
|
@ -10,76 +10,81 @@ typedef union {
|
||||||
char c[4]; /* 4 Byte char array for string packing */
|
char c[4]; /* 4 Byte char array for string packing */
|
||||||
} Value;
|
} Value;
|
||||||
|
|
||||||
typedef union {
|
typedef struct {
|
||||||
uint32_t length;
|
uint32_t start;
|
||||||
char *string;
|
uint32_t end;
|
||||||
Value *array;
|
} Slice;
|
||||||
Value *code;
|
|
||||||
} Object;
|
|
||||||
|
|
||||||
#define MAX_REGS 256
|
#define MAX_REGS 256
|
||||||
typedef struct {
|
typedef struct {
|
||||||
Value registers[MAX_REGS]; /* R0-R255 */
|
Value registers[MAX_REGS]; /* R0-R255 */
|
||||||
Object *locals; /* Short lived object */
|
Slice allocated;
|
||||||
} Frame;
|
} Frame;
|
||||||
|
|
||||||
|
#define MEMORY_SIZE 1024
|
||||||
#define STACK_SIZE 128
|
#define STACK_SIZE 128
|
||||||
|
#define RETURN_STACK_SIZE 256
|
||||||
typedef struct {
|
typedef struct {
|
||||||
Value stack[STACK_SIZE];
|
Value memory[MEMORY_SIZE]; /* Memory array */
|
||||||
uint32_t stack_size;
|
|
||||||
uint32_t pc; /* Program counter */
|
|
||||||
Value *memory;
|
|
||||||
uint32_t memory_size;
|
uint32_t memory_size;
|
||||||
Frame *frame;
|
Value return_stack[RETURN_STACK_SIZE];
|
||||||
|
uint32_t return_stack_size;
|
||||||
|
Frame stack[STACK_SIZE];
|
||||||
|
uint32_t stack_size;
|
||||||
|
uint32_t rp; /* Return stack pointer (top of stack) */
|
||||||
|
uint32_t sp; /* Stack pointer (top of stack) */
|
||||||
|
uint32_t pc; /* Program counter */
|
||||||
} VM;
|
} VM;
|
||||||
|
|
||||||
typedef enum {
|
typedef enum {
|
||||||
OP_HALT, /* terminate execution */
|
OP_HALT, /* halt : terminate execution */
|
||||||
OP_LOADI, /* dest = next memory location as int */
|
OP_LOADI, /* lodi : dest = next memory location as int */
|
||||||
OP_LOADU, /* dest = next memory location as uint */
|
OP_LOADU, /* lodu : dest = next memory location as uint */
|
||||||
OP_LOADF, /* dest = next memory location as float */
|
OP_LOADF, /* lodf : dest = next memory location as float */
|
||||||
OP_STOREI, /* next memory location = src1 as int */
|
OP_STOREI, /* stri : next memory location = src1 as int */
|
||||||
OP_STOREU, /* next memory location = src1 as uint */
|
OP_STOREU, /* stru : next memory location = src1 as uint */
|
||||||
OP_STOREF, /* next memory location = src1 as float */
|
OP_STOREF, /* strf : next memory location = src1 as float */
|
||||||
OP_ADD_INT, /* dest = src1 + src2 */
|
OP_ADD_INT, /* addi : dest = src1 + src2 */
|
||||||
OP_SUB_INT, /* dest = src1 - src2 */
|
OP_SUB_INT, /* subs : dest = src1 - src2 */
|
||||||
OP_MUL_INT, /* dest = src1 * src2 */
|
OP_MUL_INT, /* mulm : dest = src1 * src2 */
|
||||||
OP_DIV_INT, /* dest = src1 / src2 */
|
OP_DIV_INT, /* divd : dest = src1 / src2 */
|
||||||
OP_JEQ_INT, /* jump to address dest if src1 as int == src2 as int */
|
OP_JEQ_INT, /* jeqi : jump to address dest if src1 as int == src2 as int */
|
||||||
OP_JGT_INT, /* jump to address dest if src1 as int > src2 as int*/
|
OP_JGT_INT, /* jgti : jump to address dest if src1 as int > src2 as int*/
|
||||||
OP_JLT_INT, /* jump to address dest if src1 as int < src2 as int */
|
OP_JLT_INT, /* jlti : jump to address dest if src1 as int < src2 as int */
|
||||||
OP_JLE_INT, /* jump to address dest if src1 as int <= src2 as int */
|
OP_JLE_INT, /* jlei : jump to address dest if src1 as int <= src2 as int */
|
||||||
OP_JGE_INT, /* jump to address dest if src1 as int >= src2 as int*/
|
OP_JGE_INT, /* jgei : jump to address dest if src1 as int >= src2 as int*/
|
||||||
OP_INT_TO_REAL, /* dest = src1 as f32 */
|
OP_INT_TO_REAL, /* itor : dest = src1 as f32 */
|
||||||
OP_ADD_UINT, /* dest = src1 + src2 */
|
OP_ADD_UINT, /* addu : dest = src1 + src2 */
|
||||||
OP_SUB_UINT, /* dest = src1 - src2 */
|
OP_SUB_UINT, /* subu : dest = src1 - src2 */
|
||||||
OP_MUL_UINT, /* dest = src1 * src2 */
|
OP_MUL_UINT, /* mulu : dest = src1 * src2 */
|
||||||
OP_DIV_UINT, /* dest = src1 / src2 */
|
OP_DIV_UINT, /* divu : dest = src1 / src2 */
|
||||||
OP_JEQ_UINT, /* jump to address dest if src1 as int == src2 as uint */
|
OP_JEQ_UINT, /* jequ : jump to address dest if src1 as int == src2 as uint */
|
||||||
OP_JGT_UINT, /* jump to address dest if src1 as int > src2 as uint*/
|
OP_JGT_UINT, /* jgtu : jump to address dest if src1 as int > src2 as uint*/
|
||||||
OP_JLT_UINT, /* jump to address dest if src1 as int < src2 as uint */
|
OP_JLT_UINT, /* jltu : jump to address dest if src1 as int < src2 as uint */
|
||||||
OP_JLE_UINT, /* jump to address dest if src1 as int <= src2 as uint */
|
OP_JLE_UINT, /* jleu : jump to address dest if src1 as int <= src2 as uint */
|
||||||
OP_JGE_UINT, /* jump to address dest if src1 as int >= src2 as uint*/
|
OP_JGE_UINT, /* jgeu : jump to address dest if src1 as int >= src2 as uint*/
|
||||||
OP_UINT_TO_REAL, /* dest = src1 as f32 */
|
OP_UINT_TO_REAL, /* utor : dest = src1 as f32 */
|
||||||
OP_ADD_REAL, /* dest = src1 + src2 */
|
OP_ADD_REAL, /* addr : dest = src1 + src2 */
|
||||||
OP_SUB_REAL, /* dest = src1 - src2 */
|
OP_SUB_REAL, /* subr : dest = src1 - src2 */
|
||||||
OP_MUL_REAL, /* dest = src1 * src2 */
|
OP_MUL_REAL, /* mulr : dest = src1 * src2 */
|
||||||
OP_DIV_REAL, /* dest = src1 / src2 */
|
OP_DIV_REAL, /* divr : dest = src1 / src2 */
|
||||||
OP_JEQ_REAL, /* jump to address dest if src1 as real == src2 as real */
|
OP_JEQ_REAL, /* jeqr : jump to address dest if src1 as real == src2 as real */
|
||||||
OP_JGE_REAL, /* jump to address dest if src1 as real >= src2 as real */
|
OP_JGE_REAL, /* jgtr : jump to address dest if src1 as real >= src2 as real */
|
||||||
OP_JGT_REAL, /* jump to address dest if src1 as real > src2 as real */
|
OP_JGT_REAL, /* jltr : jump to address dest if src1 as real > src2 as real */
|
||||||
OP_JLT_REAL, /* jump to address dest if src1 as real < src2 as real */
|
OP_JLT_REAL, /* jler : jump to address dest if src1 as real < src2 as real */
|
||||||
OP_JLE_REAL, /* jump to address dest if src1 as real <= src2 as real */
|
OP_JLE_REAL, /* jger : jump to address dest if src1 as real <= src2 as real */
|
||||||
OP_REAL_TO_INT, /* dest = src1 as int */
|
OP_REAL_TO_INT, /* rtoi : dest = src1 as int */
|
||||||
OP_REAL_TO_UINT, /* dest = src1 as uint */
|
OP_REAL_TO_UINT, /* rtou : dest = src1 as uint */
|
||||||
OP_MOV, /* dest = src1 */
|
OP_MOV, /* move : dest = src1 */
|
||||||
OP_JMP, /* jump to address src1 unconditionally */
|
OP_JMP, /* jump : jump to address src1 unconditionally */
|
||||||
OP_INT_TO_STRING, /* dest = src1 as str */
|
OP_CALL, /* creates a new frame */
|
||||||
OP_UINT_TO_STRING, /* dest = src1 as str */
|
OP_RETURN, /* returns from a frame to the parent frame */
|
||||||
OP_REAL_TO_STRING, /* dest = src1 as str */
|
OP_INT_TO_STRING, /* itos : dest = src1 as str */
|
||||||
OP_READ_STRING, /* dest = read as str */
|
OP_UINT_TO_STRING, /* utos : dest = src1 as str */
|
||||||
OP_PRINT_STRING, /* write src1 to stdout */
|
OP_REAL_TO_STRING, /* rtos : dest = src1 as str */
|
||||||
OP_CMP_STRING, /* dest = (str == src2) as bool */
|
OP_READ_STRING, /* read : dest = read as str */
|
||||||
|
OP_PRINT_STRING, /* wrte : write src1 to stdout */
|
||||||
|
OP_CMP_STRING, /* cmps : dest = (str == src2) as bool */
|
||||||
} Opcode;
|
} Opcode;
|
||||||
|
|
||||||
/* defines a uint32 opcode */
|
/* defines a uint32 opcode */
|
||||||
|
|
|
@ -48,6 +48,7 @@ void initTokenMap() {
|
||||||
put_TokenMap(tokenMap, "ge", TOKEN_GE);
|
put_TokenMap(tokenMap, "ge", TOKEN_GE);
|
||||||
put_TokenMap(tokenMap, "srl", TOKEN_SHIFTRIGHT);
|
put_TokenMap(tokenMap, "srl", TOKEN_SHIFTRIGHT);
|
||||||
put_TokenMap(tokenMap, "sll", TOKEN_SHIFTLEFT);
|
put_TokenMap(tokenMap, "sll", TOKEN_SHIFTLEFT);
|
||||||
|
put_TokenMap(tokenMap, "toS", TOKEN_TO_S);
|
||||||
}
|
}
|
||||||
|
|
||||||
typedef struct Tokenizer Tokenizer;
|
typedef struct Tokenizer Tokenizer;
|
||||||
|
@ -222,6 +223,10 @@ Token nextToken() {
|
||||||
return makeToken(TOKEN_MUL);
|
return makeToken(TOKEN_MUL);
|
||||||
case ';':
|
case ';':
|
||||||
return makeToken(TOKEN_SEMICOLON);
|
return makeToken(TOKEN_SEMICOLON);
|
||||||
|
case '=':
|
||||||
|
return makeToken(TOKEN_EQUALS);
|
||||||
|
case '.':
|
||||||
|
return makeToken(TOKEN_DOT);
|
||||||
case '"':
|
case '"':
|
||||||
return string();
|
return string();
|
||||||
}
|
}
|
||||||
|
@ -234,6 +239,8 @@ void printToken(Token t) {
|
||||||
char *str = currentTokenToS();
|
char *str = currentTokenToS();
|
||||||
|
|
||||||
switch (t.type) {
|
switch (t.type) {
|
||||||
|
PRINT_TOKEN_CASE(TOKEN_EQUALS)
|
||||||
|
PRINT_TOKEN_CASE(TOKEN_DOT)
|
||||||
PRINT_TOKEN_CASE(TOKEN_LEFT_PAREN)
|
PRINT_TOKEN_CASE(TOKEN_LEFT_PAREN)
|
||||||
PRINT_TOKEN_CASE(TOKEN_RIGHT_PAREN)
|
PRINT_TOKEN_CASE(TOKEN_RIGHT_PAREN)
|
||||||
PRINT_TOKEN_CASE(TOKEN_LEFT_BRACE)
|
PRINT_TOKEN_CASE(TOKEN_LEFT_BRACE)
|
||||||
|
@ -299,6 +306,7 @@ void printToken(Token t) {
|
||||||
PRINT_TOKEN_CASE(TOKEN_BREAK)
|
PRINT_TOKEN_CASE(TOKEN_BREAK)
|
||||||
PRINT_TOKEN_CASE(TOKEN_LET)
|
PRINT_TOKEN_CASE(TOKEN_LET)
|
||||||
PRINT_TOKEN_CASE(TOKEN_PRINT)
|
PRINT_TOKEN_CASE(TOKEN_PRINT)
|
||||||
|
PRINT_TOKEN_CASE(TOKEN_TO_S)
|
||||||
}
|
}
|
||||||
free(str);
|
free(str);
|
||||||
}
|
}
|
||||||
|
|
|
@ -12,6 +12,8 @@ typedef enum TokenType
|
||||||
TOKEN_LEFT_BRACE,
|
TOKEN_LEFT_BRACE,
|
||||||
TOKEN_RIGHT_BRACE,
|
TOKEN_RIGHT_BRACE,
|
||||||
TOKEN_SEMICOLON,
|
TOKEN_SEMICOLON,
|
||||||
|
TOKEN_EQUALS,
|
||||||
|
TOKEN_DOT,
|
||||||
/* Literals */
|
/* Literals */
|
||||||
TOKEN_IDENTIFIER,
|
TOKEN_IDENTIFIER,
|
||||||
TOKEN_STRING,
|
TOKEN_STRING,
|
||||||
|
@ -75,6 +77,7 @@ typedef enum TokenType
|
||||||
TOKEN_BREAK,
|
TOKEN_BREAK,
|
||||||
TOKEN_LET,
|
TOKEN_LET,
|
||||||
TOKEN_PRINT,
|
TOKEN_PRINT,
|
||||||
|
TOKEN_TO_S,
|
||||||
} TokenType;
|
} TokenType;
|
||||||
|
|
||||||
#define PRINT_TOKEN_CASE(token_suffix) \
|
#define PRINT_TOKEN_CASE(token_suffix) \
|
||||||
|
|
86
src/vm.c
86
src/vm.c
|
@ -3,17 +3,19 @@
|
||||||
|
|
||||||
#define COMPARE_AND_JUMP(type, accessor, op) \
|
#define COMPARE_AND_JUMP(type, accessor, op) \
|
||||||
do { \
|
do { \
|
||||||
type value = vm->frame->registers[src1].accessor; \
|
type value = vm->stack[vm->sp].registers[src1].accessor; \
|
||||||
type value2 = vm->frame->registers[src2].accessor; \
|
type value2 = vm->stack[vm->sp].registers[src2].accessor; \
|
||||||
vm->pc = (value op value2) ? dest : vm->pc; \
|
vm->pc = (value op value2) ? dest : vm->pc; \
|
||||||
return true; \
|
return true; \
|
||||||
} while (0)
|
} while (0)
|
||||||
|
|
||||||
#define MATH_OP(accessor, op) \
|
#define MATH_OP(accessor, op) \
|
||||||
do { \
|
do { \
|
||||||
vm->frame->registers[dest].accessor = \
|
vm->stack[vm->sp].registers[dest].accessor = \
|
||||||
vm->frame->registers[src1] \
|
vm->stack[vm->sp] \
|
||||||
.accessor op vm->frame->registers[src2] \
|
.registers[src1] \
|
||||||
|
.accessor op vm->stack[vm->sp] \
|
||||||
|
.registers[src2] \
|
||||||
.accessor; \
|
.accessor; \
|
||||||
return true; \
|
return true; \
|
||||||
} while (0)
|
} while (0)
|
||||||
|
@ -31,18 +33,6 @@ void mem_strcpy(Value *memory, const char *str, uint32_t length,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#define MEMORY_SIZE 1024
|
|
||||||
|
|
||||||
VM *init_vm() {
|
|
||||||
Value memory[MEMORY_SIZE] = {0}; /* Memory array */
|
|
||||||
VM *vm = (VM *)malloc(sizeof(VM));
|
|
||||||
vm->memory = memory;
|
|
||||||
vm->memory_size = MEMORY_SIZE;
|
|
||||||
vm->stack_size = 0;
|
|
||||||
|
|
||||||
return vm;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Step to the next opcode in the vm.
|
* Step to the next opcode in the vm.
|
||||||
*/
|
*/
|
||||||
|
@ -62,23 +52,37 @@ bool step_vm(VM *vm) {
|
||||||
switch (opcode) {
|
switch (opcode) {
|
||||||
case OP_HALT:
|
case OP_HALT:
|
||||||
return false;
|
return false;
|
||||||
|
case OP_CALL:
|
||||||
|
vm->return_stack[vm->rp++].u = vm->pc; /* push the return address */
|
||||||
|
vm->sp++; /* increment to the next free frame */
|
||||||
|
|
||||||
|
return true;
|
||||||
|
case OP_RETURN:
|
||||||
|
vm->pc = vm->return_stack[vm->rp].u; /* set pc to return address */
|
||||||
|
Slice s = vm->stack[vm->rp].allocated;
|
||||||
|
memset(&vm->memory[s.start], 0, s.end - s.start); /* deallocate memory from slice */
|
||||||
|
vm->return_stack[vm->rp--].u = 0; /* deallocate the stack */
|
||||||
|
vm->return_stack[vm->rp] = vm->stack[vm->sp].registers[0]; /* push the return value onto the return stack (always register 0) */
|
||||||
|
|
||||||
|
|
||||||
|
return true;
|
||||||
case OP_LOADI:
|
case OP_LOADI:
|
||||||
vm->frame->registers[dest].i = vm->memory[vm->pc++].i;
|
vm->stack[vm->sp].registers[dest].i = vm->memory[vm->pc++].i;
|
||||||
return true;
|
return true;
|
||||||
case OP_LOADU:
|
case OP_LOADU:
|
||||||
vm->frame->registers[dest].u = vm->memory[vm->pc++].u;
|
vm->stack[vm->sp].registers[dest].u = vm->memory[vm->pc++].u;
|
||||||
return true;
|
return true;
|
||||||
case OP_LOADF:
|
case OP_LOADF:
|
||||||
vm->frame->registers[dest].f = vm->memory[vm->pc++].f;
|
vm->stack[vm->sp].registers[dest].f = vm->memory[vm->pc++].f;
|
||||||
return true;
|
return true;
|
||||||
case OP_STOREI:
|
case OP_STOREI:
|
||||||
vm->memory[vm->pc++].i = vm->frame->registers[src1].i;
|
vm->memory[vm->pc++].i = vm->stack[vm->sp].registers[src1].i;
|
||||||
return true;
|
return true;
|
||||||
case OP_STOREU:
|
case OP_STOREU:
|
||||||
vm->memory[vm->pc++].u = vm->frame->registers[src1].u;
|
vm->memory[vm->pc++].u = vm->stack[vm->sp].registers[src1].u;
|
||||||
return true;
|
return true;
|
||||||
case OP_STOREF:
|
case OP_STOREF:
|
||||||
vm->memory[vm->pc++].f = vm->frame->registers[src1].f;
|
vm->memory[vm->pc++].f = vm->stack[vm->sp].registers[src1].f;
|
||||||
return true;
|
return true;
|
||||||
case OP_ADD_INT:
|
case OP_ADD_INT:
|
||||||
MATH_OP(i, +);
|
MATH_OP(i, +);
|
||||||
|
@ -105,22 +109,26 @@ bool step_vm(VM *vm) {
|
||||||
case OP_DIV_REAL:
|
case OP_DIV_REAL:
|
||||||
MATH_OP(f, /);
|
MATH_OP(f, /);
|
||||||
case OP_REAL_TO_INT:
|
case OP_REAL_TO_INT:
|
||||||
vm->frame->registers[dest].i = (int32_t)(vm->frame->registers[src1].f);
|
vm->stack[vm->sp].registers[dest].i =
|
||||||
|
(int32_t)(vm->stack[vm->sp].registers[src1].f);
|
||||||
return true;
|
return true;
|
||||||
case OP_INT_TO_REAL:
|
case OP_INT_TO_REAL:
|
||||||
vm->frame->registers[dest].f = (float)(vm->frame->registers[src1].i);
|
vm->stack[vm->sp].registers[dest].f =
|
||||||
|
(float)(vm->stack[vm->sp].registers[src1].i);
|
||||||
return true;
|
return true;
|
||||||
case OP_REAL_TO_UINT:
|
case OP_REAL_TO_UINT:
|
||||||
vm->frame->registers[dest].u = (uint32_t)(vm->frame->registers[src1].f);
|
vm->stack[vm->sp].registers[dest].u =
|
||||||
|
(uint32_t)(vm->stack[vm->sp].registers[src1].f);
|
||||||
return true;
|
return true;
|
||||||
case OP_UINT_TO_REAL:
|
case OP_UINT_TO_REAL:
|
||||||
vm->frame->registers[dest].f = (float)(vm->frame->registers[src1].u);
|
vm->stack[vm->sp].registers[dest].f =
|
||||||
|
(float)(vm->stack[vm->sp].registers[src1].u);
|
||||||
return true;
|
return true;
|
||||||
case OP_MOV:
|
case OP_MOV:
|
||||||
vm->frame->registers[dest] = vm->frame->registers[src1];
|
vm->stack[vm->sp].registers[dest] = vm->stack[vm->sp].registers[src1];
|
||||||
return true;
|
return true;
|
||||||
case OP_JMP:
|
case OP_JMP:
|
||||||
vm->pc = vm->frame->registers[src1].u; /* Jump to address */
|
vm->pc = vm->stack[vm->sp].registers[src1].u; /* Jump to address */
|
||||||
return true;
|
return true;
|
||||||
case OP_JEQ_UINT: {
|
case OP_JEQ_UINT: {
|
||||||
COMPARE_AND_JUMP(uint32_t, u, ==);
|
COMPARE_AND_JUMP(uint32_t, u, ==);
|
||||||
|
@ -168,31 +176,31 @@ bool step_vm(VM *vm) {
|
||||||
COMPARE_AND_JUMP(float, u, <=);
|
COMPARE_AND_JUMP(float, u, <=);
|
||||||
}
|
}
|
||||||
case OP_INT_TO_STRING: {
|
case OP_INT_TO_STRING: {
|
||||||
int32_t a = (int32_t)vm->frame->registers[src1].i;
|
int32_t a = (int32_t)vm->stack[vm->sp].registers[src1].i;
|
||||||
uint32_t str_dest = (uint32_t)vm->frame->registers[dest].u;
|
uint32_t str_dest = (uint32_t)vm->stack[vm->sp].registers[dest].u;
|
||||||
char buffer[32];
|
char buffer[32];
|
||||||
int len = sprintf(buffer, "%d", a);
|
int len = sprintf(buffer, "%d", a);
|
||||||
mem_strcpy(vm->memory, buffer, len, str_dest);
|
mem_strcpy(vm->memory, buffer, len, str_dest);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
case OP_UINT_TO_STRING: {
|
case OP_UINT_TO_STRING: {
|
||||||
uint32_t a = (uint32_t)vm->frame->registers[src1].u;
|
uint32_t a = (uint32_t)vm->stack[vm->sp].registers[src1].u;
|
||||||
uint32_t str_dest = (uint32_t)vm->frame->registers[dest].u;
|
uint32_t str_dest = (uint32_t)vm->stack[vm->sp].registers[dest].u;
|
||||||
char buffer[32];
|
char buffer[32];
|
||||||
int len = sprintf(buffer, "%d", a);
|
int len = sprintf(buffer, "%d", a);
|
||||||
mem_strcpy(vm->memory, buffer, len, str_dest);
|
mem_strcpy(vm->memory, buffer, len, str_dest);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
case OP_REAL_TO_STRING: {
|
case OP_REAL_TO_STRING: {
|
||||||
float a = (float)vm->frame->registers[src1].f;
|
float a = (float)vm->stack[vm->sp].registers[src1].f;
|
||||||
uint32_t str_dest = (uint32_t)vm->frame->registers[dest].u;
|
uint32_t str_dest = (uint32_t)vm->stack[vm->sp].registers[dest].u;
|
||||||
char buffer[32];
|
char buffer[32];
|
||||||
int len = sprintf(buffer, "%f", a);
|
int len = sprintf(buffer, "%f", a);
|
||||||
mem_strcpy(vm->memory, buffer, len, str_dest);
|
mem_strcpy(vm->memory, buffer, len, str_dest);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
case OP_READ_STRING: {
|
case OP_READ_STRING: {
|
||||||
uint32_t str_dest = (uint32_t)vm->frame->registers[dest].u;
|
uint32_t str_dest = (uint32_t)vm->stack[vm->sp].registers[dest].u;
|
||||||
uint32_t buffer = str_dest + 1;
|
uint32_t buffer = str_dest + 1;
|
||||||
uint32_t length = 0;
|
uint32_t length = 0;
|
||||||
while (1) {
|
while (1) {
|
||||||
|
@ -208,7 +216,7 @@ bool step_vm(VM *vm) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
case OP_PRINT_STRING: {
|
case OP_PRINT_STRING: {
|
||||||
uint32_t ptr = (uint32_t)vm->frame->registers[src1].u;
|
uint32_t ptr = (uint32_t)vm->stack[vm->sp].registers[src1].u;
|
||||||
uint32_t length = vm->memory[ptr].u;
|
uint32_t length = vm->memory[ptr].u;
|
||||||
uint32_t str_src = ptr + 1;
|
uint32_t str_src = ptr + 1;
|
||||||
uint32_t i;
|
uint32_t i;
|
||||||
|
@ -222,8 +230,8 @@ bool step_vm(VM *vm) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
case OP_CMP_STRING: {
|
case OP_CMP_STRING: {
|
||||||
uint32_t addr1 = (uint32_t)vm->frame->registers[src1].u;
|
uint32_t addr1 = (uint32_t)vm->stack[vm->sp].registers[src1].u;
|
||||||
uint32_t addr2 = (uint32_t)vm->frame->registers[src2].u;
|
uint32_t addr2 = (uint32_t)vm->stack[vm->sp].registers[src2].u;
|
||||||
uint32_t length1 = vm->memory[addr1 - 1].u;
|
uint32_t length1 = vm->memory[addr1 - 1].u;
|
||||||
uint32_t length2 = vm->memory[addr2 - 1].u;
|
uint32_t length2 = vm->memory[addr2 - 1].u;
|
||||||
uint32_t equal = 1;
|
uint32_t equal = 1;
|
||||||
|
|
|
@ -1 +1,2 @@
|
||||||
print(1 + 2);
|
let sum = 1 + 2;
|
||||||
|
print(sum.toS());
|
||||||
|
|
|
@ -0,0 +1,6 @@
|
||||||
|
fn fib(int n) {
|
||||||
|
if (n < 2) return n;
|
||||||
|
return fib(n - 2) + fib(n - 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
print fib(35);
|
|
@ -0,0 +1,6 @@
|
||||||
|
fn add(a int, b int) int {
|
||||||
|
return a + b;
|
||||||
|
}
|
||||||
|
|
||||||
|
let sum = add(1, 1);
|
||||||
|
print(sum.toS());
|
|
@ -0,0 +1,14 @@
|
||||||
|
fn first() {
|
||||||
|
int a = 1;
|
||||||
|
second(a, -1);
|
||||||
|
int b = 2;
|
||||||
|
second(a, b);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn second(int c, int d) {
|
||||||
|
str numbers = c.toS() + " " + d.toS();
|
||||||
|
print(numbers);
|
||||||
|
! implied return because return type is null
|
||||||
|
}
|
||||||
|
|
||||||
|
first();
|
Loading…
Reference in New Issue