aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorGravatar Tom Willemse2022-01-12 23:09:36 -0800
committerGravatar Tom Willemse2022-01-12 23:09:36 -0800
commit37ac05af6d0aa57ccc5ea805af262a407fedeeae (patch)
treecb188b2af41728de22789602190508b281932cd1
parentba6ab6759e4257e543ca5da4caf2705711e5b3ed (diff)
downloadcrafting-interpreters-37ac05af6d0aa57ccc5ea805af262a407fedeeae.tar.gz
crafting-interpreters-37ac05af6d0aa57ccc5ea805af262a407fedeeae.zip
Chapter 23.3
-rw-r--r--clox/src/chunk.h1
-rw-r--r--clox/src/compiler.c28
-rw-r--r--clox/src/debug.c2
-rw-r--r--clox/src/vm.c5
4 files changed, 36 insertions, 0 deletions
diff --git a/clox/src/chunk.h b/clox/src/chunk.h
index db524cf..2ec7a8d 100644
--- a/clox/src/chunk.h
+++ b/clox/src/chunk.h
@@ -27,6 +27,7 @@ typedef enum {
OP_PRINT,
OP_JUMP,
OP_JUMP_IF_FALSE,
+ OP_LOOP,
OP_RETURN,
} OpCode;
diff --git a/clox/src/compiler.c b/clox/src/compiler.c
index d965f45..beda5d5 100644
--- a/clox/src/compiler.c
+++ b/clox/src/compiler.c
@@ -119,6 +119,17 @@ static void emitBytes(uint8_t byte1, uint8_t byte2) {
emitByte(byte2);
}
+static void emitLoop(int loopStart) {
+ emitByte(OP_LOOP);
+
+ int offset = currentChunk()->count - loopStart + 2;
+ if (offset > UINT16_MAX)
+ error("Loop body too large.");
+
+ emitByte((offset >> 8) & 0xff);
+ emitByte(offset & 0xff);
+}
+
static int emitJump(uint8_t instruction) {
emitByte(instruction);
emitByte(0xff);
@@ -302,6 +313,21 @@ static void printStatement() {
emitByte(OP_PRINT);
}
+static void whileStatement() {
+ int loopStart = currentChunk()->count;
+ consume(TOKEN_LEFT_PAREN, "Expect '(' after 'while'.");
+ expression();
+ consume(TOKEN_RIGHT_PAREN, "Expect ')' after condition.");
+
+ int exitJump = emitJump(OP_JUMP_IF_FALSE);
+ emitByte(OP_POP);
+ statement();
+ emitLoop(loopStart);
+
+ patchJump(exitJump);
+ emitByte(OP_POP);
+}
+
static void synchronize() {
parser.panicMode = false;
@@ -342,6 +368,8 @@ static void statement() {
printStatement();
} else if (match(TOKEN_IF)) {
ifStatement();
+ } else if (match(TOKEN_WHILE)) {
+ whileStatement();
} else if (match(TOKEN_LEFT_BRACE)) {
beginScope();
block();
diff --git a/clox/src/debug.c b/clox/src/debug.c
index b3f756a..3f3c289 100644
--- a/clox/src/debug.c
+++ b/clox/src/debug.c
@@ -92,6 +92,8 @@ int disassembleInstruction(Chunk *chunk, int offset) {
return jumpInstruction("OP_JUMP", 1, chunk, offset);
case OP_JUMP_IF_FALSE:
return jumpInstruction("OP_JUMP_IF_FALSE", 1, chunk, offset);
+ case OP_LOOP:
+ return jumpInstruction("OP_LOOP", -1, chunk, offset);
case OP_RETURN:
return simpleInstruction("OP_RETURN", offset);
default:
diff --git a/clox/src/vm.c b/clox/src/vm.c
index 49a162d..c1c6941 100644
--- a/clox/src/vm.c
+++ b/clox/src/vm.c
@@ -211,6 +211,11 @@ static InterpretResult run() {
vm.ip += offset;
break;
}
+ case OP_LOOP: {
+ uint16_t offset = READ_SHORT();
+ vm.ip -= offset;
+ break;
+ }
case OP_RETURN: {
/* The book said to remove this, but when I do I get an infinite loop and
then a segfault because it keeps trying to add the constant 1 to the