Chapter 17.1 - 17.4
This commit is contained in:
parent
350a5cc4e3
commit
0b89bd5de0
3 changed files with 157 additions and 16 deletions
|
@ -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;
|
||||||
|
}
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue