aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorGravatar Tom Willemse2021-08-16 22:17:40 -0700
committerGravatar Tom Willemse2021-08-16 22:17:40 -0700
commit0b89bd5de09c6a93d25768b54efb426732c8797d (patch)
treeabc3ee5dbe15ff4dad11592c1f9ebc273aac7687
parent350a5cc4e3e6c19c2e01d9150b147b696dd13aea (diff)
downloadcrafting-interpreters-0b89bd5de09c6a93d25768b54efb426732c8797d.tar.gz
crafting-interpreters-0b89bd5de09c6a93d25768b54efb426732c8797d.zip
Chapter 17.1 - 17.4
-rw-r--r--clox/src/compiler.c152
-rw-r--r--clox/src/compiler.h4
-rw-r--r--clox/src/vm.c17
3 files changed, 157 insertions, 16 deletions
diff --git a/clox/src/compiler.c b/clox/src/compiler.c
index 2cc2ee4..c002ea8 100644
--- a/clox/src/compiler.c
+++ b/clox/src/compiler.c
@@ -1,23 +1,149 @@
#include <stdio.h>
+#include <stdlib.h>
#include "common.h"
#include "compiler.h"
#include "scanner.h"
-void compile(const char *source) {
- initScanner(source);
- int line = -1;
+typedef struct {
+ Token current;
+ Token previous;
+ bool hadError;
+ bool panicMode;
+} Parser;
+
+typedef enum {
+ PREC_NONE,
+ PREC_ASSIGNMENT, /* = */
+ PREC_OR, /* or */
+ PREC_AND, /* and */
+ PREC_EQUALITY, /* == != */
+ PREC_COMPARISON, /* < > <= >= */
+ PREC_TERM, /* + - */
+ PREC_FACTOR, /* * / */
+ PREC_UNARY, /* ! - */
+ PREC_CALL, /* . () */
+ PREC_PRIMARY
+} Precedence;
+
+Parser parser;
+Chunk *compilingChunk;
+
+static Chunk *currentChunk() { return compilingChunk; }
+
+static void errorAt(Token *token, const char *message) {
+ if (parser.panicMode)
+ return;
+ parser.panicMode = true;
+ fprintf(stderr, "[line %d] Error", token->line);
+
+ if (token->type == TOKEN_EOF) {
+ fprintf(stderr, " at end");
+ } else if (token->type == TOKEN_ERROR) {
+ /* Nothing */
+ } else {
+ fprintf(stderr, " at '%.*s'", token->length, token->start);
+ }
+
+ fprintf(stderr, ": %s\n", message);
+ parser.hadError = true;
+}
+
+static void error(const char *message) { errorAt(&parser.previous, message); }
+
+static void errorAtCurrent(const char *message) {
+ errorAt(&parser.current, message);
+}
+
+static void advance() {
+ parser.previous = parser.current;
+
for (;;) {
- Token token = scanToken();
- if (token.line != line) {
- printf("%4d ", token.line);
- line = token.line;
- } else {
- printf(" | ");
- }
- printf("%2d '%.*s'\n", token.type, token.length, token.start);
-
- if (token.type == TOKEN_EOF)
+ parser.current = scanToken();
+ if (parser.current.type != TOKEN_ERROR)
break;
+
+ errorAtCurrent(parser.current.start);
+ }
+}
+
+static void consume(TokenType type, const char *message) {
+ if (parser.current.type == type) {
+ advance();
+ return;
}
+
+ errorAtCurrent(message);
+}
+
+static void emitByte(uint8_t byte) {
+ writeChunk(currentChunk(), byte, parser.previous.line);
+}
+
+static void emitBytes(uint8_t byte1, uint8_t byte2) {
+ emitByte(byte1);
+ emitByte(byte2);
+}
+
+static void emitReturn() { emitByte(OP_RETURN); }
+
+static uint8_t makeConstant(Value value) {
+ int constant = addConstant(currentChunk(), value);
+ if (constant > UINT8_MAX) {
+ error("Too many constants in one chunk.");
+ return 0;
+ }
+
+ return (uint8_t)constant;
+}
+
+static void emitConstant(Value value) {
+ emitBytes(OP_CONSTANT, makeConstant(value));
+}
+
+static void endCompiler() { emitReturn(); }
+
+static void parsePrecedence(Precedence precedence) {
+ // What goes here?
+}
+static void expression() { parsePrecedence(PREC_ASSIGNMENT); }
+
+static void number() {
+ double value = strtod(parser.previous.start, NULL);
+ emitConstant(value);
+}
+
+static void unary() {
+ TokenType operatorType = parser.previous.type;
+
+ // Compile the operand.
+ parsePrecedence(PREC_UNARY);
+
+ // Emit the operator instruction.
+ switch (operatorType) {
+ case TOKEN_MINUS:
+ emitByte(OP_NEGATE);
+ break;
+ default:
+ return; // Unreachable.
+ }
+}
+
+static void grouping() {
+ expression();
+ consume(TOKEN_RIGHT_PAREN, "Expect ')' after expression.");
+}
+
+bool compile(const char *source, Chunk *chunk) {
+ initScanner(source);
+ compilingChunk = chunk;
+
+ parser.hadError = false;
+ parser.panicMode = false;
+
+ advance();
+ expression();
+ consume(TOKEN_EOF, "Expect end of expression.");
+ endCompiler();
+ return !parser.hadError;
}
diff --git a/clox/src/compiler.h b/clox/src/compiler.h
index 49a45b0..c4376a5 100644
--- a/clox/src/compiler.h
+++ b/clox/src/compiler.h
@@ -1,6 +1,8 @@
#ifndef COMPILER_H
#define COMPILER_H
-void compile(const char *source);
+#include "vm.h"
+
+bool compile(const char *source, Chunk *chunk);
#endif
diff --git a/clox/src/vm.c b/clox/src/vm.c
index d9e5248..eb79661 100644
--- a/clox/src/vm.c
+++ b/clox/src/vm.c
@@ -81,6 +81,19 @@ static InterpretResult run() {
}
InterpretResult interpret(const char *source) {
- compile(source);
- return INTERPRET_OK;
+ Chunk chunk;
+ initChunk(&chunk);
+
+ if (!compile(source, &chunk)) {
+ freeChunk(&chunk);
+ return INTERPRET_COMPILE_ERROR;
+ }
+
+ vm.chunk = &chunk;
+ vm.ip = vm.chunk->code;
+
+ InterpretResult result = run();
+
+ freeChunk(&chunk);
+ return result;
}