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