Chapter 21
This commit is contained in:
parent
7bd9934a4b
commit
26b418d254
4 changed files with 38 additions and 15 deletions
|
@ -12,6 +12,7 @@ typedef enum {
|
||||||
OP_POP,
|
OP_POP,
|
||||||
OP_GET_GLOBAL,
|
OP_GET_GLOBAL,
|
||||||
OP_DEFINE_GLOBAL,
|
OP_DEFINE_GLOBAL,
|
||||||
|
OP_SET_GLOBAL,
|
||||||
OP_EQUAL,
|
OP_EQUAL,
|
||||||
OP_GREATER,
|
OP_GREATER,
|
||||||
OP_LESS,
|
OP_LESS,
|
||||||
|
|
|
@ -30,7 +30,7 @@ typedef enum {
|
||||||
PREC_PRIMARY
|
PREC_PRIMARY
|
||||||
} Precedence;
|
} Precedence;
|
||||||
|
|
||||||
typedef void (*ParseFn)();
|
typedef void (*ParseFn)(bool canAssign);
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
ParseFn prefix;
|
ParseFn prefix;
|
||||||
|
@ -140,7 +140,7 @@ static uint8_t parseVariable(const char *name);
|
||||||
static void defineVariable(uint8_t global);
|
static void defineVariable(uint8_t global);
|
||||||
static uint8_t identifierConstant(Token *name);
|
static uint8_t identifierConstant(Token *name);
|
||||||
|
|
||||||
static void binary() {
|
static void binary(bool canAssign) {
|
||||||
TokenType operatorType = parser.previous.type;
|
TokenType operatorType = parser.previous.type;
|
||||||
ParseRule *rule = getRule(operatorType);
|
ParseRule *rule = getRule(operatorType);
|
||||||
parsePrecedence((Precedence)(rule->precedence + 1));
|
parsePrecedence((Precedence)(rule->precedence + 1));
|
||||||
|
@ -181,7 +181,7 @@ static void binary() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void literal() {
|
static void literal(bool canAssign) {
|
||||||
switch (parser.previous.type) {
|
switch (parser.previous.type) {
|
||||||
case TOKEN_FALSE:
|
case TOKEN_FALSE:
|
||||||
emitByte(OP_FALSE);
|
emitByte(OP_FALSE);
|
||||||
|
@ -267,26 +267,32 @@ static void statement() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void number() {
|
static void number(bool canAssign) {
|
||||||
double value = strtod(parser.previous.start, NULL);
|
double value = strtod(parser.previous.start, NULL);
|
||||||
emitConstant(NUMBER_VAL(value));
|
emitConstant(NUMBER_VAL(value));
|
||||||
}
|
}
|
||||||
|
|
||||||
static void string() {
|
static void string(bool canAssign) {
|
||||||
emitConstant(OBJ_VAL(
|
emitConstant(OBJ_VAL(
|
||||||
copyString(parser.previous.start + 1, parser.previous.length - 2)));
|
copyString(parser.previous.start + 1, parser.previous.length - 2)));
|
||||||
}
|
}
|
||||||
|
|
||||||
static void namedVariable(Token name) {
|
static void namedVariable(Token name, bool canAssign) {
|
||||||
uint8_t arg = identifierConstant(&name);
|
uint8_t arg = identifierConstant(&name);
|
||||||
emitBytes(OP_GET_GLOBAL, arg);
|
|
||||||
|
if (canAssign && match(TOKEN_EQUAL)) {
|
||||||
|
expression();
|
||||||
|
emitBytes(OP_SET_GLOBAL, arg);
|
||||||
|
} else {
|
||||||
|
emitBytes(OP_GET_GLOBAL, arg);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void variable() {
|
static void variable(bool canAssign) {
|
||||||
namedVariable(parser.previous);
|
namedVariable(parser.previous, canAssign);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void unary() {
|
static void unary(bool canAssign) {
|
||||||
TokenType operatorType = parser.previous.type;
|
TokenType operatorType = parser.previous.type;
|
||||||
|
|
||||||
// Compile the operand.
|
// Compile the operand.
|
||||||
|
@ -305,7 +311,7 @@ static void unary() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void grouping() {
|
static void grouping(bool canAssign) {
|
||||||
expression();
|
expression();
|
||||||
consume(TOKEN_RIGHT_PAREN, "Expect ')' after expression.");
|
consume(TOKEN_RIGHT_PAREN, "Expect ')' after expression.");
|
||||||
}
|
}
|
||||||
|
@ -361,12 +367,17 @@ static void parsePrecedence(Precedence precedence) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
prefixRule();
|
bool canAssign = precedence <= PREC_ASSIGNMENT;
|
||||||
|
prefixRule(canAssign);
|
||||||
|
|
||||||
while (precedence <= getRule(parser.current.type)->precedence) {
|
while (precedence <= getRule(parser.current.type)->precedence) {
|
||||||
advance();
|
advance();
|
||||||
ParseFn infixRule = getRule(parser.previous.type)->infix;
|
ParseFn infixRule = getRule(parser.previous.type)->infix;
|
||||||
infixRule();
|
infixRule(canAssign);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (canAssign && match(TOKEN_EQUAL)) {
|
||||||
|
error("Invalid assignment target.");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -48,6 +48,8 @@ int disassembleInstruction(Chunk *chunk, int offset) {
|
||||||
return constantInstruction("OP_GET_GLOBAL", chunk, offset);
|
return constantInstruction("OP_GET_GLOBAL", chunk, offset);
|
||||||
case OP_DEFINE_GLOBAL:
|
case OP_DEFINE_GLOBAL:
|
||||||
return constantInstruction("OP_DEFINE_GLOBAL", chunk, offset);
|
return constantInstruction("OP_DEFINE_GLOBAL", chunk, offset);
|
||||||
|
case OP_SET_GLOBAL:
|
||||||
|
return constantInstruction("OP_SET_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:
|
||||||
|
|
|
@ -119,8 +119,8 @@ static InterpretResult run() {
|
||||||
ObjString *name = READ_STRING();
|
ObjString *name = READ_STRING();
|
||||||
Value value;
|
Value value;
|
||||||
if (!tableGet(&vm.globals, name, &value)) {
|
if (!tableGet(&vm.globals, name, &value)) {
|
||||||
runtimeError("Undefined variable '%s'.", name->chars);
|
runtimeError("Undefined variable '%s'.", name->chars);
|
||||||
return INTERPRET_RUNTIME_ERROR;
|
return INTERPRET_RUNTIME_ERROR;
|
||||||
}
|
}
|
||||||
push(value);
|
push(value);
|
||||||
break;
|
break;
|
||||||
|
@ -131,6 +131,15 @@ static InterpretResult run() {
|
||||||
pop();
|
pop();
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
case OP_SET_GLOBAL: {
|
||||||
|
ObjString *name = READ_STRING();
|
||||||
|
if (tableSet(&vm.globals, name, peek(0))) {
|
||||||
|
tableDelete(&vm.globals, name);
|
||||||
|
runtimeError("Undefined variable '%s'.", name->chars);
|
||||||
|
return INTERPRET_RUNTIME_ERROR;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
case OP_EQUAL: {
|
case OP_EQUAL: {
|
||||||
Value b = pop();
|
Value b = pop();
|
||||||
Value a = pop();
|
Value a = pop();
|
||||||
|
|
Loading…
Reference in a new issue