diff --git a/.gitignore b/.gitignore index d0908d9..d554959 100644 --- a/.gitignore +++ b/.gitignore @@ -22,6 +22,7 @@ out/ *.log out *.stackdump +*.tb #Shell files *.bat diff --git a/source/common.c b/source/common.c index f01d437..3a2a23b 100644 --- a/source/common.c +++ b/source/common.c @@ -11,7 +11,10 @@ void initCommand(int argc, const char* argv[]) { command.error = false; command.help = false; command.version = false; - command.filename = NULL; + command.binaryfile = NULL; + command.sourcefile = NULL; + command.compilefile = NULL; + command.outfile = "out.tb"; command.source = NULL; command.verbose = false; command.optimize = 1; @@ -27,8 +30,22 @@ void initCommand(int argc, const char* argv[]) { continue; } - if ((!strcmp(argv[i], "-f") || !strcmp(argv[i], "--file")) && i + 1 < argc) { - command.filename = (char*)argv[i + 1]; + //binary file check at the end + + if ((!strcmp(argv[i], "-f") || !strcmp(argv[i], "--sourcefile")) && i + 1 < argc) { + command.sourcefile = (char*)argv[i + 1]; + i++; + continue; + } + + if ((!strcmp(argv[i], "-c") || !strcmp(argv[i], "--compile")) && i + 1 < argc) { + command.compilefile = (char*)argv[i + 1]; + i++; + continue; + } + + if ((!strcmp(argv[i], "-o") || !strcmp(argv[i], "--output")) && i + 1 < argc) { + command.outfile = (char*)argv[i + 1]; i++; continue; } @@ -49,23 +66,32 @@ void initCommand(int argc, const char* argv[]) { continue; } + //option without a flag = binary input + if (i < argc) { + command.binaryfile = (char*)argv[i]; + continue; + } + command.error = true; } } void usageCommand(int argc, const char* argv[]) { - printf("Usage: %s [-h | -v | [-OX][-d][-f filename | -i source]]\n\n", argv[0]); + printf("Usage: %s [ | -h | -v | [-OX][-d][-f file | -i source | -c file [-o outfile]]]\n\n", argv[0]); } void helpCommand(int argc, const char* argv[]) { usageCommand(argc, argv); - printf("-h | --help\t\tShow this help then exit.\n"); - printf("-v | --version\t\tShow version and copyright information then exit.\n"); - printf("-f | --file filename\tParse and execute the source file.\n"); - printf("-i | --input source\tParse and execute this given string of source code.\n"); - printf("-d | --debug\t\tBe verbose when operating.\n"); - printf("-OX\t\t\tUse level X optimization (default 1)\n"); + printf("\t\t\tBinary input file in tb format, must be version %d.%d.%d.\n\n", TOY_VERSION_MAJOR, TOY_VERSION_MINOR, TOY_VERSION_PATCH); + printf("-h\t| --help\t\tShow this help then exit.\n\n"); + printf("-v\t| --version\t\tShow version and copyright information then exit.\n\n"); + printf("-f\t| --file filename\tParse, compile and execute the source file.\n\n"); + printf("-c\t| --compile filename\tParse and compile the specified source file into an output file.\n\n"); + printf("-o\t| --output filename\tName of the file compiled with --compile (default: out.tb).\n\n"); + printf("-i\t| --input source\tParse, compile and execute this given string of source code.\n\n"); + printf("-d\t| --debug\t\tBe verbose when operating.\n\n"); + printf("-OX\t\t\t\tUse level X optimization (default 1)\n\n"); } void copyrightCommand(int argc, const char* argv[]) { diff --git a/source/common.h b/source/common.h index c416fd3..13b6481 100644 --- a/source/common.h +++ b/source/common.h @@ -14,7 +14,10 @@ typedef struct { bool error; bool help; bool version; - char* filename; + char* binaryfile; + char* sourcefile; + char* compilefile; + char* outfile; //defaults to out.tb char* source; bool verbose; int optimize; diff --git a/source/debug.c b/source/debug.c index 3999550..6f53c0f 100644 --- a/source/debug.c +++ b/source/debug.c @@ -8,55 +8,55 @@ #include //utils -static unsigned char printByte(const char* tb, int* count) { +static unsigned char printByte(unsigned char* tb, int* count) { unsigned char ret = *(unsigned char*)(tb + *count); printf("%u ", ret); *count += 1; return ret; } -static unsigned short printShort(const char* tb, int* count) { +static unsigned short printShort(unsigned char* tb, int* count) { unsigned short ret = *(unsigned short*)(tb + *count); printf("%d ", ret); *count += 2; return ret; } -static int printInt(const char* tb, int* count) { +static int printInt(unsigned char* tb, int* count) { int ret = *(int*)(tb + *count); printf("%d ", ret); *count += 4; return ret; } -static float printFloat(const char* tb, int* count) { +static float printFloat(unsigned char* tb, int* count) { float ret = *(float*)(tb + *count); printf("%f ", ret); *count += 4; return ret; } -static const char* printString(const char* tb, int* count) { - const char* ret = tb + *count; - *count += printf("%s ", ret); //return includes the space, but not the null terminator +static unsigned char* printString(unsigned char* tb, int* count) { + unsigned char* ret = tb + *count; + *count += printf("%s ", (char*)ret); //return includes the space, but not the null terminator return ret; } -static void consumeByte(unsigned char byte, const char* str, int* count) { +static void consumeByte(unsigned char byte, unsigned char* str, int* count) { if (byte != str[*count]) { printf("Failed to consume the correct byte"); } *count += 1; } -static void consumeShort(unsigned short bytes, const char* str, int* count) { +static void consumeShort(unsigned short bytes, unsigned char* str, int* count) { if (bytes != *(unsigned short*)(str + *count)) { printf("Failed to consume the correct bytes"); } *count += 2; } -void dissectBytecode(const char* tb, int size) { +void dissectBytecode(unsigned char* tb, int size) { int count = 0; //header @@ -101,7 +101,7 @@ void dissectBytecode(const char* tb, int size) { break; case LITERAL_STRING: { - const char* s = printString(tb, &count); + const unsigned char* s = printString(tb, &count); printf("(string)"); } break; @@ -118,31 +118,60 @@ void dissectBytecode(const char* tb, int size) { const unsigned char opcode = printByte(tb, &count); switch (opcode) { + case OP_ASSERT: + printf("assert\n"); + break; + case OP_PRINT: printf("print\n"); break; - case OP_LITERAL: { + case OP_LITERAL: printf("literal "); printByte(tb, &count); printf("\n"); - } break; - case OP_LITERAL_LONG: { + case OP_LITERAL_LONG: printf("long literal "); printShort(tb, &count); printf("\n"); - } break; - case OP_NEGATE: { + case OP_NEGATE: printf("negate\n"); - } + break; + + case OP_ADDITION: + printf("+\n"); + break; + + case OP_SUBTRACTION: + printf("-\n"); + break; + + case OP_MULTIPLICATION: + printf("*\n"); + break; + + case OP_DIVISION: + printf("/\n"); + break; + + case OP_MODULO: + printf("%%\n"); + break; + + case OP_GROUPING_BEGIN: + printf("(\n"); + break; + + case OP_GROUPING_END: + printf(")\n"); break; case OP_SECTION_END: { - printf("--SECTION END--"); + printf("--SECTION END--\n"); } break; diff --git a/source/debug.h b/source/debug.h index a797554..a80e4b2 100644 --- a/source/debug.h +++ b/source/debug.h @@ -2,4 +2,4 @@ #include "common.h" -void dissectBytecode(const char* tb, int size); \ No newline at end of file +void dissectBytecode(unsigned char* tb, int size); \ No newline at end of file diff --git a/source/repl_main.c b/source/repl_main.c index 135dd03..97f7036 100644 --- a/source/repl_main.c +++ b/source/repl_main.c @@ -11,45 +11,60 @@ #include #include -//read a file and return it as a char array -char* readFile(char* path) { +//IO functions +char* readFile(char* path, size_t* fileSize) { FILE* file = fopen(path, "rb"); if (file == NULL) { fprintf(stderr, "Could not open file \"%s\"\n", path); - exit(74); + exit(-1); } fseek(file, 0L, SEEK_END); - size_t fileSize = ftell(file); + *fileSize = ftell(file); rewind(file); - char* buffer = (char*)malloc(fileSize + 1); + char* buffer = (char*)malloc(*fileSize); if (buffer == NULL) { fprintf(stderr, "Not enough memory to read \"%s\"\n", path); - exit(74); + exit(-1); } - size_t bytesRead = fread(buffer, sizeof(char), fileSize, file); + size_t bytesRead = fread(buffer, sizeof(char), *fileSize, file); - if (bytesRead < fileSize) { + if (bytesRead < *fileSize) { fprintf(stderr, "Could not read file \"%s\"\n", path); - exit(74); + exit(-1); } fclose(file); - buffer[bytesRead] = '\0'; - return buffer; } -void runString(char* source) { +void writeFile(char* path, unsigned char* bytes, size_t size) { + FILE* file = fopen(path, "wb"); + + if (file == NULL) { + fprintf(stderr, "Could not open file \"%s\"\n", path); + exit(-1); + } + + int written = fwrite(bytes, size, 1, file); + + if (written != 1) { + fprintf(stderr, "Could not write file \"%s\"\n", path); + exit(-1); + } + + fclose(file); +} + +unsigned char* compileString(char* source, size_t* size) { Lexer lexer; Parser parser; Compiler compiler; - Interpreter interpreter; initLexer(&lexer, source); initParser(&parser, &lexer); @@ -63,7 +78,7 @@ void runString(char* source) { freeNode(node); freeCompiler(&compiler); freeParser(&parser); - return; + return NULL; } writeCompiler(&compiler, node); @@ -72,26 +87,46 @@ void runString(char* source) { } //get the bytecode dump - int size = 0; - unsigned char* tb = collateCompiler(&compiler, &size); + unsigned char* tb = collateCompiler(&compiler, (int*)(size)); //cleanup freeCompiler(&compiler); freeParser(&parser); + //no lexer to clean up - //run the bytecode + //finally + return tb; +} + +void runBinary(unsigned char* tb, size_t size) { + Interpreter interpreter; initInterpreter(&interpreter, tb, size); runInterpreter(&interpreter); freeInterpreter(&interpreter); } -void runFile(char* fname) { - char* source = readFile(fname); - runString(source); +void runBinaryFile(char* fname) { + size_t size = 0; //not used + unsigned char* tb = (unsigned char*)readFile(fname, &size); + runBinary(tb, size); + //interpreter takes ownership of the binary data +} + +void runSource(char* source) { + size_t size; + unsigned char* tb = compileString(source, &size); + runBinary(tb, size); +} + +void runSourceFile(char* fname) { + size_t size = 0; //not used + char* source = readFile(fname, &size); + runSource(source); free((void*)source); } void repl() { + //repl does it's own thing for now bool error = false; const int size = 2048; @@ -205,13 +240,30 @@ int main(int argc, const char* argv[]) { printf("Warning! This interpreter is a work in progress, it does not yet meet the %d.%d.%d specification.\n", TOY_VERSION_MAJOR, TOY_VERSION_MINOR, TOY_VERSION_PATCH); } - if (command.filename) { - runFile(command.filename); + //run binary + if (command.binaryfile) { + runBinaryFile(command.binaryfile); return 0; } + //run source file + if (command.sourcefile) { + runSourceFile(command.sourcefile); + return 0; + } + + //compile source file + if (command.compilefile) { + size_t size = 0; + char* source = readFile(command.compilefile, &size); + unsigned char* tb = compileString(source, &size); + writeFile(command.outfile, tb, size); + return 0; + } + + //run from stdin if (command.source) { - runString(command.source); + runSource(command.source); return 0; }