Chapter 21.1 - 21.3

This commit is contained in:
Tom Willemse 2021-09-20 21:47:41 -07:00
parent aa41f26a26
commit fcbea5f617
Signed by: ryuslash
GPG key ID: 7D5C407B435025C1
6 changed files with 132 additions and 3 deletions

View file

@ -9,6 +9,8 @@ typedef enum {
OP_NIL, OP_NIL,
OP_TRUE, OP_TRUE,
OP_FALSE, OP_FALSE,
OP_POP,
OP_DEFINE_GLOBAL,
OP_EQUAL, OP_EQUAL,
OP_GREATER, OP_GREATER,
OP_LESS, OP_LESS,
@ -18,6 +20,7 @@ typedef enum {
OP_DIVIDE, OP_DIVIDE,
OP_NOT, OP_NOT,
OP_NEGATE, OP_NEGATE,
OP_PRINT,
OP_RETURN, OP_RETURN,
} OpCode; } OpCode;

View file

@ -88,6 +88,15 @@ static void consume(TokenType type, const char *message) {
errorAtCurrent(message); errorAtCurrent(message);
} }
static bool check(TokenType type) { return parser.current.type == type; }
static bool match(TokenType type) {
if (!check(type))
return false;
advance();
return true;
}
static void emitByte(uint8_t byte) { static void emitByte(uint8_t byte) {
writeChunk(currentChunk(), byte, parser.previous.line); writeChunk(currentChunk(), byte, parser.previous.line);
} }
@ -123,8 +132,12 @@ static void endCompiler() {
} }
static void expression(); static void expression();
static void statement();
static void declaration();
static ParseRule *getRule(TokenType type); static ParseRule *getRule(TokenType type);
static void parsePrecedence(Precedence precedence); static void parsePrecedence(Precedence precedence);
static uint8_t parseVariable(const char *name);
static void defineVariable(uint8_t global);
static void binary() { static void binary() {
TokenType operatorType = parser.previous.type; TokenType operatorType = parser.previous.type;
@ -185,6 +198,74 @@ static void literal() {
static void expression() { parsePrecedence(PREC_ASSIGNMENT); } static void expression() { parsePrecedence(PREC_ASSIGNMENT); }
static void varDeclaration() {
uint8_t global = parseVariable("Expect variable name.");
if (match(TOKEN_EQUAL)) {
expression();
} else {
emitByte(OP_NIL);
}
consume(TOKEN_SEMICOLON, "Expect ';' after variable declaration.");
defineVariable(global);
}
static void expressionStatement() {
expression();
consume(TOKEN_SEMICOLON, "Expect ';' after expression.");
emitByte(OP_POP);
}
static void printStatement() {
expression();
consume(TOKEN_SEMICOLON, "Expect ';' after value.");
emitByte(OP_PRINT);
}
static void synchronize() {
parser.panicMode = false;
while (parser.current.type != TOKEN_EOF) {
if (parser.previous.type == TOKEN_SEMICOLON)
return;
switch (parser.current.type) {
case TOKEN_CLASS:
case TOKEN_FUN:
case TOKEN_VAR:
case TOKEN_FOR:
case TOKEN_IF:
case TOKEN_WHILE:
case TOKEN_PRINT:
case TOKEN_RETURN:
return;
default:; /* Do nothing */
}
}
advance();
}
static void declaration() {
if (match(TOKEN_VAR)) {
varDeclaration();
} else {
statement();
}
if (parser.panicMode)
synchronize();
}
static void statement() {
if (match(TOKEN_PRINT)) {
printStatement();
} else {
expressionStatement();
}
}
static void number() { static void number() {
double value = strtod(parser.previous.start, NULL); double value = strtod(parser.previous.start, NULL);
emitConstant(NUMBER_VAL(value)); emitConstant(NUMBER_VAL(value));
@ -279,6 +360,19 @@ static void parsePrecedence(Precedence precedence) {
} }
} }
static uint8_t identifierConstant(Token *name) {
return makeConstant(OBJ_VAL(copyString(name->start, name->length)));
}
static uint8_t parseVariable(const char *errorMessage) {
consume(TOKEN_IDENTIFIER, errorMessage);
return identifierConstant(&parser.previous);
}
static void defineVariable(uint8_t global) {
emitBytes(OP_DEFINE_GLOBAL, global);
}
static ParseRule *getRule(TokenType type) { return &rules[type]; } static ParseRule *getRule(TokenType type) { return &rules[type]; }
bool compile(const char *source, Chunk *chunk) { bool compile(const char *source, Chunk *chunk) {
@ -289,8 +383,11 @@ bool compile(const char *source, Chunk *chunk) {
parser.panicMode = false; parser.panicMode = false;
advance(); advance();
expression();
consume(TOKEN_EOF, "Expect end of expression."); while (!match(TOKEN_EOF)) {
declaration();
}
endCompiler(); endCompiler();
return !parser.hadError; return !parser.hadError;
} }

View file

@ -42,6 +42,10 @@ int disassembleInstruction(Chunk *chunk, int offset) {
return simpleInstruction("OP_TRUE", offset); return simpleInstruction("OP_TRUE", offset);
case OP_FALSE: case OP_FALSE:
return simpleInstruction("OP_FALSE", offset); return simpleInstruction("OP_FALSE", offset);
case OP_POP:
return simpleInstruction("OP_POP", offset);
case OP_DEFINE_GLOBAL:
return constantInstruction("OP_DEFINE_GLOBAL", chunk, offset);
case OP_EQUAL: case OP_EQUAL:
return simpleInstruction("OP_EQUAL", offset); return simpleInstruction("OP_EQUAL", offset);
case OP_GREATER: case OP_GREATER:
@ -60,6 +64,8 @@ int disassembleInstruction(Chunk *chunk, int offset) {
return simpleInstruction("OP_NOT", offset); return simpleInstruction("OP_NOT", offset);
case OP_NEGATE: case OP_NEGATE:
return simpleInstruction("OP_NEGATE", offset); return simpleInstruction("OP_NEGATE", offset);
case OP_PRINT:
return simpleInstruction("OP_PRINT", offset);
case OP_RETURN: case OP_RETURN:
return simpleInstruction("OP_RETURN", offset); return simpleInstruction("OP_RETURN", offset);
default: default:

View file

@ -66,7 +66,7 @@ int main(int argc, const char *argv[]) {
if (argc == 1) { if (argc == 1) {
repl(); repl();
} else if (argc = 2) { } else if (argc == 2) {
runFile(argv[1]); runFile(argv[1]);
} else { } else {
fprintf(stderr, "Usage: clox [path]\n"); fprintf(stderr, "Usage: clox [path]\n");

View file

@ -29,10 +29,13 @@ static void runtimeError(const char *format, ...) {
void initVM() { void initVM() {
resetStack(); resetStack();
vm.objects = NULL; vm.objects = NULL;
initTable(&vm.globals);
initTable(&vm.strings); initTable(&vm.strings);
} }
void freeVM() { void freeVM() {
freeTable(&vm.globals);
freeTable(&vm.strings); freeTable(&vm.strings);
freeObjects(); freeObjects();
} }
@ -70,6 +73,7 @@ static void concatenate() {
static InterpretResult run() { static InterpretResult run() {
#define READ_BYTE() (*vm.ip++) #define READ_BYTE() (*vm.ip++)
#define READ_CONSTANT() (vm.chunk->constants.values[READ_BYTE()]) #define READ_CONSTANT() (vm.chunk->constants.values[READ_BYTE()])
#define READ_STRING() AS_STRING(READ_CONSTANT())
#define BINARY_OP(valueType, op) \ #define BINARY_OP(valueType, op) \
do { \ do { \
if (!IS_NUMBER(peek(0)) || !IS_NUMBER(peek(1))) { \ if (!IS_NUMBER(peek(0)) || !IS_NUMBER(peek(1))) { \
@ -108,6 +112,15 @@ static InterpretResult run() {
case OP_FALSE: case OP_FALSE:
push(BOOL_VAL(false)); push(BOOL_VAL(false));
break; break;
case OP_POP:
pop();
break;
case OP_DEFINE_GLOBAL: {
ObjString *name = READ_STRING();
tableSet(&vm.globals, name, peek(0));
pop();
break;
}
case OP_EQUAL: { case OP_EQUAL: {
Value b = pop(); Value b = pop();
Value a = pop(); Value a = pop();
@ -152,7 +165,15 @@ static InterpretResult run() {
} }
push(NUMBER_VAL(-AS_NUMBER(pop()))); push(NUMBER_VAL(-AS_NUMBER(pop())));
break; break;
case OP_PRINT: {
printValue(pop());
printf("\n");
break;
}
case OP_RETURN: { case OP_RETURN: {
/* The book said to remove this, but when I do I get an infinite loop and
then a segfault because it keeps trying to add the constant 1 to the
stack. */
printValue(pop()); printValue(pop());
printf("\n"); printf("\n");
return INTERPRET_OK; return INTERPRET_OK;
@ -162,6 +183,7 @@ static InterpretResult run() {
#undef READ_BYTE #undef READ_BYTE
#undef READ_CONSTANT #undef READ_CONSTANT
#undef READ_STRING
#undef BINARY_OP #undef BINARY_OP
} }

View file

@ -12,6 +12,7 @@ typedef struct {
uint8_t *ip; uint8_t *ip;
Value stack[STACK_MAX]; Value stack[STACK_MAX];
Value *stackTop; Value *stackTop;
Table globals;
Table strings; Table strings;
Obj *objects; Obj *objects;
} VM; } VM;