diff --git a/include/chunk.h b/include/chunk.h index 5d9100f..2e30342 100644 --- a/include/chunk.h +++ b/include/chunk.h @@ -6,6 +6,11 @@ typedef enum { OP_CONSTANT, + OP_ADD, + OP_SUBTRACT, + OP_MULTIPLY, + OP_DIVIDE, + OP_NEGATE, OP_RETURN, } OpCode; diff --git a/include/common.h b/include/common.h index c827b76..ddab699 100644 --- a/include/common.h +++ b/include/common.h @@ -5,4 +5,6 @@ #include #include +#define DEBUG_TRACE_EXECUTION + #endif diff --git a/include/vm.h b/include/vm.h new file mode 100644 index 0000000..460cc1c --- /dev/null +++ b/include/vm.h @@ -0,0 +1,28 @@ +#ifndef clox_vm_h +#define clox_vm_h + +#include "chunk.h" + +#define STACK_MAX 256 + +typedef struct { + Chunk *chunk; + uint8_t *ip; + Value stack[STACK_MAX]; + Value *stackTop; +} VM; + +typedef enum { + INTERPRET_OK, + INTERPRET_COMPILE_ERROR, + INTERPRET_RUNTIME_ERROR +} InterpretResult; + +void initVM(); +void freeVM(); + +InterpretResult interpret(Chunk *chunk); +void push(Value value); +Value pop(); + +#endif /* clox_vm_h */ diff --git a/src/debug.c b/src/debug.c index 428b49e..ec06ba3 100644 --- a/src/debug.c +++ b/src/debug.c @@ -37,6 +37,16 @@ int disassembleInstruction(Chunk *chunk, int offset) { switch (instruction) { case OP_CONSTANT: return constantInstruction("OP_CONSTANT", chunk, offset); + case OP_ADD: + return simpleInstruction("OP_ADD", offset); + case OP_SUBTRACT: + return simpleInstruction("OP_SUBTRACT", offset); + case OP_MULTIPLY: + return simpleInstruction("OP_MULTIPLY", offset); + case OP_DIVIDE: + return simpleInstruction("OP_DIVIDE", offset); + case OP_NEGATE: + return simpleInstruction("OP_NEGATE", offset); case OP_RETURN: return simpleInstruction("OP_RETURN", offset); default: diff --git a/src/main.c b/src/main.c index 30e3298..f94ed66 100644 --- a/src/main.c +++ b/src/main.c @@ -1,16 +1,34 @@ #include "chunk.h" #include "common.h" #include "debug.h" +#include "vm.h" int main(int argc, const char *argv[]) { + initVM(); + Chunk chunk; initChunk(&chunk); int constant = addConstant(&chunk, 1.2); writeChunk(&chunk, OP_CONSTANT, 123); writeChunk(&chunk, constant, 123); + + constant = addConstant(&chunk, 3.4); + writeChunk(&chunk, OP_CONSTANT, 123); + writeChunk(&chunk, constant, 123); + + writeChunk(&chunk, OP_ADD, 123); + + constant = addConstant(&chunk, 5.6); + writeChunk(&chunk, OP_CONSTANT, 123); + writeChunk(&chunk, constant, 123); + + writeChunk(&chunk, OP_DIVIDE, 123); + writeChunk(&chunk, OP_NEGATE, 123); writeChunk(&chunk, OP_RETURN, 123); disassembleChunk(&chunk, "test chunk"); + interpret(&chunk); + freeVM(); freeChunk(&chunk); return 0; } diff --git a/src/vm.c b/src/vm.c new file mode 100644 index 0000000..1c52d2f --- /dev/null +++ b/src/vm.c @@ -0,0 +1,89 @@ +#include "vm.h" +#include "chunk.h" +#include "common.h" +#include "debug.h" +#include "value.h" +#include + +VM vm; + +static void resetStack() { + vm.stackTop = vm.stack; +} + +void initVM() { + resetStack(); +} + +void freeVM() { +} + +void push(Value value) { + *vm.stackTop = value; + vm.stackTop++; +} + +Value pop() { + vm.stackTop--; + return *vm.stackTop; +} + +static InterpretResult run() { +#define READ_BYTE() (*vm.ip++) +#define READ_CONSTANT() (vm.chunk->constants.values[READ_BYTE()]) +#define BINARY_OP(op) \ + do { \ + double b = pop(); \ + double a = pop(); \ + push(a op b); \ + } while (false) + + for (;;) { +#ifdef DEBUG_TRACE_EXECUTION + printf(" "); + for (Value *slot = vm.stack; slot < vm.stackTop; slot++) { + printf("[ "); + printValue(*slot); + printf(" ]"); + } + printf("\n"); + disassembleInstruction(vm.chunk, (int)(vm.ip - vm.chunk->code)); +#endif + uint8_t instruction; + switch (instruction = READ_BYTE()) { + case OP_CONSTANT: + Value constant = READ_CONSTANT(); + push(constant); + break; + case OP_ADD: + BINARY_OP(+); + break; + case OP_SUBTRACT: + BINARY_OP(-); + break; + case OP_MULTIPLY: + BINARY_OP(*); + break; + case OP_DIVIDE: + BINARY_OP(/); + break; + case OP_NEGATE: + push(-pop()); + break; + case OP_RETURN: + printValue(pop()); + printf("\n"); + return INTERPRET_OK; + } + } + +#undef READ_CONSTANT +#undef READ_BYTE +#undef BINARY_OP +} + +InterpretResult interpret(Chunk *chunk) { + vm.chunk = chunk; + vm.ip = vm.chunk->code; + return run(); +}