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_GET_GLOBAL,
|
||||
OP_DEFINE_GLOBAL,
|
||||
OP_SET_GLOBAL,
|
||||
OP_EQUAL,
|
||||
OP_GREATER,
|
||||
OP_LESS,
|
||||
|
|
|
@ -30,7 +30,7 @@ typedef enum {
|
|||
PREC_PRIMARY
|
||||
} Precedence;
|
||||
|
||||
typedef void (*ParseFn)();
|
||||
typedef void (*ParseFn)(bool canAssign);
|
||||
|
||||
typedef struct {
|
||||
ParseFn prefix;
|
||||
|
@ -140,7 +140,7 @@ static uint8_t parseVariable(const char *name);
|
|||
static void defineVariable(uint8_t global);
|
||||
static uint8_t identifierConstant(Token *name);
|
||||
|
||||
static void binary() {
|
||||
static void binary(bool canAssign) {
|
||||
TokenType operatorType = parser.previous.type;
|
||||
ParseRule *rule = getRule(operatorType);
|
||||
parsePrecedence((Precedence)(rule->precedence + 1));
|
||||
|
@ -181,7 +181,7 @@ static void binary() {
|
|||
}
|
||||
}
|
||||
|
||||
static void literal() {
|
||||
static void literal(bool canAssign) {
|
||||
switch (parser.previous.type) {
|
||||
case TOKEN_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);
|
||||
emitConstant(NUMBER_VAL(value));
|
||||
}
|
||||
|
||||
static void string() {
|
||||
static void string(bool canAssign) {
|
||||
emitConstant(OBJ_VAL(
|
||||
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);
|
||||
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() {
|
||||
namedVariable(parser.previous);
|
||||
static void variable(bool canAssign) {
|
||||
namedVariable(parser.previous, canAssign);
|
||||
}
|
||||
|
||||
static void unary() {
|
||||
static void unary(bool canAssign) {
|
||||
TokenType operatorType = parser.previous.type;
|
||||
|
||||
// Compile the operand.
|
||||
|
@ -305,7 +311,7 @@ static void unary() {
|
|||
}
|
||||
}
|
||||
|
||||
static void grouping() {
|
||||
static void grouping(bool canAssign) {
|
||||
expression();
|
||||
consume(TOKEN_RIGHT_PAREN, "Expect ')' after expression.");
|
||||
}
|
||||
|
@ -361,12 +367,17 @@ static void parsePrecedence(Precedence precedence) {
|
|||
return;
|
||||
}
|
||||
|
||||
prefixRule();
|
||||
bool canAssign = precedence <= PREC_ASSIGNMENT;
|
||||
prefixRule(canAssign);
|
||||
|
||||
while (precedence <= getRule(parser.current.type)->precedence) {
|
||||
advance();
|
||||
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);
|
||||
case OP_DEFINE_GLOBAL:
|
||||
return constantInstruction("OP_DEFINE_GLOBAL", chunk, offset);
|
||||
case OP_SET_GLOBAL:
|
||||
return constantInstruction("OP_SET_GLOBAL", chunk, offset);
|
||||
case OP_EQUAL:
|
||||
return simpleInstruction("OP_EQUAL", offset);
|
||||
case OP_GREATER:
|
||||
|
|
|
@ -119,8 +119,8 @@ static InterpretResult run() {
|
|||
ObjString *name = READ_STRING();
|
||||
Value value;
|
||||
if (!tableGet(&vm.globals, name, &value)) {
|
||||
runtimeError("Undefined variable '%s'.", name->chars);
|
||||
return INTERPRET_RUNTIME_ERROR;
|
||||
runtimeError("Undefined variable '%s'.", name->chars);
|
||||
return INTERPRET_RUNTIME_ERROR;
|
||||
}
|
||||
push(value);
|
||||
break;
|
||||
|
@ -131,6 +131,15 @@ static InterpretResult run() {
|
|||
pop();
|
||||
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: {
|
||||
Value b = pop();
|
||||
Value a = pop();
|
||||
|
|
Loading…
Reference in a new issue