Add useful error handler

This commit is contained in:
Curle 2023-04-24 02:17:11 +01:00
parent 09af190aa9
commit 70ae06af44
3 changed files with 117 additions and 4 deletions

View File

@ -68,6 +68,7 @@ enum TokenTypes {
LI_INT, // Integer literal LI_INT, // Integer literal
LI_STR, // String literal LI_STR, // String literal
LI_SEMIC, // ; LI_SEMIC, // ;
LI_COLON, // :
LI_LBRAC, // { LI_LBRAC, // {
LI_RBRAC, // } LI_RBRAC, // }
@ -93,6 +94,10 @@ enum TokenTypes {
KW_BREAK, // "break" keyword KW_BREAK, // "break" keyword
KW_CONTINUE, // "continue" keyword KW_CONTINUE, // "continue" keyword
KW_SWITCH, // "switch" keyword
KW_DEFAULT, // "default" keyword
KW_CASE, // "case" keyword
KW_PRINT, KW_PRINT,
KW_IF, KW_IF,
KW_ELSE, KW_ELSE,
@ -180,6 +185,10 @@ enum SyntaxOps {
OP_FUNC = 40, // Define a function OP_FUNC = 40, // Define a function
OP_BREAK, // Break out of the loop OP_BREAK, // Break out of the loop
OP_CONTINUE, // Continue 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 // The filename of the assembled object code
char* ObjectName; 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 // The line of the file we are currently working on, -1 if it is finished
long CurrentLine; long CurrentLine;
// The column of the file we are currently working on, -1 if it is finished // The column of the file we are currently working on, -1 if it is finished
long CurrentColumn; long CurrentColumn;
// The depth of the loop currently being parsed. // The depth of the loop currently being parsed.
long CurrentLoopDepth; 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. // The symbol currently being lexed - TokenTypes index and integer value.
struct Token CurrentSymbol; struct Token CurrentSymbol;
@ -508,6 +517,10 @@ void DieChar(char* Error, int Char);
void DieBinary(char* Error, int Number); 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 * * * * * * * * C O D E G E N E R A T I O N * * * *
@ -571,6 +584,8 @@ struct AssemblerVtable {
// Loops and jumps // Loops and jumps
int (*AsIf)(struct ASTNode*, int, int); int (*AsIf)(struct ASTNode*, int, int);
int (*AsWhile)(struct ASTNode*); int (*AsWhile)(struct ASTNode*);
int (*AsSwitch)(struct ASTNode*);
int (*AsSwitchTable)(int, int, int, int*, int*, int);
int (*NewLabel)(); int (*NewLabel)();
void (*AsJmp)(int); void (*AsJmp)(int);
void (*AsLabel)(int); void (*AsLabel)(int);
@ -619,5 +634,7 @@ struct ASTNode* WhileStatement();
struct ASTNode* ForStatement(); struct ASTNode* ForStatement();
struct ASTNode* SwitchStatement();
void DumpTree(struct ASTNode* node, int level); void DumpTree(struct ASTNode* node, int level);

84
src/Errors.c Normal file
View File

@ -0,0 +1,84 @@
/*************/
/*GEMWIRE */
/* ERYTHRO*/
/*************/
#include <stdio.h>
#include <Defs.h>
#include <Data.h>
#include <stdarg.h>
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);
}
}

View File

@ -45,8 +45,12 @@ static int NextChar(void) {
Char = fgetc(CurrentFile->Stream); Char = fgetc(CurrentFile->Stream);
if (Char == '\n') CurrentFile->CurrentColumn++;
if (Char == '\n') {
CurrentFile->CurrentLine++; CurrentFile->CurrentLine++;
CurrentFile->CurrentColumn = 0;
}
return Char; return Char;
} }
@ -94,7 +98,7 @@ void VerifyToken(int Type, char* TokenExpected) {
if (CurrentFile->CurrentSymbol.type == Type) if (CurrentFile->CurrentSymbol.type == Type)
Tokenise(); Tokenise();
else { 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); exit(1);
} }
} }
@ -298,9 +302,15 @@ static int ReadKeyword(char* Str) {
return TY_CHAR; return TY_CHAR;
if (!strcmp(Str, "continue")) if (!strcmp(Str, "continue"))
return KW_CONTINUE; return KW_CONTINUE;
if (!strcmp(Str, "case"))
return KW_CASE;
break; break;
case 'd':
if (!strcmp(Str, "default"))
return KW_DEFAULT;
case 'e': case 'e':
if (!strcmp(Str, "else")) if (!strcmp(Str, "else"))
return KW_ELSE; return KW_ELSE;
@ -354,6 +364,8 @@ static int ReadKeyword(char* Str) {
case 's': case 's':
if (!strcmp(Str, "struct")) if (!strcmp(Str, "struct"))
return KW_STRUCT; return KW_STRUCT;
if (!strcmp(Str, "switch"))
return KW_SWITCH;
break; break;
case 'u': case 'u':