aboutsummaryrefslogtreecommitdiffstats
path: root/clox/src/compiler.c
diff options
context:
space:
mode:
authorGravatar Tom Willemse2021-08-17 20:41:54 -0700
committerGravatar Tom Willemse2021-08-17 20:41:54 -0700
commit964859a8a135d890019ee31d0a474b90b9b78b4e (patch)
treed8db9ddcb0089932b80228f814abd1524753f47d /clox/src/compiler.c
parent0b89bd5de09c6a93d25768b54efb426732c8797d (diff)
downloadcrafting-interpreters-964859a8a135d890019ee31d0a474b90b9b78b4e.tar.gz
crafting-interpreters-964859a8a135d890019ee31d0a474b90b9b78b4e.zip
Chapter 17.5 - 17.6
Diffstat (limited to 'clox/src/compiler.c')
-rw-r--r--clox/src/compiler.c98
1 files changed, 96 insertions, 2 deletions
diff --git a/clox/src/compiler.c b/clox/src/compiler.c
index c002ea8..578af94 100644
--- a/clox/src/compiler.c
+++ b/clox/src/compiler.c
@@ -26,6 +26,14 @@ typedef enum {
PREC_PRIMARY
} Precedence;
+typedef void (*ParseFn)();
+
+typedef struct {
+ ParseFn prefix;
+ ParseFn infix;
+ Precedence precedence;
+} ParseRule;
+
Parser parser;
Chunk *compilingChunk;
@@ -103,9 +111,33 @@ static void emitConstant(Value value) {
static void endCompiler() { emitReturn(); }
-static void parsePrecedence(Precedence precedence) {
- // What goes here?
+static void expression();
+static ParseRule *getRule(TokenType type);
+static void parsePrecedence(Precedence precedence);
+
+static void binary() {
+ TokenType operatorType = parser.previous.type;
+ ParseRule *rule = getRule(operatorType);
+ parsePrecedence((Precedence)(rule->precedence + 1));
+
+ switch (operatorType) {
+ case TOKEN_PLUS:
+ emitByte(OP_ADD);
+ break;
+ case TOKEN_MINUS:
+ emitByte(OP_SUBTRACT);
+ break;
+ case TOKEN_STAR:
+ emitByte(OP_MULTIPLY);
+ break;
+ case TOKEN_SLASH:
+ emitByte(OP_DIVIDE);
+ break;
+ default:
+ return; // Unreachable.
+ }
}
+
static void expression() { parsePrecedence(PREC_ASSIGNMENT); }
static void number() {
@@ -134,6 +166,68 @@ static void grouping() {
consume(TOKEN_RIGHT_PAREN, "Expect ')' after expression.");
}
+ParseRule rules[] = {
+ [TOKEN_LEFT_PAREN] = {grouping, NULL, PREC_NONE},
+ [TOKEN_RIGHT_PAREN] = {NULL, NULL, PREC_NONE},
+ [TOKEN_LEFT_BRACE] = {NULL, NULL, PREC_NONE},
+ [TOKEN_RIGHT_BRACE] = {NULL, NULL, PREC_NONE},
+ [TOKEN_COMMA] = {NULL, NULL, PREC_NONE},
+ [TOKEN_DOT] = {NULL, NULL, PREC_NONE},
+ [TOKEN_MINUS] = {unary, binary, PREC_TERM},
+ [TOKEN_PLUS] = {NULL, binary, PREC_TERM},
+ [TOKEN_SEMICOLON] = {NULL, NULL, PREC_NONE},
+ [TOKEN_SLASH] = {NULL, binary, PREC_FACTOR},
+ [TOKEN_STAR] = {NULL, binary, PREC_FACTOR},
+ [TOKEN_BANG] = {NULL, NULL, PREC_NONE},
+ [TOKEN_BANG_EQUAL] = {NULL, NULL, PREC_NONE},
+ [TOKEN_EQUAL] = {NULL, NULL, PREC_NONE},
+ [TOKEN_EQUAL_EQUAL] = {NULL, NULL, PREC_NONE},
+ [TOKEN_GREATER] = {NULL, NULL, PREC_NONE},
+ [TOKEN_GREATER_EQUAL] = {NULL, NULL, PREC_NONE},
+ [TOKEN_LESS] = {NULL, NULL, PREC_NONE},
+ [TOKEN_LESS_EQUAL] = {NULL, NULL, PREC_NONE},
+ [TOKEN_IDENTIFIER] = {NULL, NULL, PREC_NONE},
+ [TOKEN_STRING] = {NULL, NULL, PREC_NONE},
+ [TOKEN_NUMBER] = {number, NULL, PREC_NONE},
+ [TOKEN_AND] = {NULL, NULL, PREC_NONE},
+ [TOKEN_CLASS] = {NULL, NULL, PREC_NONE},
+ [TOKEN_ELSE] = {NULL, NULL, PREC_NONE},
+ [TOKEN_FALSE] = {NULL, NULL, PREC_NONE},
+ [TOKEN_FOR] = {NULL, NULL, PREC_NONE},
+ [TOKEN_FUN] = {NULL, NULL, PREC_NONE},
+ [TOKEN_IF] = {NULL, NULL, PREC_NONE},
+ [TOKEN_NIL] = {NULL, NULL, PREC_NONE},
+ [TOKEN_OR] = {NULL, NULL, PREC_NONE},
+ [TOKEN_PRINT] = {NULL, NULL, PREC_NONE},
+ [TOKEN_RETURN] = {NULL, NULL, PREC_NONE},
+ [TOKEN_SUPER] = {NULL, NULL, PREC_NONE},
+ [TOKEN_THIS] = {NULL, NULL, PREC_NONE},
+ [TOKEN_TRUE] = {NULL, NULL, PREC_NONE},
+ [TOKEN_VAR] = {NULL, NULL, PREC_NONE},
+ [TOKEN_WHILE] = {NULL, NULL, PREC_NONE},
+ [TOKEN_ERROR] = {NULL, NULL, PREC_NONE},
+ [TOKEN_EOF] = {NULL, NULL, PREC_NONE},
+};
+
+static void parsePrecedence(Precedence precedence) {
+ advance();
+ ParseFn prefixRule = getRule(parser.previous.type)->prefix;
+ if (prefixRule == NULL) {
+ error("Expect expression.");
+ return;
+ }
+
+ prefixRule();
+
+ while (precedence <= getRule(parser.current.type)->precedence) {
+ advance();
+ ParseFn infixRule = getRule(parser.previous.type)->infix;
+ infixRule();
+ }
+}
+
+static ParseRule *getRule(TokenType type) { return &rules[type]; }
+
bool compile(const char *source, Chunk *chunk) {
initScanner(source);
compilingChunk = chunk;