Finish Chapter 14
Implements code chunks, a couple of basic opcodes, constants, and basic execution of those opcodes. Signed-off-by: Daniel Henry <iamdanhenry@gmail.com>
This commit is contained in:
7
.gitignore
vendored
Normal file
7
.gitignore
vendored
Normal file
@@ -0,0 +1,7 @@
|
||||
.cache
|
||||
compile_commands.json
|
||||
.clang-format
|
||||
|
||||
build/
|
||||
obj/
|
||||
bin/
|
||||
8
.ignore
Normal file
8
.ignore
Normal file
@@ -0,0 +1,8 @@
|
||||
.cache
|
||||
.ignore
|
||||
compile_commands.json
|
||||
|
||||
build/
|
||||
obj/
|
||||
bin/
|
||||
.git/
|
||||
50
Makefile
Normal file
50
Makefile
Normal file
@@ -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
|
||||
25
include/chunk.h
Normal file
25
include/chunk.h
Normal file
@@ -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 */
|
||||
8
include/common.h
Normal file
8
include/common.h
Normal file
@@ -0,0 +1,8 @@
|
||||
#ifndef clox_common_h
|
||||
#define clox_common_h
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#endif
|
||||
9
include/debug.h
Normal file
9
include/debug.h
Normal file
@@ -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 */
|
||||
15
include/memory.h
Normal file
15
include/memory.h
Normal file
@@ -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 */
|
||||
19
include/value.h
Normal file
19
include/value.h
Normal file
@@ -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 */
|
||||
37
src/chunk.c
Normal file
37
src/chunk.c
Normal file
@@ -0,0 +1,37 @@
|
||||
#include "chunk.h"
|
||||
#include "memory.h"
|
||||
#include <stdlib.h>
|
||||
|
||||
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;
|
||||
}
|
||||
46
src/debug.c
Normal file
46
src/debug.c
Normal file
@@ -0,0 +1,46 @@
|
||||
#include "debug.h"
|
||||
#include <stdio.h>
|
||||
|
||||
#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;
|
||||
}
|
||||
}
|
||||
16
src/main.c
Normal file
16
src/main.c
Normal file
@@ -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;
|
||||
}
|
||||
15
src/memory.c
Normal file
15
src/memory.c
Normal file
@@ -0,0 +1,15 @@
|
||||
#include "memory.h"
|
||||
#include <stdlib.h>
|
||||
|
||||
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;
|
||||
}
|
||||
31
src/value.c
Normal file
31
src/value.c
Normal file
@@ -0,0 +1,31 @@
|
||||
#include <stdio.h>
|
||||
|
||||
#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);
|
||||
}
|
||||
Reference in New Issue
Block a user