Chapter 18

This commit is contained in:
Tom Willemse 2021-09-06 02:03:31 -07:00
parent 6508cfd8fe
commit c10cbcdf99
Signed by: ryuslash
GPG key ID: 7D5C407B435025C1
6 changed files with 125 additions and 11 deletions

View file

@ -6,10 +6,17 @@
typedef enum { typedef enum {
OP_CONSTANT, OP_CONSTANT,
OP_NIL,
OP_TRUE,
OP_FALSE,
OP_EQUAL,
OP_GREATER,
OP_LESS,
OP_ADD, OP_ADD,
OP_SUBTRACT, OP_SUBTRACT,
OP_MULTIPLY, OP_MULTIPLY,
OP_DIVIDE, OP_DIVIDE,
OP_NOT,
OP_NEGATE, OP_NEGATE,
OP_RETURN, OP_RETURN,
} OpCode; } OpCode;

View file

@ -132,6 +132,24 @@ static void binary() {
parsePrecedence((Precedence)(rule->precedence + 1)); parsePrecedence((Precedence)(rule->precedence + 1));
switch (operatorType) { switch (operatorType) {
case TOKEN_BANG_EQUAL:
emitBytes(OP_EQUAL, OP_NOT);
break;
case TOKEN_EQUAL_EQUAL:
emitByte(OP_EQUAL);
break;
case TOKEN_GREATER:
emitByte(OP_GREATER);
break;
case TOKEN_GREATER_EQUAL:
emitBytes(OP_LESS, OP_NOT);
break;
case TOKEN_LESS:
emitByte(OP_LESS);
break;
case TOKEN_LESS_EQUAL:
emitBytes(OP_GREATER, OP_NOT);
break;
case TOKEN_PLUS: case TOKEN_PLUS:
emitByte(OP_ADD); emitByte(OP_ADD);
break; break;
@ -149,6 +167,22 @@ static void binary() {
} }
} }
static void literal() {
switch (parser.previous.type) {
case TOKEN_FALSE:
emitByte(OP_FALSE);
break;
case TOKEN_NIL:
emitByte(OP_NIL);
break;
case TOKEN_TRUE:
emitByte(OP_TRUE);
break;
default:
return; /* Unreachable */
}
}
static void expression() { parsePrecedence(PREC_ASSIGNMENT); } static void expression() { parsePrecedence(PREC_ASSIGNMENT); }
static void number() { static void number() {
@ -164,6 +198,9 @@ static void unary() {
// Emit the operator instruction. // Emit the operator instruction.
switch (operatorType) { switch (operatorType) {
case TOKEN_BANG:
emitByte(OP_NOT);
break;
case TOKEN_MINUS: case TOKEN_MINUS:
emitByte(OP_NEGATE); emitByte(OP_NEGATE);
break; break;
@ -189,31 +226,31 @@ ParseRule rules[] = {
[TOKEN_SEMICOLON] = {NULL, NULL, PREC_NONE}, [TOKEN_SEMICOLON] = {NULL, NULL, PREC_NONE},
[TOKEN_SLASH] = {NULL, binary, PREC_FACTOR}, [TOKEN_SLASH] = {NULL, binary, PREC_FACTOR},
[TOKEN_STAR] = {NULL, binary, PREC_FACTOR}, [TOKEN_STAR] = {NULL, binary, PREC_FACTOR},
[TOKEN_BANG] = {NULL, NULL, PREC_NONE}, [TOKEN_BANG] = {unary, NULL, PREC_NONE},
[TOKEN_BANG_EQUAL] = {NULL, NULL, PREC_NONE}, [TOKEN_BANG_EQUAL] = {NULL, binary, PREC_EQUALITY},
[TOKEN_EQUAL] = {NULL, NULL, PREC_NONE}, [TOKEN_EQUAL] = {NULL, NULL, PREC_NONE},
[TOKEN_EQUAL_EQUAL] = {NULL, NULL, PREC_NONE}, [TOKEN_EQUAL_EQUAL] = {NULL, binary, PREC_EQUALITY},
[TOKEN_GREATER] = {NULL, NULL, PREC_NONE}, [TOKEN_GREATER] = {NULL, binary, PREC_COMPARISON},
[TOKEN_GREATER_EQUAL] = {NULL, NULL, PREC_NONE}, [TOKEN_GREATER_EQUAL] = {NULL, binary, PREC_COMPARISON},
[TOKEN_LESS] = {NULL, NULL, PREC_NONE}, [TOKEN_LESS] = {NULL, binary, PREC_COMPARISON},
[TOKEN_LESS_EQUAL] = {NULL, NULL, PREC_NONE}, [TOKEN_LESS_EQUAL] = {NULL, binary, PREC_COMPARISON},
[TOKEN_IDENTIFIER] = {NULL, NULL, PREC_NONE}, [TOKEN_IDENTIFIER] = {NULL, NULL, PREC_NONE},
[TOKEN_STRING] = {NULL, NULL, PREC_NONE}, [TOKEN_STRING] = {NULL, NULL, PREC_NONE},
[TOKEN_NUMBER] = {number, NULL, PREC_NONE}, [TOKEN_NUMBER] = {number, NULL, PREC_NONE},
[TOKEN_AND] = {NULL, NULL, PREC_NONE}, [TOKEN_AND] = {NULL, NULL, PREC_NONE},
[TOKEN_CLASS] = {NULL, NULL, PREC_NONE}, [TOKEN_CLASS] = {NULL, NULL, PREC_NONE},
[TOKEN_ELSE] = {NULL, NULL, PREC_NONE}, [TOKEN_ELSE] = {NULL, NULL, PREC_NONE},
[TOKEN_FALSE] = {NULL, NULL, PREC_NONE}, [TOKEN_FALSE] = {literal, NULL, PREC_NONE},
[TOKEN_FOR] = {NULL, NULL, PREC_NONE}, [TOKEN_FOR] = {NULL, NULL, PREC_NONE},
[TOKEN_FUN] = {NULL, NULL, PREC_NONE}, [TOKEN_FUN] = {NULL, NULL, PREC_NONE},
[TOKEN_IF] = {NULL, NULL, PREC_NONE}, [TOKEN_IF] = {NULL, NULL, PREC_NONE},
[TOKEN_NIL] = {NULL, NULL, PREC_NONE}, [TOKEN_NIL] = {literal, NULL, PREC_NONE},
[TOKEN_OR] = {NULL, NULL, PREC_NONE}, [TOKEN_OR] = {NULL, NULL, PREC_NONE},
[TOKEN_PRINT] = {NULL, NULL, PREC_NONE}, [TOKEN_PRINT] = {NULL, NULL, PREC_NONE},
[TOKEN_RETURN] = {NULL, NULL, PREC_NONE}, [TOKEN_RETURN] = {NULL, NULL, PREC_NONE},
[TOKEN_SUPER] = {NULL, NULL, PREC_NONE}, [TOKEN_SUPER] = {NULL, NULL, PREC_NONE},
[TOKEN_THIS] = {NULL, NULL, PREC_NONE}, [TOKEN_THIS] = {NULL, NULL, PREC_NONE},
[TOKEN_TRUE] = {NULL, NULL, PREC_NONE}, [TOKEN_TRUE] = {literal, NULL, PREC_NONE},
[TOKEN_VAR] = {NULL, NULL, PREC_NONE}, [TOKEN_VAR] = {NULL, NULL, PREC_NONE},
[TOKEN_WHILE] = {NULL, NULL, PREC_NONE}, [TOKEN_WHILE] = {NULL, NULL, PREC_NONE},
[TOKEN_ERROR] = {NULL, NULL, PREC_NONE}, [TOKEN_ERROR] = {NULL, NULL, PREC_NONE},

View file

@ -36,6 +36,18 @@ int disassembleInstruction(Chunk *chunk, int offset) {
switch (instruction) { switch (instruction) {
case OP_CONSTANT: case OP_CONSTANT:
return constantInstruction("OP_CONSTANT", chunk, offset); return constantInstruction("OP_CONSTANT", chunk, offset);
case OP_NIL:
return simpleInstruction("OP_NIL", offset);
case OP_TRUE:
return simpleInstruction("OP_TRUE", offset);
case OP_FALSE:
return simpleInstruction("OP_FALSE", offset);
case OP_EQUAL:
return simpleInstruction("OP_EQUAL", offset);
case OP_GREATER:
return simpleInstruction("OP_GREATER", offset);
case OP_LESS:
return simpleInstruction("OP_LESS", offset);
case OP_ADD: case OP_ADD:
return simpleInstruction("OP_ADD", offset); return simpleInstruction("OP_ADD", offset);
case OP_SUBTRACT: case OP_SUBTRACT:
@ -44,6 +56,8 @@ int disassembleInstruction(Chunk *chunk, int offset) {
return simpleInstruction("OP_MULTIPLY", offset); return simpleInstruction("OP_MULTIPLY", offset);
case OP_DIVIDE: case OP_DIVIDE:
return simpleInstruction("OP_DIVIDE", offset); return simpleInstruction("OP_DIVIDE", offset);
case OP_NOT:
return simpleInstruction("OP_NOT", offset);
case OP_NEGATE: case OP_NEGATE:
return simpleInstruction("OP_NEGATE", offset); return simpleInstruction("OP_NEGATE", offset);
case OP_RETURN: case OP_RETURN:

View file

@ -26,4 +26,31 @@ void freeValueArray(ValueArray *array) {
initValueArray(array); initValueArray(array);
} }
void printValue(Value value) { printf("%g", AS_NUMBER(value)); } void printValue(Value value) {
switch (value.type) {
case VAL_BOOL:
printf(AS_BOOL(value) ? "true" : "false");
break;
case VAL_NIL:
printf("nil");
break;
case VAL_NUMBER:
printf("%g", AS_NUMBER(value));
break;
}
}
bool valuesEqual(Value a, Value b) {
if (a.type != b.type)
return false;
switch (a.type) {
case VAL_BOOL:
return AS_BOOL(a) == AS_BOOL(b);
case VAL_NIL:
return true;
case VAL_NUMBER:
return AS_NUMBER(a) == AS_NUMBER(b);
default:
return false; /* Unreachable */
}
}

View file

@ -34,6 +34,7 @@ typedef struct {
Value *values; Value *values;
} ValueArray; } ValueArray;
bool valuesEqual(Value a, Value b);
void initValueArray(ValueArray *array); void initValueArray(ValueArray *array);
void writeValueArray(ValueArray *array, Value value); void writeValueArray(ValueArray *array, Value value);
void freeValueArray(ValueArray *array); void freeValueArray(ValueArray *array);

View file

@ -39,6 +39,10 @@ Value pop() {
static Value peek(int distance) { return vm.stackTop[-1 - distance]; } static Value peek(int distance) { return vm.stackTop[-1 - distance]; }
static bool isFalsey(Value value) {
return IS_NIL(value) || (IS_BOOL(value) && !AS_BOOL(value));
}
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()])
@ -71,6 +75,27 @@ static InterpretResult run() {
push(constant); push(constant);
break; break;
} }
case OP_NIL:
push(NIL_VAL);
break;
case OP_TRUE:
push(BOOL_VAL(true));
break;
case OP_FALSE:
push(BOOL_VAL(false));
break;
case OP_EQUAL: {
Value b = pop();
Value a = pop();
push(BOOL_VAL(valuesEqual(a, b)));
break;
}
case OP_GREATER:
BINARY_OP(BOOL_VAL, >);
break;
case OP_LESS:
BINARY_OP(BOOL_VAL, <);
break;
case OP_ADD: case OP_ADD:
BINARY_OP(NUMBER_VAL, +); BINARY_OP(NUMBER_VAL, +);
break; break;
@ -83,6 +108,9 @@ static InterpretResult run() {
case OP_DIVIDE: case OP_DIVIDE:
BINARY_OP(NUMBER_VAL, /); BINARY_OP(NUMBER_VAL, /);
break; break;
case OP_NOT:
push(BOOL_VAL(isFalsey(pop())));
break;
case OP_NEGATE: case OP_NEGATE:
if (!IS_NUMBER(peek(0))) { if (!IS_NUMBER(peek(0))) {
runtimeError("Operand must be a number."); runtimeError("Operand must be a number.");