Added header-only parsing to the repl, read more

Also:

* Ensured TOY_VERSION_BUILD is consistent throughout the whole build
* Updated README.md
This commit is contained in:
2023-06-07 23:55:30 +10:00
parent cdb2613e5d
commit 763581c73b
6 changed files with 94 additions and 7 deletions

View File

@@ -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.

View File

@@ -193,8 +193,14 @@ int main(int argc, const char* argv[]) {
return -1;
}
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();

View File

@@ -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);
}

View File

@@ -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);

View File

@@ -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");
}

View File

@@ -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;