Add useful error handler
This commit is contained in:
parent
09af190aa9
commit
70ae06af44
|
@ -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);
|
84
src/Errors.c
Normal file
84
src/Errors.c
Normal 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);
|
||||
}
|
||||
|
||||
|
||||
}
|
16
src/Lexer.c
16
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':
|
||||
|
|
Loading…
Reference in New Issue
Block a user