Chapter 18
This commit is contained in:
parent
6508cfd8fe
commit
c10cbcdf99
6 changed files with 125 additions and 11 deletions
|
@ -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;
|
||||||
|
|
|
@ -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},
|
||||||
|
|
|
@ -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:
|
||||||
|
|
|
@ -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 */
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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.");
|
||||||
|
|
Loading…
Reference in a new issue