This commit is contained in:
Randy Jordan 2024-08-31 15:54:46 -05:00
parent a6153e87ec
commit 021696daa1
No known key found for this signature in database
GPG Key ID: BF8CCF4CDDE47493
8 changed files with 134 additions and 5 deletions

46
NOTES.md Normal file
View File

@ -0,0 +1,46 @@
# clox
## Description
My notes for Crafting Interpreters
## Table of Contents
- [Description](#description)
- [Chunks of Bytecode](#chunks-of-bytecode)
## Chunks of Bytecode
### Why Bytecode
Goes over the choice of bytecode vs machine code / assembly. <br>
Compiling to native instruction set the chip supports is what the fastest languages do.<br>
However, this is extremely low-level and time consuming. Portability is just exponential complexity at that level.<br>
We're exchanging performance for portability by writing an emulator in C.<br>
That emulator is a VM or virtual machine to run that bytecode one instruction at a time.
### Dynamic Arrays
Goes over his interface and implementation of dynamic arrays.<br>
The `struct` contains a pointer to items of "type". Ex. `uint8_t *data, void *ptr`, etc. <br>
It also contains the current length and capacity of the array.<br>
The implementation contains a reallocate, initType, freeType, and writeType function.<br>
It exposes three macros `GROW_CAP(cap), GROW_ARRAY(type,ptr,old*type,new*type), and FREE_ARRAY`. <br>
GROW_CAP is how you handle growing your capacity.<br>
FREE_ARRAY and GROW_ARRAY utilize our reallocate implementation.<br>
### Chunks
Now we can build dynamic arrays or "Chunks" of instructions or operations. These will be `uint8_t *ptr`. Which is the instruction number or Enum.<br>
This gives us 255 available operations or instructions we can have.<br>
Once we have instructions, we also want to be able to have constant values. This is another dynamic array inside chunk.<br>
These type "values" are really the C primitive double type. 64 bits.<br>
Instead of writing to it like earlier make a function to add new values and return the index so we can track it. <br>
For line debugging we add an array of integers to act as a LUT with index of the operation. Each operation maps to a line.<br>
To disassemble, we just need to write a disassemble chunk function. Instead of iterating or incrementing the offset, disassembleInstruction returns the <b>next</b> offset.<br>
The offset of the first chunk is it's length. From there disassembleInstruction performs a switch statement on the operation or instruction to return the proper offset.<br>
disassembleChunk prints out the "name" which is going to be used for the __FILE__, the chunk maps to a line, operation, and possible value.<br>

View File

@ -2,6 +2,7 @@
## Description
My code/notes for Crafting Interpreters
## Table of Contents
- [Description](#description)

View File

@ -2,8 +2,10 @@
#define CHUNK_INCLUDED
#include "common.h"
#include "value.h"
typedef enum {
OP_CONSTANT,
OP_RETURN,
OP_COUNT,
}OpCode;
@ -12,10 +14,13 @@ typedef struct {
int len;
int cap;
uint8_t* code;
int *lines;
ValueArray constants;
} Chunk;
void initChunk(Chunk *chunk);
void freeChunk(Chunk *chunk);
void writeChunk(Chunk *chunk, uint8_t byte);
void writeChunk(Chunk *chunk, uint8_t byte,int line);
int addConstant(Chunk *chunk, Value value);
#endif

18
include/value.h Normal file
View File

@ -0,0 +1,18 @@
#ifndef VALUE_INCLUDED
#define VALUE_INCLUDED
#include "common.h"
typedef double Value;
typedef struct {
int len;
int cap;
Value *values;
} ValueArray;
void initValueArray(ValueArray *array);
void writeValueArray(ValueArray *array, Value value);
void freeValueArray(ValueArray *array);
void printValue(Value value);
#endif

View File

@ -4,18 +4,27 @@ void initChunk(Chunk *chunk){
chunk->len =0;
chunk->cap = 0;
chunk->code = NULL;
chunk->lines = NULL;
initValueArray(&chunk->constants);
}
void freeChunk(Chunk *chunk){
FREE_ARRAY(uint8_t, chunk->code, chunk->cap);
FREE_ARRAY(int,chunk->lines,chunk->cap);
freeValueArray(&chunk->constants);
initChunk(chunk);
}
void writeChunk(Chunk *chunk, uint8_t byte){
void writeChunk(Chunk *chunk, uint8_t byte, int line){
if(chunk->cap < chunk->len+1){// If we don't have room grow it.
int oldCap = chunk->cap;
chunk->cap = GROW_CAP(oldCap);
chunk->code = GROW_ARRAY(uint8_t, chunk->code, oldCap, chunk->cap);
chunk->lines =GROW_ARRAY(int,chunk->lines,oldCap,chunk->cap);
} // Else write byte to chunk
chunk->code[chunk->len] = byte;
chunk->lines[chunk->len] = line;
chunk->len++;
}
int addConstant(Chunk *chunk, Value value){
writeValueArray(&chunk->constants,value);
return chunk->constants.len-1;
}

View File

@ -1,5 +1,6 @@
#include <stdio.h>
#include "../include/debug.h"
#include "../include/value.h"
void disassembleChunk(Chunk *chunk, const char* name){
printf("== %s ==\n",name);
@ -7,15 +8,32 @@ void disassembleChunk(Chunk *chunk, const char* name){
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\t",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:

28
src/value.c Normal file
View File

@ -0,0 +1,28 @@
#include <stdio.h>
#include "../include/memory.h"
#include "../include/value.h"
void initValueArray(ValueArray *array){
array->values = NULL;
array->cap = 0;
array->len = 0;
}
void writeValueArray(ValueArray *array, Value value){
if(array->cap < array->len+1){
int oldCap = array->cap;
array->cap = GROW_CAP(oldCap);
array->values = GROW_ARRAY(Value,array->values,oldCap, array->cap);
}
array->values[array->len] = value;
array->len ++;
}
void freeValueArray(ValueArray *array){
FREE_ARRAY(Value, array->values,array->cap);
initValueArray(array);
}
void printValue(Value value){
printf("%g",value);
}

View File

@ -5,7 +5,11 @@
int main(void){
Chunk chunk;
initChunk(&chunk);
writeChunk(&chunk, OP_RETURN);
int constant = addConstant(&chunk,1.2);
writeChunk(&chunk, OP_CONSTANT,10);
writeChunk(&chunk,constant,10);
writeChunk(&chunk, OP_RETURN,10);
disassembleChunk(&chunk,"Test Chunk");
freeChunk(&chunk);