diff --git a/include/Defs.h b/include/Defs.h index 3c49dec..28248a5 100644 --- a/include/Defs.h +++ b/include/Defs.h @@ -68,6 +68,7 @@ enum TokenTypes { LI_INT, // Integer literal LI_STR, // String literal LI_SEMIC, // ; + LI_COLON, // : LI_LBRAC, // { LI_RBRAC, // } @@ -93,6 +94,10 @@ enum TokenTypes { KW_BREAK, // "break" keyword KW_CONTINUE, // "continue" keyword + KW_SWITCH, // "switch" keyword + KW_DEFAULT, // "default" keyword + KW_CASE, // "case" keyword + KW_PRINT, KW_IF, KW_ELSE, @@ -180,6 +185,10 @@ enum SyntaxOps { OP_FUNC = 40, // Define a function OP_BREAK, // Break out of the loop OP_CONTINUE, // Continue the loop + + OP_SWITCH, // Switch statement + OP_DEFAULT, // Default case + OP_CASE = 45 // Case }; @@ -269,14 +278,14 @@ struct FileData { // The filename of the assembled object code char* ObjectName; - // The full contents of the source file - char* Content; // The line of the file we are currently working on, -1 if it is finished long CurrentLine; // The column of the file we are currently working on, -1 if it is finished long CurrentColumn; // The depth of the loop currently being parsed. long CurrentLoopDepth; + // The column that was last marked as "valid", the start of the error block if something goes wrong. + long CurrentSafeColumn; // The symbol currently being lexed - TokenTypes index and integer value. struct Token CurrentSymbol; @@ -508,6 +517,10 @@ void DieChar(char* Error, int Char); void DieBinary(char* Error, int Number); +void ErrorReport(char* message, ...); + +void Safe(); + /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * C O D E G E N E R A T I O N * * * * @@ -571,6 +584,8 @@ struct AssemblerVtable { // Loops and jumps int (*AsIf)(struct ASTNode*, int, int); int (*AsWhile)(struct ASTNode*); + int (*AsSwitch)(struct ASTNode*); + int (*AsSwitchTable)(int, int, int, int*, int*, int); int (*NewLabel)(); void (*AsJmp)(int); void (*AsLabel)(int); @@ -619,5 +634,7 @@ struct ASTNode* WhileStatement(); struct ASTNode* ForStatement(); +struct ASTNode* SwitchStatement(); + void DumpTree(struct ASTNode* node, int level); \ No newline at end of file diff --git a/src/Errors.c b/src/Errors.c new file mode 100644 index 0000000..cdde91e --- /dev/null +++ b/src/Errors.c @@ -0,0 +1,84 @@ +/*************/ +/*GEMWIRE */ +/* ERYTHRO*/ +/*************/ +#include +#include +#include +#include + +void Safe() { + CurrentFile->CurrentSafeColumn = CurrentFile->CurrentColumn; +} + +void printLine(FILE* file, int ln) { + char buffer[256]; + fgets(buffer, 256, file); + // Line number + printf("%03d|%s", ln + 1, buffer); +} + +void printErrorLine(FILE* file, int ln) { + char firstBuffer[256], problemBuffer[256], tailBuffer[256]; + if (CurrentFile->CurrentSafeColumn != 0) + fgets(firstBuffer, CurrentFile->CurrentSafeColumn, file); + fgets(problemBuffer, (CurrentFile->CurrentColumn > CurrentFile->CurrentSafeColumn ? CurrentFile->CurrentColumn - CurrentFile->CurrentSafeColumn : CurrentFile->CurrentSafeColumn), file); + if (CurrentFile->CurrentColumn > CurrentFile->CurrentSafeColumn) + fgets(tailBuffer, 256, file); + // Line number + printf("%03d|%s\033[0;31m%s\033[0m%s", ln + 1, firstBuffer, problemBuffer, tailBuffer); +} + +void printHelpLine(int line, char* message) { + printf(" | %s", message); +} + +void ErrorReport(char* message, ...) { + char strbuf[256]; + + // Resolve varargs to a string + va_list args; + va_start(args, message); + vsprintf(strbuf, message, args); + va_end(args); + + int line = CurrentFile->CurrentLine - 1; + FILE* file = fopen(CurrentFile->SourceName, "r"); + + int errorOnLastLine = CurrentFile->CurrentColumn == 0; + + // Print context for the error - up to 2 lines above the error + if (line < 3) { + // If we're at 0 or 1, we need to be careful to not try to print -1 for example. + for (int i = 0; i < line; i++) + printLine(file, i); + } else { + // Skip to line - 2 + char buffer[256]; + int count = 0; + while (count < line - (errorOnLastLine ? 3 : 2)) { + fgets(buffer, 256, file); + count++; + } + + if (errorOnLastLine) + printLine(file, line - 3); + + printLine(file, line - 2); + if (!errorOnLastLine) printLine(file, line - 1); + } + + if (errorOnLastLine) { + printErrorLine(file, line - 1); + printHelpLine(line, strbuf); + printLine(file, line); + printLine(file, line + 1); + } else { + printErrorLine(file, line); + printHelpLine(line, strbuf); + printLine(file, line + 1); + printLine(file, line + 2); + } + + +} diff --git a/src/Lexer.c b/src/Lexer.c index ef3cf7d..7b5e076 100644 --- a/src/Lexer.c +++ b/src/Lexer.c @@ -45,8 +45,12 @@ static int NextChar(void) { Char = fgetc(CurrentFile->Stream); - if (Char == '\n') + CurrentFile->CurrentColumn++; + + if (Char == '\n') { CurrentFile->CurrentLine++; + CurrentFile->CurrentColumn = 0; + } return Char; } @@ -94,7 +98,7 @@ void VerifyToken(int Type, char* TokenExpected) { if (CurrentFile->CurrentSymbol.type == Type) Tokenise(); else { - printf("Expected %s on line %ld\n", TokenExpected, CurrentFile->CurrentLine); + ErrorReport("Expected %s, but got %s instead.\n", TokenExpected, TokenNames[CurrentFile->CurrentSymbol.type]); exit(1); } } @@ -298,9 +302,15 @@ static int ReadKeyword(char* Str) { return TY_CHAR; if (!strcmp(Str, "continue")) return KW_CONTINUE; + if (!strcmp(Str, "case")) + return KW_CASE; break; + case 'd': + if (!strcmp(Str, "default")) + return KW_DEFAULT; + case 'e': if (!strcmp(Str, "else")) return KW_ELSE; @@ -354,6 +364,8 @@ static int ReadKeyword(char* Str) { case 's': if (!strcmp(Str, "struct")) return KW_STRUCT; + if (!strcmp(Str, "switch")) + return KW_SWITCH; break; case 'u':