From e1992f60a5c7642055fad42104c03ee2b098326e Mon Sep 17 00:00:00 2001 From: Jack Kelly Date: Sun, 28 May 2023 09:06:23 +1000 Subject: [PATCH] zlox: `while` statements --- zlox/src/chunk.h | 1 + zlox/src/compiler.c | 27 +++++++++++++++++++++++++++ zlox/src/debug.c | 2 ++ zlox/src/vm.c | 6 ++++++ 4 files changed, 36 insertions(+) diff --git a/zlox/src/chunk.h b/zlox/src/chunk.h index 608ce26..6b53b4f 100644 --- a/zlox/src/chunk.h +++ b/zlox/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/zlox/src/compiler.c b/zlox/src/compiler.c index 692465e..370bcf2 100644 --- a/zlox/src/compiler.c +++ b/zlox/src/compiler.c @@ -138,6 +138,16 @@ 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); @@ -496,6 +506,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; @@ -535,6 +560,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/zlox/src/debug.c b/zlox/src/debug.c index 57b0e89..c7c94da 100644 --- a/zlox/src/debug.c +++ b/zlox/src/debug.c @@ -97,6 +97,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/zlox/src/vm.c b/zlox/src/vm.c index 64d8ef5..a1cf358 100644 --- a/zlox/src/vm.c +++ b/zlox/src/vm.c @@ -195,6 +195,12 @@ static InterpretResult run() { if (isFalsey(peek(0))) vm.ip += offset; break; } + case OP_LOOP: + { + uint16_t offset = READ_SHORT(); + vm.ip -= offset; + break; + } case OP_RETURN: /* Exit interpreter. */ return INTERPRET_OK; -- 2.45.2