From cbc5fa14e5834cb8e12897e33aa14d373c7bf23b Mon Sep 17 00:00:00 2001 From: Harrison Shoebridge Date: Thu, 27 Sep 2018 12:30:22 +1000 Subject: [PATCH] Add bytecode hunks, disassembly, and constants --- .gitignore | 33 +-------- .gitmodules | 3 + build.sh | 45 ++++++++++++ env.sh | 2 + src/debug.cpp | 0 src/main.cpp | 193 ++++++++++++++++++++++++++++++++++++++++++++++++++ vendor/uslib | 1 + 7 files changed, 245 insertions(+), 32 deletions(-) create mode 100644 .gitmodules create mode 100755 build.sh create mode 100644 env.sh create mode 100644 src/debug.cpp create mode 100644 src/main.cpp create mode 160000 vendor/uslib diff --git a/.gitignore b/.gitignore index 259148f..378eac2 100644 --- a/.gitignore +++ b/.gitignore @@ -1,32 +1 @@ -# Prerequisites -*.d - -# Compiled Object files -*.slo -*.lo -*.o -*.obj - -# Precompiled Headers -*.gch -*.pch - -# Compiled Dynamic libraries -*.so -*.dylib -*.dll - -# Fortran module files -*.mod -*.smod - -# Compiled Static libraries -*.lai -*.la -*.a -*.lib - -# Executables -*.exe -*.out -*.app +build diff --git a/.gitmodules b/.gitmodules new file mode 100644 index 0000000..a466494 --- /dev/null +++ b/.gitmodules @@ -0,0 +1,3 @@ +[submodule "vendor/uslib"] + path = vendor/uslib + url = git@github.com:paked/us.git diff --git a/build.sh b/build.sh new file mode 100755 index 0000000..d419d06 --- /dev/null +++ b/build.sh @@ -0,0 +1,45 @@ +#!/bin/bash + +# Quick function which exits if the last command ran fails. Intended to be used +# after compiling something. +function compileCheckError() { + if [ ! $? -eq 0 ]; then + echo "Compilation failed, exiting." + + exit 1 + fi +} + +PROJECT_DIR="$(git rev-parse --show-toplevel)" + +if [ ! $? -eq 0 ]; then + echo "For whatever reason, project isn't being built as a git repository. Assuming current directory is the project dir." + + PROJECT_DIR=$(pwd) +fi + +BUILD_DIR=$PROJECT_DIR/build +SRC_DIR=$PROJECT_DIR/src +VENDOR_DIR=$PROJECT_DIR/vendor + +USLIB_FLAGS="-I$VENDOR_DIR/uslib" + +GCC="gcc" +GPP="g++ -Wall -Werror -std=c++11" + +START_TIME=$(date +%s) + +mkdir -p $BUILD_DIR +pushd $BUILD_DIR + +echo "Building program..." +$GPP -o loaf $SRC_DIR/main.cpp $USLIB_FLAGS + +echo "Done!" + +END_TIME=$(date +%s) +TOTAL_TIME=$(expr $END_TIME - $START_TIME) + +echo "Took to build project: $TOTAL_TIME" + +popd diff --git a/env.sh b/env.sh new file mode 100644 index 0000000..ff0c218 --- /dev/null +++ b/env.sh @@ -0,0 +1,2 @@ +alias m="./build.sh" +alias r="./build/loaf" diff --git a/src/debug.cpp b/src/debug.cpp new file mode 100644 index 0000000..e69de29 diff --git a/src/main.cpp b/src/main.cpp new file mode 100644 index 0000000..448677a --- /dev/null +++ b/src/main.cpp @@ -0,0 +1,193 @@ +#include +#include + +#include + +#define REALLOC(Type, ptr, count) ((Type*) realloc(ptr, count * sizeof(Type))) + +enum ProgramResult : uint32 { + PROGRAM_RESULT_OK, + PROGRAM_RESULT_COMPILE_ERROR, + PROGRAM_RESULT_RUNTIME_ERROR +}; + +typedef uint8 Instruction; + +enum OPCode : Instruction { + OP_RETURN, + OP_CONSTANT +}; + +typedef int Value; + +// Constants keeps track of all the available constants in a program. Zero is initialisation. +// TODO(harrison): force constants count to fit within the maximum addressable space by opcodes (256) +#define CONSTANTS_CAPACITY_GROW(c) ( ((c) < 8) ? 8 : (c)*2 ) +struct Constants { + int count; + int capacity; + + // NOTE(harrison): Don't store any references to this pointer. It can change + // unexpectedly. + Value* values; +}; + +// returns -1 on failure +int constants_add(Constants* constants, Value val) { + if (constants->capacity < constants->count + 1) { + constants->capacity = CONSTANTS_CAPACITY_GROW(constants->capacity); + + constants->values = REALLOC(Value, constants->values, constants->capacity); + + if (constants->values == 0) { + return -1; + } + } + + *(constants->values + constants->count) = val; + + constants->count += 1; + + return constants->count - 1; +} + +// Hunk represents a section of Loaf bytecode from a file/module/whatever +// distinction I decide to make. Zero is initialisation. There is no explicit +// free function as Hunk's are expected to last the duration of the program, so +// the operating system can dispose of their memory much better than us. +#define HUNK_CAPACITY_GROW(c) ( ((c) < 8) ? 8 : (c)*2 ) +struct Hunk { + int count; + int capacity; + + // NOTE(harrison): Don't store any references to this pointer. It can change + // unexpectedly. + uint8* code; + uint32* lines; + + Constants constants; +}; + +bool hunk_write(Hunk* hunk, Instruction in, uint32 line) { + if (hunk->capacity < hunk->count + 1) { + hunk->capacity = HUNK_CAPACITY_GROW(hunk->capacity); + + hunk->code = REALLOC(uint8, hunk->code, hunk->capacity); + if (hunk->code == 0) { + return false; + } + + hunk->lines = REALLOC(uint32, hunk->lines, hunk->capacity); + if (hunk->lines == 0) { + return false; + } + } + + *(hunk->code + hunk->count) = in; + *(hunk->lines + hunk->count) = line; + + hunk->count += 1; + + return true; +} + +int hunk_addConstant(Hunk* hunk, Value val) { + return constants_add(&hunk->constants, val); +} + +int hunk_disassembleInstruction(Hunk* hunk, int offset) { + printf("%04d | %04d | ", hunk->lines[offset], offset); + + uint8 in = hunk->code[offset]; +#define SIMPLE_INSTRUCTION(code) \ + case code: \ + { \ + printf("%s\n", #code ); \ +\ + return offset + 1; \ + } break; \ + + switch (in) { + SIMPLE_INSTRUCTION(OP_RETURN); + + case OP_CONSTANT: + { + printf("%s %d\n", "OP_CONSTANT", hunk->constants.values[hunk->code[offset + 1]]); + + return offset + 2; + } break; + + default: + { + printf("Unknown opcode: %d\n", in); + }; + } + + return offset + 1; + +#undef SIMPLE_INSTRUCTION +} + +void hunk_disassemble(Hunk* hunk, const char* name) { + printf("=== %s ===\n", name); + + int i = 0; + + while (i < hunk->count) { + i += hunk_disassembleInstruction(hunk, i); + } +} + +int main(int argc, char** argv) { + Hunk hunk = {0}; + + if (!hunk_write(&hunk, OP_CONSTANT, 0)) { + printf("ERROR: could not write chunk data\n"); + return -1; + } + + int constant = hunk_addConstant(&hunk, 22); + if (constant == -1) { + printf("ERROR: could not add constant\n"); + + return -1; + } + + if (!hunk_write(&hunk, constant, 0)) { + printf("ERROR: could not write chunk data\n"); + + return -1; + } + + if (!hunk_write(&hunk, OP_RETURN, 1)) { + printf("ERROR: could not write chunk data\n"); + return -1; + } + + hunk_disassemble(&hunk, "main"); + + return 0; +} + +/* +int main(int argc, char** argv) { + Program program = {0}; + Hunk hunk = {0}; + + Instruction constant = program_addConstant(&program, 22); + + hunk_write(&hunk, OP_CONSTANT); + hunk_write(&hunk, constant); + + ProgramResult res = program_execute(&program, &hunk); + + if (res != PROGRAM_RESULT_OK) { + // printf("%s\n", program_getError(&program)); + + return 1; + } + + printf("Program finished executing...\n"); + + return 0; +}*/ diff --git a/vendor/uslib b/vendor/uslib new file mode 160000 index 0000000..ee61072 --- /dev/null +++ b/vendor/uslib @@ -0,0 +1 @@ +Subproject commit ee6107223af3ed040b3e2ba051fd938c805bab00