aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorGravatar Tom Willemse2021-08-25 01:08:14 -0700
committerGravatar Tom Willemse2021-08-25 01:08:14 -0700
commit6508cfd8fe55e03a587b2f72d3ffc901d7ada049 (patch)
treeb5856f9802a5f1c60024cdc158ee2832179cfc5f
parent3a02da216122c890c1218fe0c5488bc477e89031 (diff)
downloadcrafting-interpreters-6508cfd8fe55e03a587b2f72d3ffc901d7ada049.tar.gz
crafting-interpreters-6508cfd8fe55e03a587b2f72d3ffc901d7ada049.zip
Chapter 18.1 - 18.3
-rw-r--r--clox/src/compiler.c2
-rw-r--r--clox/src/value.c13
-rw-r--r--clox/src/value.h33
-rw-r--r--clox/src/vm.c41
4 files changed, 67 insertions, 22 deletions
diff --git a/clox/src/compiler.c b/clox/src/compiler.c
index 75df7aa..81e1616 100644
--- a/clox/src/compiler.c
+++ b/clox/src/compiler.c
@@ -153,7 +153,7 @@ static void expression() { parsePrecedence(PREC_ASSIGNMENT); }
static void number() {
double value = strtod(parser.previous.start, NULL);
- emitConstant(value);
+ emitConstant(NUMBER_VAL(value));
}
static void unary() {
diff --git a/clox/src/value.c b/clox/src/value.c
index 9a27034..0737999 100644
--- a/clox/src/value.c
+++ b/clox/src/value.c
@@ -3,28 +3,27 @@
#include "memory.h"
#include "value.h"
-void initValueArray(ValueArray* array) {
+void initValueArray(ValueArray *array) {
array->values = NULL;
array->capacity = 0;
array->count = 0;
}
-void writeValueArray(ValueArray* array, Value value) {
+void writeValueArray(ValueArray *array, Value value) {
if (array->capacity < array->count + 1) {
int oldCapacity = array->capacity;
array->capacity = GROW_CAPACITY(oldCapacity);
- array->values = GROW_ARRAY(Value, array->values, oldCapacity, array->capacity);
+ array->values =
+ GROW_ARRAY(Value, array->values, oldCapacity, array->capacity);
}
array->values[array->count] = value;
array->count++;
}
-void freeValueArray(ValueArray* array) {
+void freeValueArray(ValueArray *array) {
FREE_ARRAY(Value, array->values, array->capacity);
initValueArray(array);
}
-void printValue(Value value) {
- printf("%g", value);
-}
+void printValue(Value value) { printf("%g", AS_NUMBER(value)); }
diff --git a/clox/src/value.h b/clox/src/value.h
index 86d4b1c..7478aaf 100644
--- a/clox/src/value.h
+++ b/clox/src/value.h
@@ -3,17 +3,40 @@
#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(value) ((Value){VAL_BOOL, {.boolean = value}})
+#define NIL_VAL ((Value){VAL_NIL, {.number = 0}})
+#define NUMBER_VAL(value) ((Value){VAL_NUMBER, {.number = value}})
typedef struct {
int capacity;
int count;
- Value* values;
+ Value *values;
} ValueArray;
-void initValueArray(ValueArray* array);
-void writeValueArray(ValueArray* array, Value value);
-void freeValueArray(ValueArray* array);
+void initValueArray(ValueArray *array);
+void writeValueArray(ValueArray *array, Value value);
+void freeValueArray(ValueArray *array);
void printValue(Value value);
#endif
diff --git a/clox/src/vm.c b/clox/src/vm.c
index eb79661..381c8c0 100644
--- a/clox/src/vm.c
+++ b/clox/src/vm.c
@@ -1,3 +1,4 @@
+#include <stdarg.h>
#include <stdio.h>
#include "common.h"
@@ -9,6 +10,19 @@ VM vm;
static void resetStack() { 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(); }
void freeVM() {}
@@ -23,14 +37,19 @@ Value pop() {
return *vm.stackTop;
}
+static Value peek(int distance) { return vm.stackTop[-1 - distance]; }
+
static InterpretResult run() {
#define READ_BYTE() (*vm.ip++)
#define READ_CONSTANT() (vm.chunk->constants.values[READ_BYTE()])
-#define BINARY_OP(op) \
+#define BINARY_OP(valueType, op) \
do { \
- double b = pop(); \
- double a = pop(); \
- push(a op b); \
+ if (!IS_NUMBER(peek(0)) || !IS_NUMBER(peek(1))) { \
+ runtimeError("Operands must be numbers."); \
+ } \
+ double b = AS_NUMBER(pop()); \
+ double a = AS_NUMBER(pop()); \
+ push(valueType(a op b)); \
} while (false)
for (;;) {
@@ -53,19 +72,23 @@ static InterpretResult run() {
break;
}
case OP_ADD:
- BINARY_OP(+);
+ BINARY_OP(NUMBER_VAL, +);
break;
case OP_SUBTRACT:
- BINARY_OP(-);
+ BINARY_OP(NUMBER_VAL, -);
break;
case OP_MULTIPLY:
- BINARY_OP(*);
+ BINARY_OP(NUMBER_VAL, *);
break;
case OP_DIVIDE:
- BINARY_OP(/);
+ BINARY_OP(NUMBER_VAL, /);
break;
case OP_NEGATE:
- push(-pop());
+ 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());