Chapter 17.1 - 17.4

This commit is contained in:
Tom Willemse 2021-08-16 22:17:40 -07:00
parent 350a5cc4e3
commit 0b89bd5de0
Signed by: ryuslash
GPG key ID: 7D5C407B435025C1
3 changed files with 157 additions and 16 deletions

View file

@ -1,23 +1,149 @@
#include <stdio.h> #include <stdio.h>
#include <stdlib.h>
#include "common.h" #include "common.h"
#include "compiler.h" #include "compiler.h"
#include "scanner.h" #include "scanner.h"
void compile(const char *source) { typedef struct {
initScanner(source); Token current;
int line = -1; Token previous;
for (;;) { bool hadError;
Token token = scanToken(); bool panicMode;
if (token.line != line) { } Parser;
printf("%4d ", token.line);
line = token.line;
} else {
printf(" | ");
}
printf("%2d '%.*s'\n", token.type, token.length, token.start);
if (token.type == TOKEN_EOF) 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 (;;) {
parser.current = scanToken();
if (parser.current.type != TOKEN_ERROR)
break; 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;
}

View file

@ -1,6 +1,8 @@
#ifndef COMPILER_H #ifndef COMPILER_H
#define COMPILER_H #define COMPILER_H
void compile(const char *source); #include "vm.h"
bool compile(const char *source, Chunk *chunk);
#endif #endif

View file

@ -81,6 +81,19 @@ static InterpretResult run() {
} }
InterpretResult interpret(const char *source) { InterpretResult interpret(const char *source) {
compile(source); Chunk chunk;
return INTERPRET_OK; 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;
} }