|
|
@@ -7,6 +7,7 @@
|
|
|
* @date : 2023/8/17
|
|
|
******************************************************************************
|
|
|
*/
|
|
|
+#include <stdarg.h>
|
|
|
#include "common.h"
|
|
|
#include "vm.h"
|
|
|
#include "debug.h"
|
|
|
@@ -16,12 +17,30 @@ VM vm;
|
|
|
|
|
|
/// \brief 重置栈
|
|
|
static void resetStack() {
|
|
|
- vm.stackTop = vm.stack; // 指针指向栈顶
|
|
|
+ vm.stackTop = vm.stack; // 指针指向栈底
|
|
|
+}
|
|
|
+
|
|
|
+static void runtimeError(const char *format, ...) {
|
|
|
+ va_list args;
|
|
|
+ va_start(args, format);
|
|
|
+ vfprintf(stderr, format, args);
|
|
|
+ va_end(args);
|
|
|
+ fputs("\n", stderr);
|
|
|
+
|
|
|
+ size_t instruction = vm.ip - vm.chunk->code - 1;
|
|
|
+ int line = vm.chunk->lines[instruction];
|
|
|
+ fprintf(stderr, "[line %d] in script\n", line);
|
|
|
+ resetStack();
|
|
|
}
|
|
|
|
|
|
void initVM() {
|
|
|
- resetStack();
|
|
|
+ resetStack();
|
|
|
+}
|
|
|
+
|
|
|
+static Value peek(int distance) {
|
|
|
+ return vm.stackTop[-1 - distance];
|
|
|
}
|
|
|
+
|
|
|
static InterpretResult run() {
|
|
|
//! <macro> reads the byte currently pointed at by ip
|
|
|
//! and then advances the instruction pointer
|
|
|
@@ -29,83 +48,99 @@ static InterpretResult run() {
|
|
|
//! reads the next byte from the bytecode
|
|
|
//! treats the resulting number as an index
|
|
|
#define READ_CONSTANT() (vm.chunk->constants.values[READ_BYTE()])
|
|
|
-#define BINARY_OP(op) \
|
|
|
- do { \
|
|
|
- double b = pop(); \
|
|
|
- double a = pop(); \
|
|
|
- push(a op b); \
|
|
|
+#define BINARY_OP(valueType, op) \
|
|
|
+ do { \
|
|
|
+ if (!IS_NUMBER(peek(0)) || !IS_NUMBER(peek(1))) { \
|
|
|
+ runtimeError("Operands must be numbers."); \
|
|
|
+ return INTERPRET_RUNTIME_ERROR; \
|
|
|
+ } \
|
|
|
+ double b = AS_NUMBER(pop()); \
|
|
|
+ double a = AS_NUMBER(pop()); \
|
|
|
+ push(valueType(a op b)); \
|
|
|
} while(false)
|
|
|
|
|
|
- for (;;) {
|
|
|
+ for (;;) {
|
|
|
#ifdef DEBUG_TRACE_EXECUTION
|
|
|
- //! <Stack tracing> start
|
|
|
- printf("------------------------\n|");
|
|
|
- for (Value *slot = vm.stack; slot < vm.stackTop; slot++) {
|
|
|
- printf("[ ");
|
|
|
- printValue(*slot);
|
|
|
- printf(" ]");
|
|
|
- }
|
|
|
- printf("\n------------------------");
|
|
|
- printf("\n");
|
|
|
- //! <Stack tracing> end
|
|
|
- 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());
|
|
|
+ //! <Stack tracing> start
|
|
|
+ printf("------------------------\n|");
|
|
|
+ for (Value *slot = vm.stack; slot < vm.stackTop; slot++) {
|
|
|
+ printf("[ ");
|
|
|
+ printValue(*slot);
|
|
|
+ printf(" ]");
|
|
|
+ }
|
|
|
+ printf("\n------------------------");
|
|
|
printf("\n");
|
|
|
- return INTERPRET_OK;
|
|
|
- }
|
|
|
+ //! <Stack tracing> end
|
|
|
+ disassembleInstruction(vm.chunk, (int) (vm.ip - vm.chunk->code));
|
|
|
+#endif
|
|
|
+ switch (READ_BYTE()) {
|
|
|
+ case OP_CONSTANT: {
|
|
|
+ Value constant = READ_CONSTANT();
|
|
|
+ push(constant);
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ case OP_ADD:
|
|
|
+ BINARY_OP(NUMBER_VAL, +);
|
|
|
+ break;
|
|
|
+ case OP_SUBTRACT:
|
|
|
+ BINARY_OP(NUMBER_VAL, -);
|
|
|
+ break;
|
|
|
+ case OP_MULTIPLY:
|
|
|
+ BINARY_OP(NUMBER_VAL, *);
|
|
|
+ break;
|
|
|
+ case OP_DIVIDE:
|
|
|
+ BINARY_OP(NUMBER_VAL, /);
|
|
|
+ break;
|
|
|
+ case OP_NEGATE:
|
|
|
+ if (!IS_NUMBER(peek(0))) {
|
|
|
+ runtimeError("Operand must be a number.");
|
|
|
+ return INTERPRET_RUNTIME_ERROR;
|
|
|
+ }
|
|
|
+ push(NUMBER_VAL(-AS_NUMBER(pop())));
|
|
|
+ break;
|
|
|
+ case OP_RETURN: {
|
|
|
+ printValue(pop());
|
|
|
+ printf("\n");
|
|
|
+ return INTERPRET_OK;
|
|
|
+ }
|
|
|
+ }
|
|
|
}
|
|
|
- }
|
|
|
|
|
|
#undef READ_BYTE
|
|
|
#undef READ_CONSTANT
|
|
|
#undef BINARY_OP
|
|
|
}
|
|
|
+
|
|
|
void freeVM() {
|
|
|
|
|
|
}
|
|
|
+
|
|
|
InterpretResult interpret(const char *source) {
|
|
|
- Chunk chunk;
|
|
|
- initChunk(&chunk);
|
|
|
+ Chunk chunk;
|
|
|
+ initChunk(&chunk);
|
|
|
|
|
|
- if (!compile(source, &chunk)) {
|
|
|
- freeChunk(&chunk);
|
|
|
- return INTERPRET_COMPILE_ERROR;
|
|
|
- }
|
|
|
+ if (!compile(source, &chunk)) {
|
|
|
+ freeChunk(&chunk);
|
|
|
+ return INTERPRET_COMPILE_ERROR;
|
|
|
+ }
|
|
|
|
|
|
- vm.chunk = &chunk;
|
|
|
- vm.ip = vm.chunk->code;
|
|
|
+ vm.chunk = &chunk;
|
|
|
+ vm.ip = vm.chunk->code;
|
|
|
|
|
|
- InterpretResult result = run();
|
|
|
+ InterpretResult result = run();
|
|
|
|
|
|
- freeChunk(&chunk);
|
|
|
- return result;
|
|
|
+ freeChunk(&chunk);
|
|
|
+ return result;
|
|
|
}
|
|
|
+
|
|
|
void push(Value value) {
|
|
|
- *vm.stackTop = value;
|
|
|
- vm.stackTop++;
|
|
|
+ *vm.stackTop = value;
|
|
|
+ vm.stackTop++;
|
|
|
}
|
|
|
+
|
|
|
Value pop() {
|
|
|
- vm.stackTop--;
|
|
|
- //! NOTE: 出栈后,里面的值没有清除
|
|
|
- return *vm.stackTop;
|
|
|
+ vm.stackTop--;
|
|
|
+ //! NOTE: 出栈后,里面的值没有清除
|
|
|
+ return *vm.stackTop;
|
|
|
}
|
|
|
|