Notes
This commit is contained in:
parent
a6153e87ec
commit
021696daa1
46
NOTES.md
Normal file
46
NOTES.md
Normal 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>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
@ -2,6 +2,7 @@
|
||||
|
||||
## Description
|
||||
My code/notes for Crafting Interpreters
|
||||
|
||||
## Table of Contents
|
||||
|
||||
- [Description](#description)
|
||||
|
@ -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
18
include/value.h
Normal 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
|
13
src/chunk.c
13
src/chunk.c
@ -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;
|
||||
}
|
||||
|
18
src/debug.c
18
src/debug.c
@ -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
28
src/value.c
Normal 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);
|
||||
}
|
@ -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);
|
||||
|
Loading…
Reference in New Issue
Block a user