[Chapter22&Locals] - Adding locals
This commit is contained in:
parent
a40570768a
commit
8bce027f37
@ -1,5 +1,7 @@
|
||||
CC = gcc
|
||||
CFLAGS = -Wall -Wextra -g
|
||||
INC_DIR = ./
|
||||
CFLAGS = -Wall -Wextra -g -I$(INC_DIR)
|
||||
DEPS = common.h
|
||||
SOURCES = main.c chunk.c memory.c debug.c value.c vm.c compiler.c scanner.c object.c table.c
|
||||
OBJECTS = $(SOURCES:.c=.o)
|
||||
EXECUTABLE = clox
|
||||
@ -9,7 +11,7 @@ all: $(EXECUTABLE)
|
||||
$(EXECUTABLE): $(OBJECTS)
|
||||
$(CC) $(CFLAGS) -o $@ $(OBJECTS)
|
||||
|
||||
%.o: %.c
|
||||
%.o: %.c $(DEPS)
|
||||
$(CC) $(CFLAGS) -c $< -o $@
|
||||
|
||||
clean:
|
||||
|
@ -10,6 +10,8 @@ typedef enum {
|
||||
OP_TRUE,
|
||||
OP_FALSE,
|
||||
OP_POP,
|
||||
OP_GET_LOCAL,
|
||||
OP_SET_LOCAL,
|
||||
OP_GET_GLOBAL,
|
||||
OP_SET_GLOBAL,
|
||||
OP_DEFINE_GLOBAL,
|
||||
|
BIN
clox/chunk.o
BIN
clox/chunk.o
Binary file not shown.
BIN
clox/clox
BIN
clox/clox
Binary file not shown.
@ -6,5 +6,6 @@
|
||||
#include <stdint.h>
|
||||
|
||||
#define DEBUG_TRACE_EXECUTION
|
||||
#define UINT8_COUNT (UINT8_MAX + 1)
|
||||
#define DEBUG_PRINT_CODE
|
||||
#endif
|
||||
|
121
clox/compiler.c
121
clox/compiler.c
@ -1,5 +1,6 @@
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "common.h"
|
||||
#include "compiler.h"
|
||||
@ -38,7 +39,19 @@ typedef struct {
|
||||
Precedence precedence;
|
||||
} ParseRule;
|
||||
|
||||
typedef struct {
|
||||
Token name;
|
||||
int depth;
|
||||
} Local;
|
||||
|
||||
typedef struct {
|
||||
Local locals[UINT8_COUNT];
|
||||
int localCount;
|
||||
int scopeDepth;
|
||||
} Compiler;
|
||||
|
||||
Parser parser;
|
||||
Compiler* current = NULL;
|
||||
Chunk* compilingChunk;
|
||||
|
||||
static Chunk* currentChunk() {
|
||||
@ -127,6 +140,12 @@ static void emitConstant(Value value) {
|
||||
emitBytes(OP_CONSTANT, makeConstant(value));
|
||||
}
|
||||
|
||||
static void initCompiler(Compiler* compiler) {
|
||||
compiler->localCount = 0;
|
||||
compiler->scopeDepth = 0;
|
||||
current = compiler;
|
||||
}
|
||||
|
||||
static void endCompiler() {
|
||||
emitReturn();
|
||||
#ifdef DEBUG_PRINT_CODE
|
||||
@ -135,6 +154,20 @@ static void endCompiler() {
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
static void beginScope() {
|
||||
current->scopeDepth++;
|
||||
}
|
||||
|
||||
static void endScope() {
|
||||
current->scopeDepth--;
|
||||
while (current->localCount > 0 &&
|
||||
current->locals[current->localCount - 1].depth >
|
||||
current->scopeDepth) {
|
||||
emitByte(OP_POP);
|
||||
current->localCount--;
|
||||
}
|
||||
}
|
||||
static void expression();
|
||||
static void statement();
|
||||
static void declaration();
|
||||
@ -144,13 +177,69 @@ static void parsePrecedence(Precedence precedence);
|
||||
static uint8_t identifierConstant(Token* name) {
|
||||
return makeConstant(OBJ_VAL(copyString(name->start,name->length)));
|
||||
}
|
||||
static bool identifiersEqual(Token* a, Token* b) {
|
||||
if (a->length != b->length) return false;
|
||||
return memcmp(a->start, b->start, a->length) == 0;
|
||||
}
|
||||
static int resolveLocal(Compiler* compiler, Token* name) {
|
||||
for (int i = compiler->localCount - 1; i >= 0; i--) {
|
||||
Local* local = &compiler->locals[i];
|
||||
if (identifiersEqual(name, &local->name)) {
|
||||
if (local->depth == -1) {
|
||||
error("Can't read local variable in its own initializer.");
|
||||
}
|
||||
return i;
|
||||
}
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
static void addLocal(Token name) {
|
||||
if (current->localCount == UINT8_COUNT) {
|
||||
error("Too many local variables in function.");
|
||||
return;
|
||||
}
|
||||
Local* local = ¤t->locals[current->localCount++];
|
||||
local->name = name;
|
||||
local->depth = -1;
|
||||
// local->depth = current->scopeDepth;
|
||||
}
|
||||
|
||||
static void declareVariable() {
|
||||
if (current->scopeDepth == 0) return;
|
||||
|
||||
Token* name = &parser.previous;
|
||||
for (int i = current->localCount - 1; i >= 0; i--) {
|
||||
Local* local = ¤t->locals[i];
|
||||
if (local->depth != -1 && local->depth < current->scopeDepth) {
|
||||
break;
|
||||
}
|
||||
|
||||
if (identifiersEqual(name, &local->name)) {
|
||||
error("Already a variable with this name in this scope.");
|
||||
}
|
||||
}
|
||||
addLocal(*name);
|
||||
}
|
||||
|
||||
static uint8_t parseVariable(const char* errorMessage) {
|
||||
consume(TOKEN_IDENTIFIER, errorMessage);
|
||||
|
||||
declareVariable();
|
||||
if (current->scopeDepth > 0) return 0;
|
||||
|
||||
return identifierConstant(&parser.previous);
|
||||
}
|
||||
|
||||
static void markInitialized() {
|
||||
current->locals[current->localCount - 1].depth = current->scopeDepth;
|
||||
}
|
||||
|
||||
static void defineVariable(uint8_t global) {
|
||||
if (current->scopeDepth > 0) {
|
||||
markInitialized();
|
||||
return;
|
||||
}
|
||||
emitBytes(OP_DEFINE_GLOBAL, global);
|
||||
}
|
||||
|
||||
@ -188,6 +277,13 @@ static void expression() {
|
||||
// What goes here?
|
||||
parsePrecedence(PREC_ASSIGNMENT);
|
||||
}
|
||||
static void block() {
|
||||
while (!check(TOKEN_RIGHT_BRACE) && !check(TOKEN_EOF)) {
|
||||
declaration();
|
||||
}
|
||||
|
||||
consume(TOKEN_RIGHT_BRACE, "Expect '}' after block.");
|
||||
}
|
||||
|
||||
static void varDeclaration() {
|
||||
uint8_t global = parseVariable("Expect variable name.");
|
||||
@ -253,6 +349,11 @@ static void statement() {
|
||||
if (match(TOKEN_PRINT)) {
|
||||
printStatement();
|
||||
}
|
||||
else if (match(TOKEN_LEFT_BRACE)) {
|
||||
beginScope();
|
||||
block();
|
||||
endScope();
|
||||
}
|
||||
else {
|
||||
expressionStatement();
|
||||
}
|
||||
@ -274,13 +375,23 @@ static void string(bool canAssign) {
|
||||
}
|
||||
|
||||
static void namedVariable(Token name, bool canAssign) {
|
||||
uint8_t arg = identifierConstant(&name);
|
||||
// uint8_t arg = identifierConstant(&name);
|
||||
uint8_t getOp, setOp;
|
||||
int arg = resolveLocal(current, &name);
|
||||
if (arg != -1) {
|
||||
getOp = OP_GET_LOCAL;
|
||||
setOp = OP_SET_LOCAL;
|
||||
} else {
|
||||
arg = identifierConstant(&name);
|
||||
getOp = OP_GET_GLOBAL;
|
||||
setOp = OP_SET_GLOBAL;
|
||||
}
|
||||
|
||||
if (canAssign && match(TOKEN_EQUAL)) {
|
||||
expression();
|
||||
emitBytes(OP_SET_GLOBAL, arg);
|
||||
emitBytes(setOp, (uint8_t)arg);
|
||||
} else {
|
||||
emitBytes(OP_GET_GLOBAL, arg);
|
||||
emitBytes(getOp, (uint8_t)arg);
|
||||
}
|
||||
}
|
||||
|
||||
@ -373,6 +484,8 @@ static ParseRule* getRule(TokenType type) {
|
||||
|
||||
bool compile(const char* source, Chunk* chunk) {
|
||||
initScanner(source);
|
||||
Compiler compiler;
|
||||
initCompiler(&compiler);
|
||||
compilingChunk = chunk;
|
||||
parser.hadError = false;
|
||||
parser.panicMode = false;
|
||||
@ -380,8 +493,6 @@ bool compile(const char* source, Chunk* chunk) {
|
||||
while (!match(TOKEN_EOF)) {
|
||||
declaration();
|
||||
}
|
||||
// expression();
|
||||
// consume(TOKEN_EOF, "Expect end of expression.");
|
||||
endCompiler();
|
||||
return !parser.hadError;
|
||||
}
|
||||
|
BIN
clox/compiler.o
BIN
clox/compiler.o
Binary file not shown.
11
clox/debug.c
11
clox/debug.c
@ -22,6 +22,13 @@ static int simpleInstruction(const char* name, int offset) {
|
||||
printf("%s\n", name);
|
||||
return offset + 1;
|
||||
}
|
||||
static int byteInstruction(const char* name, Chunk* chunk,
|
||||
int offset) {
|
||||
uint8_t slot = chunk->code[offset + 1];
|
||||
printf("%-16s %4d\n", name, slot);
|
||||
return offset + 2;
|
||||
}
|
||||
|
||||
int disassembleInstruction(Chunk* chunk, int offset) {
|
||||
printf("%04d ", offset);
|
||||
|
||||
@ -44,6 +51,10 @@ int disassembleInstruction(Chunk* chunk, int offset) {
|
||||
return simpleInstruction("OP_FALSE", offset);
|
||||
case OP_POP:
|
||||
return simpleInstruction("OP_POP", offset);
|
||||
case OP_GET_LOCAL:
|
||||
return byteInstruction("OP_GET_LOCAL", chunk, offset);
|
||||
case OP_SET_LOCAL:
|
||||
return byteInstruction("OP_SET_LOCAL", chunk, offset);
|
||||
case OP_GET_GLOBAL:
|
||||
return constantInstruction("OP_GET_GLOBAL", chunk, offset);
|
||||
case OP_DEFINE_GLOBAL:
|
||||
|
BIN
clox/debug.o
BIN
clox/debug.o
Binary file not shown.
BIN
clox/main.o
BIN
clox/main.o
Binary file not shown.
BIN
clox/scanner.o
BIN
clox/scanner.o
Binary file not shown.
4
clox/tests/chapter22/case2.lox
Normal file
4
clox/tests/chapter22/case2.lox
Normal file
@ -0,0 +1,4 @@
|
||||
{
|
||||
var a = "first";
|
||||
var a = "second";
|
||||
}
|
6
clox/tests/chapter22/case3.lox
Normal file
6
clox/tests/chapter22/case3.lox
Normal file
@ -0,0 +1,6 @@
|
||||
{
|
||||
var a = "outer";
|
||||
{
|
||||
var a = "inner";
|
||||
}
|
||||
}
|
6
clox/tests/chapter22/case4.lox
Normal file
6
clox/tests/chapter22/case4.lox
Normal file
@ -0,0 +1,6 @@
|
||||
{
|
||||
var a = "outer";
|
||||
{
|
||||
var a = a;
|
||||
}
|
||||
}
|
BIN
clox/value.o
BIN
clox/value.o
Binary file not shown.
10
clox/vm.c
10
clox/vm.c
@ -145,6 +145,16 @@ static InterpretResult run() {
|
||||
push(BOOL_VAL(isFalsey(pop())));
|
||||
break;
|
||||
case OP_POP: pop(); break;
|
||||
case OP_GET_LOCAL: {
|
||||
uint8_t slot = READ_BYTE();
|
||||
push(vm.stack[slot]);
|
||||
break;
|
||||
}
|
||||
case OP_SET_LOCAL: {
|
||||
uint8_t slot = READ_BYTE();
|
||||
vm.stack[slot] = peek(0);
|
||||
break;
|
||||
}
|
||||
case OP_GET_GLOBAL: {
|
||||
ObjString* name = READ_STRING();
|
||||
Value value;
|
||||
|
BIN
clox/vm.o
BIN
clox/vm.o
Binary file not shown.
Loading…
Reference in New Issue
Block a user