From 57fb1ece814e301e35bf8fa32e58436f66438343 Mon Sep 17 00:00:00 2001 From: Kayne Ruse Date: Sat, 28 Sep 2024 12:26:42 +1000 Subject: [PATCH] Basic infile reading is working, untested --- repl/main.c | 205 +++++++++++++++++++++++++++++++++++++++++--- repl/makefile | 2 +- scripts/.gitkeep | 0 scripts/example.toy | 1 + source/toy_lexer.c | 4 + source/toy_parser.c | 2 +- 6 files changed, 198 insertions(+), 16 deletions(-) delete mode 100644 scripts/.gitkeep create mode 100644 scripts/example.toy diff --git a/repl/main.c b/repl/main.c index a57adbe..4b2c429 100644 --- a/repl/main.c +++ b/repl/main.c @@ -1,11 +1,89 @@ -#include "toy_memory.h" +#include "toy.h" #include +#include +//handle command line arguments +typedef struct CmdLine { + bool error; + bool help; + bool version; + const char* infile; +} CmdLine; + +void usageCmdLine(int argc, const char* argv[]) { + printf("Usage: %s [ -h | -v | -f source.toy ]\n\n", argv[0]); +} + +void helpCmdLine(int argc, const char* argv[]) { + usageCmdLine(argc, argv); + + printf(" -h, --help\t\t\tShow this help then exit.\n"); + printf(" -v, --version\t\t\tShow version and copyright information then exit.\n"); + printf(" -f, --file infile\t\tParse, compile and execute the source file then exit.\n"); +} + +void versionCmdLine(int argc, const char* argv[]) { + printf("The Toy Programming Language, Version %d.%d.%d %s\n\n", TOY_VERSION_MAJOR, TOY_VERSION_MINOR, TOY_VERSION_PATCH, TOY_VERSION_BUILD); + + //copy/pasted from the license file - there's a way to include it directly, but it's too finnicky to bother + const char* license = "\ +Copyright (c) 2020-2024 Kayne Ruse, KR Game Studios\n\ +\n\ +This software is provided 'as-is', without any express or implied\n\ +warranty. In no event will the authors be held liable for any damages\n\ +arising from the use of this software.\n\ +\n\ +Permission is granted to anyone to use this software for any purpose,\n\ +including commercial applications, and to alter it and redistribute it\n\ +freely, subject to the following restrictions:\n\ +\n\ +1. The origin of this software must not be misrepresented; you must not\n\ + claim that you wrote the original software. If you use this software\n\ + in a product, an acknowledgment in the product documentation would be\n\ + appreciated but is not required.\n\ +2. Altered source versions must be plainly marked as such, and must not be\n\ + misrepresented as being the original software.\n\ +3. This notice may not be removed or altered from any source distribution.\n\n"; + + printf(license); +} + +CmdLine parseCmdLine(int argc, const char* argv[]) { + CmdLine cmd = { .error = false, .help = false, .version = false, .infile = NULL }; + + for (int i = 1; i < argc; i++) { + if (!strcmp(argv[i], "-h") || !strcmp(argv[i], "--help")) { + cmd.help = true; + } + + else if (!strcmp(argv[i], "-v") || !strcmp(argv[i], "--version")) { + cmd.version = true; + } + + else if (!strcmp(argv[i], "-f") || !strcmp(argv[i], "--file")) { + if (argc < i + 1) { + cmd.error = true; + } + else { + cmd.infile = argv[++i]; + } + } + + else { + cmd.error = true; + } + } + + return cmd; +} + +//utilities unsigned char* readFile(const char* path, int* size) { //open the file FILE* file = fopen(path, "rb"); if (file == NULL) { + *size = -1; //missing file error return NULL; } @@ -24,7 +102,7 @@ unsigned char* readFile(const char* path, int* size) { // if (fread(buffer, sizeof(unsigned char), *size, file) < *size) { fclose(file); - *size = -1; //singal a read error + *size = -2; //singal a read error return NULL; } @@ -32,21 +110,120 @@ unsigned char* readFile(const char* path, int* size) { return buffer; } +void dir(char* dest, const char* src) { + //extract the directory from src, and store it in dest + const char* p = strrchr(src, '/'); + int len = p != NULL ? p - src + 1 : 0; + strncpy(dest, src, len); + dest[len] = '\0'; +} -int main(int argc, char* argv[]) { - int size = 0; - unsigned char* buffer = readFile("../repl/main.c", &size); //for now, just grab the main.c file as a test +#define APPEND(dest, src) \ + sprintf(dest + strlen(dest), src) - if (buffer == NULL) { - fprintf(stderr, "Failed to open the file\n"); +//main file +int main(int argc, const char* argv[]) { + CmdLine cmd = parseCmdLine(argc, argv); + + if (cmd.error) { + usageCmdLine(argc, argv); + } + else if (cmd.help) { + helpCmdLine(argc, argv); + } + else if (cmd.version) { + versionCmdLine(argc, argv); + } + else if (cmd.infile != NULL) { + //run the given file + int size; + unsigned char* source = readFile(cmd.infile, &size); + + //check the file + if (source == NULL) { + if (size == 0) { + fprintf(stderr, TOY_CC_ERROR "ERROR: Could not parse an empty file, exiting\n" TOY_CC_RESET); + return -1; + } + + else if (size == -1) { + fprintf(stderr, TOY_CC_ERROR "ERROR: File not found, exiting\n" TOY_CC_RESET); + return -1; + } + + else { + fprintf(stderr, TOY_CC_ERROR "ERROR: Unknown error while reading file, exiting\n" TOY_CC_RESET); + return -1; + } + } + + Toy_Lexer lexer; + Toy_bindLexer(&lexer, (char*)source); + + Toy_Parser parser; + Toy_bindParser(&parser, &lexer); + + Toy_Bucket* bucket = NULL; + TOY_BUCKET_INIT(Toy_Ast, bucket, 32); + Toy_Ast* ast = Toy_scanParser(&bucket, &parser); + + Toy_Bytecode bc = Toy_compileBytecode(ast); + + //run the setup + Toy_VM vm; + Toy_initVM(&vm); + Toy_bindVM(&vm, bc.ptr, bc.capacity); + + //run + Toy_runVM(&vm); + + //debugging result + printf("printing the stack result\n\ntype\tvalue\n"); + for (int i = 0; i < vm.stack.count; i++) { + Toy_Value v = vm.stack.ptr[i]; + + printf(" %d\t ", v.type); + + switch(v.type) { + case TOY_VALUE_NULL: + printf("null"); + break; + + case TOY_VALUE_BOOLEAN: + printf("%s", TOY_VALUE_AS_BOOLEAN(v) ? "true" : "false"); + break; + + case TOY_VALUE_INTEGER: + printf("%d", TOY_VALUE_AS_INTEGER(v)); + break; + + case TOY_VALUE_FLOAT: + printf("%f", TOY_VALUE_AS_FLOAT(v)); + break; + + case TOY_VALUE_STRING: + case TOY_VALUE_ARRAY: + case TOY_VALUE_DICTIONARY: + case TOY_VALUE_FUNCTION: + case TOY_VALUE_OPAQUE: + printf("???"); + break; + } + + printf("\n"); + } + + //cleanup + Toy_freeVM(&vm); + TOY_BUCKET_FREE(bucket); + TOY_FREE_ARRAY(unsigned char, source, size); + } + else { + usageCmdLine(argc, argv); } - if (size < 0) { - fprintf(stderr, "Failed to read the file\n"); - } - - TOY_FREE_ARRAY(unsigned char, buffer, size); - - printf("All good\n"); return 0; } + + +//TODO: simple and consistent way to print an AST and Toy_Value \ No newline at end of file diff --git a/repl/makefile b/repl/makefile index 9f844e9..aeddc98 100644 --- a/repl/makefile +++ b/repl/makefile @@ -2,7 +2,7 @@ CC=gcc CFLAGS+=-g -Wall -Werror -Wno-unused-parameter -Wno-unused-function -Wno-unused-variable LIBS+=-lm -lToy -LDFLAGS+=-Wl,-rpath,'.' +LDFLAGS+=-Wl,-R -Wl,'$$ORIGIN' #directories REPL_ROOTDIR=.. diff --git a/scripts/.gitkeep b/scripts/.gitkeep deleted file mode 100644 index e69de29..0000000 diff --git a/scripts/example.toy b/scripts/example.toy new file mode 100644 index 0000000..82246fc --- /dev/null +++ b/scripts/example.toy @@ -0,0 +1 @@ +(1 + 2) * (3 + 4); \ No newline at end of file diff --git a/source/toy_lexer.c b/source/toy_lexer.c index 2af2006..309df59 100644 --- a/source/toy_lexer.c +++ b/source/toy_lexer.c @@ -236,6 +236,10 @@ void Toy_bindLexer(Toy_Lexer* lexer, const char* source) { } Toy_Token Toy_private_scanLexer(Toy_Lexer* lexer) { + if (lexer->source == NULL) { + return makeErrorToken(lexer, "Missing source code in lexer"); + } + eatWhitespace(lexer); lexer->start = lexer->current; diff --git a/source/toy_parser.c b/source/toy_parser.c index d4efab5..bce779f 100644 --- a/source/toy_parser.c +++ b/source/toy_parser.c @@ -31,7 +31,7 @@ static void advance(Toy_Parser* parser) { parser->current = Toy_private_scanLexer(parser->lexer); if (parser->current.type == TOY_TOKEN_ERROR) { - printError(parser, parser->current, "Read error"); + printError(parser, parser->current, "Can't read the source code"); } }