diff --git a/scripts/example.toy b/scripts/example.toy index 6e7ba23..2556c03 100644 --- a/scripts/example.toy +++ b/scripts/example.toy @@ -27,3 +27,10 @@ print "Back to the outer scope."; assert true, "This won't be seen"; assert false, "This is an error"; + + + + + +//var arr : [int] = [1, 2, 3, 42]; +//var dict : [string, int] = ["hello": 1, "world":2]; diff --git a/source/common.c b/source/common.c index 3a2a23b..f002b9d 100644 --- a/source/common.c +++ b/source/common.c @@ -20,78 +20,90 @@ void initCommand(int argc, const char* argv[]) { command.optimize = 1; for (int i = 1; i < argc; i++) { //start at 1 to skip the program name + command.error = true; //error state by default, set to false by successful flags + if (!strcmp(argv[i], "-h") || !strcmp(argv[i], "--help")) { command.help = true; + command.error = false; continue; } if (!strcmp(argv[i], "-v") || !strcmp(argv[i], "--version")) { command.version = true; + command.error = false; continue; } - //binary file check at the end + if (!strcmp(argv[i], "-d") || !strcmp(argv[i], "--debug")) { + command.verbose = true; + command.error = false; + continue; + } + + if (!strncmp(argv[i], "-O", 2)) { + sscanf(argv[i], "-O%d", &command.optimize); + command.error = false; + continue; + } 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++; + command.error = false; continue; } if ((!strcmp(argv[i], "-i") || !strcmp(argv[i], "--input")) && i + 1 < argc) { command.source = (char*)argv[i + 1]; i++; + command.error = false; continue; } - if (!strcmp(argv[i], "-d") || !strcmp(argv[i], "--debug")) { - command.verbose = true; + if ((!strcmp(argv[i], "-c") || !strcmp(argv[i], "--compile")) && i + 1 < argc) { + command.compilefile = (char*)argv[i + 1]; + i++; + command.error = false; continue; } - if (!strncmp(argv[i], "-O", 2)) { - sscanf(argv[i], "-O%d", &command.optimize); + if ((!strcmp(argv[i], "-o") || !strcmp(argv[i], "--output")) && i + 1 < argc) { + command.outfile = (char*)argv[i + 1]; + i++; + command.error = false; continue; } - //option without a flag = binary input + //option without a flag + ending in .tb = binary input if (i < argc) { - command.binaryfile = (char*)argv[i]; - continue; + if (strncmp(&(argv[i][strlen(argv[i]) - 3]), ".tb", 3) == 0) { + command.binaryfile = (char*)argv[i]; + command.error = false; + continue; + } } - command.error = true; + //don't keep reading in an error state + return; } } void usageCommand(int argc, const char* argv[]) { - printf("Usage: %s [ | -h | -v | [-OX][-d][-f file | -i source | -c file [-o outfile]]]\n\n", argv[0]); + printf("Usage: %s [ | -h | -v | [-d][-OX][-f file | -i source | -c file [-o outfile]]]\n\n", argv[0]); } void helpCommand(int argc, const char* argv[]) { usageCommand(argc, argv); - 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("\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"); + printf("-f\t| --file filename\tParse, compile and execute the source file.\n\n"); + printf("-i\t| --input source\tParse, compile and execute this given string of source code.\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"); } void copyrightCommand(int argc, const char* argv[]) { diff --git a/source/console_colors.h b/source/console_colors.h new file mode 100644 index 0000000..42d1f19 --- /dev/null +++ b/source/console_colors.h @@ -0,0 +1,30 @@ +#pragma once + +//NOTE: you need both font AND background for these to work + +//fonts color +#define FONT_BLACK "\033[30;" +#define FONT_RED "\033[31;" +#define FONT_GREEN "\033[32;" +#define FONT_YELLOW "\033[33;" +#define FONT_BLUE "\033[34;" +#define FONT_PURPLE "\033[35;" +#define FONT_DGREEN "\033[6;" +#define FONT_WHITE "\033[7;" +#define FONT_CYAN "\x1b[36m" + +//background color +#define BACK_BLACK "40m" +#define BACK_RED "41m" +#define BACK_GREEN "42m" +#define BACK_YELLOW "43m" +#define BACK_BLUE "44m" +#define BACK_PURPLE "45m" +#define BACK_DGREEN "46m" +#define BACK_WHITE "47m" + +//useful +#define NOTICE FONT_GREEN BACK_BLACK +#define WARN FONT_YELLOW BACK_BLACK +#define ERROR FONT_RED BACK_BLACK +#define RESET "\033[0m" \ No newline at end of file diff --git a/source/interpreter.c b/source/interpreter.c index 37fb6ad..1bd3042 100644 --- a/source/interpreter.c +++ b/source/interpreter.c @@ -1,4 +1,5 @@ #include "interpreter.h" +#include "console_colors.h" #include "common.h" #include "memory.h" @@ -310,17 +311,15 @@ void runInterpreter(Interpreter* interpreter) { const unsigned char minor = readByte(interpreter->bytecode, &interpreter->count); const unsigned char patch = readByte(interpreter->bytecode, &interpreter->count); - if (command.verbose) { - if (major != TOY_VERSION_MAJOR || minor != TOY_VERSION_MINOR || patch != TOY_VERSION_PATCH) { - printf("Warning: interpreter/bytecode version mismatch\n"); - } + if (major != TOY_VERSION_MAJOR || minor != TOY_VERSION_MINOR || patch != TOY_VERSION_PATCH) { + printf(ERROR "Error: interpreter/bytecode version mismatch\n" RESET); } const char* build = readString(interpreter->bytecode, &interpreter->count); if (command.verbose) { if (strncmp(build, TOY_VERSION_BUILD, strlen(TOY_VERSION_BUILD))) { - printf("Warning: interpreter/bytecode build mismatch\n"); + printf(WARN "Warning: interpreter/bytecode build mismatch\n" RESET); } } @@ -330,7 +329,7 @@ void runInterpreter(Interpreter* interpreter) { const short literalCount = readShort(interpreter->bytecode, &interpreter->count); if (command.verbose) { - printf("Reading %d literals\n", literalCount); + printf(NOTICE "Reading %d literals\n" RESET, literalCount); } for (int i = 0; i < literalCount; i++) { @@ -393,7 +392,7 @@ void runInterpreter(Interpreter* interpreter) { //code section if (command.verbose) { - printf("executing bytecode\n"); + printf(NOTICE "executing bytecode\n" RESET); } execInterpreter(interpreter); diff --git a/source/lexer.c b/source/lexer.c index 38c4f54..5dd6e62 100644 --- a/source/lexer.c +++ b/source/lexer.c @@ -1,8 +1,10 @@ #include "lexer.h" +#include "console_colors.h" #include "keyword_types.h" #include #include +#include //static generic utility functions static void cleanLexer(Lexer* lexer) { @@ -122,6 +124,7 @@ static Token makeToken(Lexer* lexer, TokenType type) { token.length = 1; token.line = lexer->line; + //BUG #10: this shows TOKEN_EOF twice due to the overarching structure of the program - can't be fixed if (command.verbose) { printf("tok:"); printToken(&token); @@ -297,9 +300,15 @@ Token scanLexer(Lexer* lexer) { } } +static void trim(char** s, int* l) { //all this to remove a newline? + *l = strlen(*s); + while( isspace(( (*((unsigned char**)(s)))[(*l) - 1] )) ) (*l)--; + while(**s && isspace( **(unsigned char**)(s)) ) { (*s)++; (*l)--; } +} + void printToken(Token* token) { if (token->type == TOKEN_ERROR) { - printf("Error\t%d\t%.*s\n", token->line, token->length, token->lexeme); + printf(ERROR "Error\t%d\t%.*s\n" RESET, token->line, token->length, token->lexeme); return; } @@ -313,7 +322,10 @@ void printToken(Token* token) { if (keyword != NULL) { printf("%s", keyword); } else { - printf("-"); + char* str = token->lexeme; + int length = 0; + trim(&str, &length); + printf("%.*s", length, token->lexeme); } } diff --git a/source/repl_main.c b/source/repl_main.c index 5510305..29142c3 100644 --- a/source/repl_main.c +++ b/source/repl_main.c @@ -1,4 +1,5 @@ #include "debug.h" +#include "console_colors.h" #include "lexer.h" #include "parser.h" @@ -189,17 +190,6 @@ void repl() { freeInterpreter(&interpreter); } -void debug() { - LiteralDictionary dictionary; - - initLiteralDictionary(&dictionary); - - setLiteralDictionary(&dictionary, TO_IDENTIFIER_LITERAL("variable", MASK_INTEGER), TO_INTEGER_LITERAL(2)); - printLiteral( getLiteralDictionary(&dictionary, TO_IDENTIFIER_LITERAL("variable", MASK_INTEGER)) ); - - freeLiteralDictionary(&dictionary); -} - //entry point int main(int argc, const char* argv[]) { initCommand(argc, argv); @@ -220,15 +210,9 @@ int main(int argc, const char* argv[]) { return 0; } - //print this until the interpreter meets the specification + //TODO: remove this when the interpreter meets the specification if (command.verbose) { - 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); - } - - //run binary - if (command.binaryfile) { - runBinaryFile(command.binaryfile); - return 0; + printf(WARN "Warning! This interpreter is a work in progress, it does not yet meet the %d.%d.%d specification.\n" RESET, TOY_VERSION_MAJOR, TOY_VERSION_MINOR, TOY_VERSION_PATCH); } //run source file @@ -237,22 +221,30 @@ int main(int argc, const char* argv[]) { 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) { runSource(command.source); return 0; } - // debug(); + //compile source file + if (command.compilefile && command.outfile) { + size_t size = 0; + char* source = readFile(command.compilefile, &size); + unsigned char* tb = compileString(source, &size); + if (!tb) { + return 1; + } + writeFile(command.outfile, tb, size); + return 0; + } + + //run binary + if (command.binaryfile) { + runBinaryFile(command.binaryfile); + return 0; + } + repl(); return 0;