Explorar o código

Add Types of Values

runningwater %!s(int64=2) %!d(string=hai) anos
pai
achega
06c0ab9432
Modificáronse 4 ficheiros con 128 adicións e 66 borrados
  1. 3 3
      compiler.c
  2. 1 1
      value.c
  3. 31 4
      value.h
  4. 93 58
      vm.c

+ 3 - 3
compiler.c

@@ -103,7 +103,7 @@ static void emitBytes(uint8_t byte1, uint8_t byte2) {
 static void emitReturn() {
   emitByte(OP_RETURN);
 }
-static uint8_t makeConstant(double value) {
+static uint8_t makeConstant(Value value) {
   int constant = addConstant(currentChunk(), value);
   if (constant > UINT8_MAX) {
     error("Too many constants in one chunk.");
@@ -114,7 +114,7 @@ static uint8_t makeConstant(double value) {
 static void expression() {
   parsePrecedence(PREC_ASSIGNMENT);
 }
-static void emitConstant(double value) {
+static void emitConstant(Value value) {
   emitBytes(OP_CONSTANT, makeConstant(value));
 }
 static void endCompiler() {
@@ -133,7 +133,7 @@ static void grouping() {
 /// Number literals: 123
 static void number() {
   double value = strtod(parser.previous.start, NULL);
-  emitConstant(value);
+  emitConstant(NUMBER_VAL(value));
 }
 /// Unary negation: -123
 static void unary() {

+ 1 - 1
value.c

@@ -22,5 +22,5 @@ void freeValueArray(ValueArray *array) {
   initValueArray(array);
 }
 void printValue(Value value) {
-  printf("%g", value);
+  printf("%g", AS_NUMBER(value));
 };

+ 31 - 4
value.h

@@ -13,17 +13,44 @@
 
 #include "common.h"
 
-typedef double Value;
+typedef enum {
+    VAL_BOOL,
+    VAL_NIL,
+    VAL_NUMBER,
+} ValueType;
+
+typedef struct {
+    ValueType type;
+    union {
+        bool boolean;
+        double number;
+    } as;
+} Value;
+
+#define IS_BOOL(value) ((value).type == VAL_BOOL)
+#define IS_NIL(value) ((value).type == VAL_NIL)
+#define IS_NUMBER(value) ((value).type == VAL_NUMBER)
+
+#define AS_BOOL(value) ((value).as.boolean)
+#define AS_NUMBER(value) ((value).as.number)
+
+#define BOOL_VAL(vale) ((Value){VAL_BOOL, {.boolean = value}})
+#define NIL_VAL(vale) ((Value){VAL_NIL, {.number = 0}})
+#define NUMBER_VAL(value) ((Value){VAL_NUMBER, {.number = value}})
 
 /// \brief 常量池
 typedef struct {
-  int capacity;
-  int count;
-  Value *values;
+    int capacity;
+    int count;
+    Value *values;
 } ValueArray;
 
 void initValueArray(ValueArray *array);
+
 void writeValueArray(ValueArray *array, Value value);
+
 void freeValueArray(ValueArray *array);
+
 void printValue(Value value);
+
 #endif //CLOX__VALUE_H_

+ 93 - 58
vm.c

@@ -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;
 }