Chapter 23.2
This commit is contained in:
parent
65275bde8a
commit
ba6ab6759e
4 changed files with 89 additions and 2 deletions
|
@ -25,6 +25,8 @@ typedef enum {
|
|||
OP_NOT,
|
||||
OP_NEGATE,
|
||||
OP_PRINT,
|
||||
OP_JUMP,
|
||||
OP_JUMP_IF_FALSE,
|
||||
OP_RETURN,
|
||||
} OpCode;
|
||||
|
||||
|
|
|
@ -119,6 +119,13 @@ static void emitBytes(uint8_t byte1, uint8_t byte2) {
|
|||
emitByte(byte2);
|
||||
}
|
||||
|
||||
static int emitJump(uint8_t instruction) {
|
||||
emitByte(instruction);
|
||||
emitByte(0xff);
|
||||
emitByte(0xff);
|
||||
return currentChunk()->count - 2;
|
||||
}
|
||||
|
||||
static void emitReturn() { emitByte(OP_RETURN); }
|
||||
|
||||
static uint8_t makeConstant(Value value) {
|
||||
|
@ -135,6 +142,18 @@ static void emitConstant(Value value) {
|
|||
emitBytes(OP_CONSTANT, makeConstant(value));
|
||||
}
|
||||
|
||||
static void patchJump(int offset) {
|
||||
// -2 to adjust for the bytecode for the jump offset itself...
|
||||
int jump = currentChunk()->count - offset - 2;
|
||||
|
||||
if (jump > UINT16_MAX) {
|
||||
error("Too much code to jump over.");
|
||||
}
|
||||
|
||||
currentChunk()->code[offset] = (jump >> 8) & 0xff;
|
||||
currentChunk()->code[offset + 1] = jump & 0xff;
|
||||
}
|
||||
|
||||
static void initCompiler(Compiler *compiler) {
|
||||
compiler->localCount = 0;
|
||||
compiler->scopeDepth = 0;
|
||||
|
@ -258,6 +277,25 @@ static void expressionStatement() {
|
|||
emitByte(OP_POP);
|
||||
}
|
||||
|
||||
static void ifStatement() {
|
||||
consume(TOKEN_LEFT_PAREN, "Expect '(' after 'if'.");
|
||||
expression();
|
||||
consume(TOKEN_RIGHT_PAREN, "Expect ')' after condition.");
|
||||
|
||||
int thenJump = emitJump(OP_JUMP_IF_FALSE);
|
||||
emitByte(OP_POP);
|
||||
statement();
|
||||
|
||||
int elseJump = emitJump(OP_JUMP);
|
||||
|
||||
patchJump(thenJump);
|
||||
emitByte(OP_POP);
|
||||
|
||||
if (match(TOKEN_ELSE))
|
||||
statement();
|
||||
patchJump(elseJump);
|
||||
}
|
||||
|
||||
static void printStatement() {
|
||||
expression();
|
||||
consume(TOKEN_SEMICOLON, "Expect ';' after value.");
|
||||
|
@ -302,6 +340,8 @@ static void declaration() {
|
|||
static void statement() {
|
||||
if (match(TOKEN_PRINT)) {
|
||||
printStatement();
|
||||
} else if (match(TOKEN_IF)) {
|
||||
ifStatement();
|
||||
} else if (match(TOKEN_LEFT_BRACE)) {
|
||||
beginScope();
|
||||
block();
|
||||
|
@ -316,6 +356,26 @@ static void number(bool canAssign) {
|
|||
emitConstant(NUMBER_VAL(value));
|
||||
}
|
||||
|
||||
static void and_(bool canAssign) {
|
||||
int endJump = emitJump(OP_JUMP_IF_FALSE);
|
||||
|
||||
emitByte(OP_POP);
|
||||
parsePrecedence(PREC_AND);
|
||||
|
||||
patchJump(endJump);
|
||||
}
|
||||
|
||||
static void or_(bool canAssign) {
|
||||
int elseJump = emitJump(OP_JUMP_IF_FALSE);
|
||||
int endJump = emitJump(OP_JUMP);
|
||||
|
||||
patchJump(elseJump);
|
||||
emitByte(OP_POP);
|
||||
|
||||
parsePrecedence(PREC_OR);
|
||||
patchJump(endJump);
|
||||
}
|
||||
|
||||
static void string(bool canAssign) {
|
||||
emitConstant(OBJ_VAL(
|
||||
copyString(parser.previous.start + 1, parser.previous.length - 2)));
|
||||
|
@ -393,7 +453,7 @@ ParseRule rules[] = {
|
|||
[TOKEN_IDENTIFIER] = {variable, NULL, PREC_NONE},
|
||||
[TOKEN_STRING] = {string, NULL, PREC_NONE},
|
||||
[TOKEN_NUMBER] = {number, NULL, PREC_NONE},
|
||||
[TOKEN_AND] = {NULL, NULL, PREC_NONE},
|
||||
[TOKEN_AND] = {NULL, and_, PREC_AND},
|
||||
[TOKEN_CLASS] = {NULL, NULL, PREC_NONE},
|
||||
[TOKEN_ELSE] = {NULL, NULL, PREC_NONE},
|
||||
[TOKEN_FALSE] = {literal, NULL, PREC_NONE},
|
||||
|
@ -401,7 +461,7 @@ ParseRule rules[] = {
|
|||
[TOKEN_FUN] = {NULL, NULL, PREC_NONE},
|
||||
[TOKEN_IF] = {NULL, NULL, PREC_NONE},
|
||||
[TOKEN_NIL] = {literal, NULL, PREC_NONE},
|
||||
[TOKEN_OR] = {NULL, NULL, PREC_NONE},
|
||||
[TOKEN_OR] = {NULL, or_, PREC_OR},
|
||||
[TOKEN_PRINT] = {NULL, NULL, PREC_NONE},
|
||||
[TOKEN_RETURN] = {NULL, NULL, PREC_NONE},
|
||||
[TOKEN_SUPER] = {NULL, NULL, PREC_NONE},
|
||||
|
|
|
@ -30,6 +30,14 @@ static int byteInstruction(const char *name, Chunk *chunk, int offset) {
|
|||
return offset + 2;
|
||||
}
|
||||
|
||||
static int jumpInstruction(const char *name, int sign, Chunk *chunk,
|
||||
int offset) {
|
||||
uint16_t jump = (uint16_t)(chunk->code[offset + 1] << 8);
|
||||
jump |= chunk->code[offset + 2];
|
||||
printf("%-16s %4d -> %d\n", name, offset, offset + 3 + sign * jump);
|
||||
return offset + 3;
|
||||
}
|
||||
|
||||
int disassembleInstruction(Chunk *chunk, int offset) {
|
||||
printf("%04d ", offset);
|
||||
if (offset > 0 && chunk->lines[offset] == chunk->lines[offset - 1]) {
|
||||
|
@ -80,6 +88,10 @@ int disassembleInstruction(Chunk *chunk, int offset) {
|
|||
return simpleInstruction("OP_NEGATE", offset);
|
||||
case OP_PRINT:
|
||||
return simpleInstruction("OP_PRINT", offset);
|
||||
case OP_JUMP:
|
||||
return jumpInstruction("OP_JUMP", 1, chunk, offset);
|
||||
case OP_JUMP_IF_FALSE:
|
||||
return jumpInstruction("OP_JUMP_IF_FALSE", 1, chunk, offset);
|
||||
case OP_RETURN:
|
||||
return simpleInstruction("OP_RETURN", offset);
|
||||
default:
|
||||
|
|
|
@ -73,6 +73,7 @@ static void concatenate() {
|
|||
static InterpretResult run() {
|
||||
#define READ_BYTE() (*vm.ip++)
|
||||
#define READ_CONSTANT() (vm.chunk->constants.values[READ_BYTE()])
|
||||
#define READ_SHORT() (vm.ip += 2, (uint16_t)((vm.ip[-2] << 8) | vm.ip[-1]))
|
||||
#define READ_STRING() AS_STRING(READ_CONSTANT())
|
||||
#define BINARY_OP(valueType, op) \
|
||||
do { \
|
||||
|
@ -199,6 +200,17 @@ static InterpretResult run() {
|
|||
printf("\n");
|
||||
break;
|
||||
}
|
||||
case OP_JUMP: {
|
||||
uint16_t offset = READ_SHORT();
|
||||
vm.ip += offset;
|
||||
break;
|
||||
}
|
||||
case OP_JUMP_IF_FALSE: {
|
||||
uint16_t offset = READ_SHORT();
|
||||
if (isFalsey(peek(0)))
|
||||
vm.ip += offset;
|
||||
break;
|
||||
}
|
||||
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
|
||||
|
@ -211,6 +223,7 @@ static InterpretResult run() {
|
|||
}
|
||||
|
||||
#undef READ_BYTE
|
||||
#undef READ_SHORT
|
||||
#undef READ_CONSTANT
|
||||
#undef READ_STRING
|
||||
#undef BINARY_OP
|
||||
|
|
Loading…
Reference in a new issue