From 763581c73b8ac8a61223459f75cbc4876be81ada Mon Sep 17 00:00:00 2001 From: Kayne Ruse Date: Wed, 7 Jun 2023 23:55:30 +1000 Subject: [PATCH] Added header-only parsing to the repl, read more Also: * Ensured TOY_VERSION_BUILD is consistent throughout the whole build * Updated README.md --- README.md | 9 +++++--- repl/repl_main.c | 10 ++++++-- repl/repl_tools.c | 56 +++++++++++++++++++++++++++++++++++++++++++++ repl/repl_tools.h | 1 + source/toy_common.c | 18 +++++++++++++++ source/toy_common.h | 7 ++++-- 6 files changed, 94 insertions(+), 7 deletions(-) diff --git a/README.md b/README.md index ae13c78..bf41f88 100644 --- a/README.md +++ b/README.md @@ -4,9 +4,11 @@ # Toy -This is the Toy programming language interpreter, written in C. +The Toy programming language is an imperative bytecode-intermediate embedded scripting language. It isn't intended to operate on its own, but rather as part of another program, the "host". This process is intended to allow a decent amount of easy customisation by the host's end user, by exposing logic in script files. Alternatively, binary files in a custom format can be used as well. -Special thanks to http://craftinginterpreters.com/ for their fantastic book that set me on this path. +The host will provide all of the extensions needed on a case-by-case basis. Script files have the `.toy` file extension, while binary files have the `.tb` file extension. + +This is the Toy programming language interpreter, written in C. # Nifty Features @@ -14,7 +16,7 @@ Special thanks to http://craftinginterpreters.com/ for their fantastic book that * Bytecode intermediate compilation * Optional, but robust type system (including `opaque` for arbitrary data) * Functions and types are first-class citizens -* Import external libraries +* Import native libraries from the host * Fancy slice notation for strings, arrays and dictionaries * Can re-direct output, error and assertion failure messages * Open source under the zlib license @@ -71,3 +73,4 @@ This source code is covered by the zlib license (see [LICENSE.md](LICENSE.md)). * Seth A. Robinson +Special thanks to http://craftinginterpreters.com/ for their fantastic book that set me on this path. \ No newline at end of file diff --git a/repl/repl_main.c b/repl/repl_main.c index 24f2c90..5d3a8c0 100644 --- a/repl/repl_main.c +++ b/repl/repl_main.c @@ -193,8 +193,14 @@ int main(int argc, const char* argv[]) { return -1; } - //run the binary file - Toy_runBinaryFile(Toy_commandLine.binaryfile); + if (Toy_commandLine.parseBytecodeHeader) { + //only parse the bytecode header + Toy_parseBinaryFileHeader(Toy_commandLine.binaryfile); + } + else { + //run the binary file + Toy_runBinaryFile(Toy_commandLine.binaryfile); + } //lib cleanup Toy_freeDriveSystem(); diff --git a/repl/repl_tools.c b/repl/repl_tools.c index fd44bd7..63090f9 100644 --- a/repl/repl_tools.c +++ b/repl/repl_tools.c @@ -149,3 +149,59 @@ void Toy_runSourceFile(const char* fname) { Toy_runSource(source); free((void*)source); } + +//utils for debugging the header +static unsigned char readByte(const unsigned char* tb, int* count) { + unsigned char ret = *(unsigned char*)(tb + *count); + *count += 1; + return ret; +} + +static const char* readString(const unsigned char* tb, int* count) { + const unsigned char* ret = tb + *count; + *count += strlen((char*)ret) + 1; //+1 for null character + return (const char*)ret; +} + +void Toy_parseBinaryFileHeader(const char* fname) { + size_t size = 0; //not used + const unsigned char* tb = Toy_readFile(fname, &size); + if (!tb || size < 4) { + return; + } + + int count = 0; + + //header section + const unsigned char major = readByte(tb, &count); + const unsigned char minor = readByte(tb, &count); + const unsigned char patch = readByte(tb, &count); + + const char* build = readString(tb, &count); + + printf("Toy Programming Language Interpreter Version %d.%d.%d (interpreter built on %s)\n\n", TOY_VERSION_MAJOR, TOY_VERSION_MINOR, TOY_VERSION_PATCH, TOY_VERSION_BUILD); + + printf("Toy Programming Language Bytecode Version "); + + //print the output + if (major == TOY_VERSION_MAJOR && minor == TOY_VERSION_MINOR && patch == TOY_VERSION_PATCH) { + printf("%d.%d.%d", major, minor, patch); + } + else { + printf(TOY_CC_FONT_YELLOW TOY_CC_BACK_BLACK "%d.%d.%d" TOY_CC_RESET, major, minor, patch); + } + + printf(" (interpreter built on "); + + if (strncmp(build, TOY_VERSION_BUILD, strlen(TOY_VERSION_BUILD)) == 0) { + printf("%s", build); + } + else { + printf(TOY_CC_FONT_YELLOW TOY_CC_BACK_BLACK "%s" TOY_CC_RESET, build); + } + + printf(")\n"); + + //cleanup + free((void*)tb); +} \ No newline at end of file diff --git a/repl/repl_tools.h b/repl/repl_tools.h index 235cef8..5fda23e 100644 --- a/repl/repl_tools.h +++ b/repl/repl_tools.h @@ -12,3 +12,4 @@ void Toy_runBinaryFile(const char* fname); void Toy_runSource(const char* source); void Toy_runSourceFile(const char* fname); +void Toy_parseBinaryFileHeader(const char* fname); \ No newline at end of file diff --git a/source/toy_common.c b/source/toy_common.c index 1898dca..5005500 100644 --- a/source/toy_common.c +++ b/source/toy_common.c @@ -15,6 +15,12 @@ STATIC_ASSERT(sizeof(unsigned char) == 1); STATIC_ASSERT(sizeof(unsigned short) == 2); STATIC_ASSERT(sizeof(unsigned int) == 4); +static const char* build = __DATE__ " " __TIME__; + +const char* Toy_private_version_build() { + return build; +} + #ifndef TOY_DISABLE_REPL //declare the singleton with default values @@ -29,6 +35,7 @@ Toy_CommandLine Toy_commandLine = { .source = NULL, .initialfile = NULL, .enablePrintNewline = true, + .parseBytecodeHeader = false, .verbose = false }; @@ -89,6 +96,16 @@ void Toy_initCommandLine(int argc, const char* argv[]) { continue; } + if (!strcmp(argv[i], "-p")) { + Toy_commandLine.parseBytecodeHeader = true; + + if (Toy_commandLine.binaryfile) { + Toy_commandLine.error = false; + } + + continue; + } + if (!strcmp(argv[i], "-n")) { Toy_commandLine.enablePrintNewline = false; Toy_commandLine.error = false; @@ -124,6 +141,7 @@ void Toy_helpCommandLine(int argc, const char* argv[]) { printf(" -c, --compile filename\tParse and compile the specified source file into an output file.\n"); printf(" -o, --output outfile\t\tName of the output file built with --compile (default: out.tb).\n"); printf(" -t, --initial filename\tStart the repl as normal, after first running the given file.\n"); + printf(" -p\t\t\t\tParse the given bytecode's header, then exit (requires file.tb).\n"); printf(" -n\t\t\t\tDisable the newline character at the end of the print statement.\n"); } diff --git a/source/toy_common.h b/source/toy_common.h index 1e3cb1d..7cabfbe 100644 --- a/source/toy_common.h +++ b/source/toy_common.h @@ -6,8 +6,10 @@ #define TOY_VERSION_MAJOR 1 #define TOY_VERSION_MINOR 1 -#define TOY_VERSION_PATCH 4 -#define TOY_VERSION_BUILD __DATE__ " " __TIME__ +#define TOY_VERSION_PATCH 5 +#define TOY_VERSION_BUILD Toy_private_version_build() + +const char* Toy_private_version_build(); //platform/compiler-specific instructions #if defined(__linux__) || defined(__MINGW32__) || defined(__GNUC__) @@ -42,6 +44,7 @@ typedef struct { char* source; char* initialfile; bool enablePrintNewline; + bool parseBytecodeHeader; bool verbose; } Toy_CommandLine;