[Chapter22&Locals] - Adding locals

This commit is contained in:
adnanioricce 2024-11-23 19:26:13 -03:00
parent a40570768a
commit 8bce027f37
17 changed files with 160 additions and 7 deletions

@ -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,

Binary file not shown.

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

@ -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 = &current->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 = &current->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;
}

Binary file not shown.

@ -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:

Binary file not shown.

Binary file not shown.

Binary file not shown.

@ -0,0 +1,4 @@
{
var a = "first";
var a = "second";
}

@ -0,0 +1,6 @@
{
var a = "outer";
{
var a = "inner";
}
}

@ -0,0 +1,6 @@
{
var a = "outer";
{
var a = a;
}
}

Binary file not shown.

@ -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

Binary file not shown.