From 44c7626cd7c12bb5e90417fc621448d7ac691782 Mon Sep 17 00:00:00 2001 From: Daniel Henry Date: Thu, 21 Aug 2025 16:14:22 -0500 Subject: [PATCH] Finish Chapter 14 Implements code chunks, a couple of basic opcodes, constants, and basic execution of those opcodes. Signed-off-by: Daniel Henry --- .gitignore | 7 +++++++ .ignore | 8 ++++++++ Makefile | 50 ++++++++++++++++++++++++++++++++++++++++++++++++ include/chunk.h | 25 ++++++++++++++++++++++++ include/common.h | 8 ++++++++ include/debug.h | 9 +++++++++ include/memory.h | 15 +++++++++++++++ include/value.h | 19 ++++++++++++++++++ src/chunk.c | 37 +++++++++++++++++++++++++++++++++++ src/debug.c | 46 ++++++++++++++++++++++++++++++++++++++++++++ src/main.c | 16 ++++++++++++++++ src/memory.c | 15 +++++++++++++++ src/value.c | 31 ++++++++++++++++++++++++++++++ 13 files changed, 286 insertions(+) create mode 100644 .gitignore create mode 100644 .ignore create mode 100644 Makefile create mode 100644 include/chunk.h create mode 100644 include/common.h create mode 100644 include/debug.h create mode 100644 include/memory.h create mode 100644 include/value.h create mode 100644 src/chunk.c create mode 100644 src/debug.c create mode 100644 src/main.c create mode 100644 src/memory.c create mode 100644 src/value.c diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..511ece8 --- /dev/null +++ b/.gitignore @@ -0,0 +1,7 @@ +.cache +compile_commands.json +.clang-format + +build/ +obj/ +bin/ diff --git a/.ignore b/.ignore new file mode 100644 index 0000000..14b5203 --- /dev/null +++ b/.ignore @@ -0,0 +1,8 @@ +.cache +.ignore +compile_commands.json + +build/ +obj/ +bin/ +.git/ diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..12c469f --- /dev/null +++ b/Makefile @@ -0,0 +1,50 @@ +# Compiler and flags +CC := clang +CFLAGS := -Wall -Wextra -g -xc -std=c99 -I./include +LDFLAGS := + +EXEC_NAME := $(notdir $(shell dirname $(realpath $(lastword $(MAKEFILE_LIST))))) + +# Directories +SRC_DIR := src +OBJ_DIR := obj +BIN_DIR := bin + +# Find all source files recursively +SRCS := $(shell find $(SRC_DIR) -name '*.c') +# Generate object file paths by replacing src/ with obj/ and .c with .o +OBJS := $(SRCS:$(SRC_DIR)/%.c=$(OBJ_DIR)/%.o) +# Final executable name +EXEC := $(BIN_DIR)/$(EXEC_NAME) + +# First rule is the default rule +.PHONY: all +all: $(EXEC) + +# Rule to create directories if they don't exist +$(BIN_DIR) $(OBJ_DIR): + mkdir -p $@ + +# Rule to create object files +$(OBJ_DIR)/%.o: $(SRC_DIR)/%.c | $(OBJ_DIR) + @mkdir -p $(dir $@) + $(CC) $(CFLAGS) -c $< -o $@ + +# Rule to create the executable +$(EXEC): $(OBJS) | $(BIN_DIR) + $(CC) $(OBJS) $(LDFLAGS) -o $@ + +# Clean rule to remove generated files +.PHONY: clean +clean: + rm -rf $(OBJ_DIR) $(BIN_DIR) + +# Debug rule to print variables +.PHONY: debug +debug: + @echo "Source files:" $(SRCS) + @echo "Object files:" $(OBJS) + +.PHONY: compiledb +bear: clean + bear -- make diff --git a/include/chunk.h b/include/chunk.h new file mode 100644 index 0000000..5d9100f --- /dev/null +++ b/include/chunk.h @@ -0,0 +1,25 @@ +#ifndef clox_chunk_h +#define clox_chunk_h + +#include "common.h" +#include "value.h" + +typedef enum { + OP_CONSTANT, + OP_RETURN, +} OpCode; + +typedef struct { + int count; + int capacity; + uint8_t *code; + int *lines; + ValueArray constants; +} Chunk; + +void initChunk(Chunk *chunk); +void freeChunk(Chunk *chunk); +void writeChunk(Chunk *chunk, uint8_t byte, int line); +int addConstant(Chunk *chunk, Value value); + +#endif /* clox_chunk_h */ diff --git a/include/common.h b/include/common.h new file mode 100644 index 0000000..c827b76 --- /dev/null +++ b/include/common.h @@ -0,0 +1,8 @@ +#ifndef clox_common_h +#define clox_common_h + +#include +#include +#include + +#endif diff --git a/include/debug.h b/include/debug.h new file mode 100644 index 0000000..9052d5b --- /dev/null +++ b/include/debug.h @@ -0,0 +1,9 @@ +#ifndef clox_debug_h +#define clox_debug_h + +#include "chunk.h" + +void disassembleChunk(Chunk *chunk, const char *name); +int disassembleInstruction(Chunk *chunk, int offset); + +#endif /* clox_debug_h */ diff --git a/include/memory.h b/include/memory.h new file mode 100644 index 0000000..da0e0b5 --- /dev/null +++ b/include/memory.h @@ -0,0 +1,15 @@ +#ifndef clox_memory_h +#define clox_memory_h + +#include "common.h" + +#define GROW_CAPACITY(capacity) ((capacity) < 8 ? 8 : (capacity) * 2) +#define GROW_ARRAY(type, pointer, oldCount, newCount) \ + (type *)reallocate(pointer, sizeof(type) * (oldCount), \ + sizeof(type) * (newCount)) +#define FREE_ARRAY(type, pointer, oldCount) \ + reallocate(pointer, sizeof(type) * oldCount, 0); + +void *reallocate(void *pointer, size_t oldSize, size_t newSize); + +#endif /* clox_memory_h */ diff --git a/include/value.h b/include/value.h new file mode 100644 index 0000000..5a42303 --- /dev/null +++ b/include/value.h @@ -0,0 +1,19 @@ +#ifndef clox_value_h +#define clox_value_h + +#include "common.h" + +typedef double Value; + +typedef struct { + int capacity; + int count; + Value *values; +} ValueArray; + +void initValueArray(ValueArray *array); +void writeValueArray(ValueArray *array, Value value); +void freeValueArray(ValueArray *array); +void printValue(Value value); + +#endif /* clox_value_h */ diff --git a/src/chunk.c b/src/chunk.c new file mode 100644 index 0000000..ac786f4 --- /dev/null +++ b/src/chunk.c @@ -0,0 +1,37 @@ +#include "chunk.h" +#include "memory.h" +#include + +void initChunk(Chunk *chunk) { + chunk->count = 0; + chunk->capacity = 0; + chunk->code = NULL; + chunk->lines = NULL; + initValueArray(&chunk->constants); +} + +void freeChunk(Chunk *chunk) { + FREE_ARRAY(uint8_t, chunk->code, chunk->capacity); + FREE_ARRAY(int, chunk->lines, chunk->capacity); + freeValueArray(&chunk->constants); + initChunk(chunk); +} + +void writeChunk(Chunk *chunk, uint8_t byte, int line) { + if (chunk->capacity < chunk->count + 1) { + int oldCapacity = chunk->capacity; + chunk->capacity = GROW_CAPACITY(oldCapacity); + chunk->code = + GROW_ARRAY(uint8_t, chunk->code, oldCapacity, chunk->capacity); + chunk->lines = GROW_ARRAY(int, chunk->lines, oldCapacity, chunk->capacity); + } + + chunk->code[chunk->count] = byte; + chunk->lines[chunk->count] = line; + chunk->count++; +} + +int addConstant(Chunk *chunk, Value value) { + writeValueArray(&chunk->constants, value); + return chunk->constants.count - 1; +} diff --git a/src/debug.c b/src/debug.c new file mode 100644 index 0000000..428b49e --- /dev/null +++ b/src/debug.c @@ -0,0 +1,46 @@ +#include "debug.h" +#include + +#include "chunk.h" +#include "value.h" + +void disassembleChunk(Chunk *chunk, const char *name) { + printf("== %s ==\n", name); + + for (int offset = 0; offset < chunk->count;) { + offset = disassembleInstruction(chunk, offset); + } +} + +static int constantInstruction(const char *name, Chunk *chunk, int offset) { + uint8_t constant = chunk->code[offset + 1]; + printf("%-16s %4d '", name, constant); + printValue(chunk->constants.values[constant]); + printf("'\n"); + return offset + 2; +} + +static int simpleInstruction(const char *name, int offset) { + printf("%s\n", name); + return offset + 1; +} + +int disassembleInstruction(Chunk *chunk, int offset) { + printf("%04d ", offset); + if (offset > 0 && chunk->lines[offset] == chunk->lines[offset - 1]) { + printf(" | "); + } else { + printf("%4d ", chunk->lines[offset]); + } + + uint8_t instruction = chunk->code[offset]; + switch (instruction) { + case OP_CONSTANT: + return constantInstruction("OP_CONSTANT", chunk, offset); + case OP_RETURN: + return simpleInstruction("OP_RETURN", offset); + default: + printf("Unknownopcode %d\n", instruction); + return offset + 1; + } +} diff --git a/src/main.c b/src/main.c new file mode 100644 index 0000000..30e3298 --- /dev/null +++ b/src/main.c @@ -0,0 +1,16 @@ +#include "chunk.h" +#include "common.h" +#include "debug.h" + +int main(int argc, const char *argv[]) { + Chunk chunk; + initChunk(&chunk); + int constant = addConstant(&chunk, 1.2); + writeChunk(&chunk, OP_CONSTANT, 123); + writeChunk(&chunk, constant, 123); + writeChunk(&chunk, OP_RETURN, 123); + + disassembleChunk(&chunk, "test chunk"); + freeChunk(&chunk); + return 0; +} diff --git a/src/memory.c b/src/memory.c new file mode 100644 index 0000000..d4eb410 --- /dev/null +++ b/src/memory.c @@ -0,0 +1,15 @@ +#include "memory.h" +#include + +void *reallocate(void *pointer, size_t oldSize, size_t newSize) { + if (newSize == 0) { + free(pointer); + return NULL; + } + + void *result = realloc(pointer, newSize); + if (result == NULL) { + exit(1); + } + return result; +} diff --git a/src/value.c b/src/value.c new file mode 100644 index 0000000..5ec70ea --- /dev/null +++ b/src/value.c @@ -0,0 +1,31 @@ +#include + +#include "memory.h" +#include "value.h" + +void initValueArray(ValueArray *array) { + array->values = NULL; + array->capacity = 0; + array->count = 0; +} + +void writeValueArray(ValueArray *array, Value value) { + if (array->capacity < array->count + 1) { + int oldCapacity = array->capacity; + array->capacity = GROW_CAPACITY(oldCapacity); + array->values = + GROW_ARRAY(Value, array->values, oldCapacity, array->capacity); + } + + array->values[array->count] = value; + array->count++; +} + +void freeValueArray(ValueArray *array) { + FREE_ARRAY(Value, array->values, array->capacity); + initValueArray(array); +} + +void printValue(Value value) { + printf("%g", value); +}