better error reporting

This commit is contained in:
mrexodia 2016-06-05 15:46:44 +02:00
parent 382da6b367
commit 9dfa58daef
No known key found for this signature in database
GPG Key ID: D72F9A4FAA0073B4
2 changed files with 31 additions and 13 deletions

View File

@ -60,11 +60,13 @@ struct Lexer
//lexer state //lexer state
string IdentifierStr; string IdentifierStr;
uint64_t NumberVal = 0; uint64_t NumberVal = 0;
bool IsHexNumberVal = false;
string StringLit; string StringLit;
string NumStr; string NumStr;
char CharLit = '\0'; char CharLit = '\0';
int LastChar = ' '; int LastChar = ' ';
int CurLine = 0; int CurLine = 0;
int LineIndex = 0;
static void clearReserve(string & str, size_t reserve = DEFAULT_STRING_BUFFER) static void clearReserve(string & str, size_t reserve = DEFAULT_STRING_BUFFER)
{ {
@ -87,11 +89,13 @@ struct Lexer
Warnings.clear(); Warnings.clear();
clearReserve(IdentifierStr); clearReserve(IdentifierStr);
NumberVal = 0; NumberVal = 0;
IsHexNumberVal = false;
clearReserve(StringLit); clearReserve(StringLit);
clearReserve(NumStr, 16); clearReserve(NumStr, 16);
CharLit = '\0'; CharLit = '\0';
LastChar = ' '; LastChar = ' ';
CurLine = 0; CurLine = 0;
LineIndex = 0;
} }
unordered_map<string, Token> KeywordMap; unordered_map<string, Token> KeywordMap;
@ -146,15 +150,15 @@ struct Lexer
switch (Token(tok)) switch (Token(tok))
{ {
case tok_eof: return "tok_eof"; case tok_eof: return "tok_eof";
case tok_error: return StringUtils::sprintf("error(\"%s\")", Error.c_str()); case tok_error: return StringUtils::sprintf("error(line %d, col %d, \"%s\")", CurLine + 1, LineIndex, Error.c_str());
case tok_identifier: return StringUtils::sprintf("id(\"%s\")", IdentifierStr.c_str()); case tok_identifier: return IdentifierStr.c_str();
case tok_number: return StringUtils::sprintf("num(%llu, 0x%llX)", NumberVal, NumberVal); case tok_number: return StringUtils::sprintf(IsHexNumberVal ? "0x%llX" : "%llu", NumberVal);
case tok_stringlit: return StringUtils::sprintf("\"%s\"", StringUtils::Escape(StringLit).c_str()); case tok_stringlit: return StringUtils::sprintf("\"%s\"", StringUtils::Escape(StringLit).c_str());
case tok_charlit: case tok_charlit:
{ {
String s; String s;
s = CharLit; s = CharLit;
return StringUtils::sprintf("\'%s\'", StringUtils::Escape(s).c_str()); return StringUtils::sprintf("'%s'", StringUtils::Escape(s).c_str());
} }
default: default:
{ {
@ -184,6 +188,7 @@ struct Lexer
if (Index == Input.size()) if (Index == Input.size())
return EOF; return EOF;
auto ch = Input[Index++]; auto ch = Input[Index++];
LineIndex++;
if (ch == '\0') if (ch == '\0')
{ {
ReportWarning(StringUtils::sprintf("\\0 character in file data")); ReportWarning(StringUtils::sprintf("\\0 character in file data"));
@ -211,6 +216,12 @@ struct Lexer
return LastChar = ReadChar(); return LastChar = ReadChar();
} }
void SignalNextLine()
{
CurLine++;
LineIndex = 0;
}
static const char* ConvertNumber(const char* str, uint64_t & result, int radix) static const char* ConvertNumber(const char* str, uint64_t & result, int radix)
{ {
errno = 0; errno = 0;
@ -231,7 +242,7 @@ struct Lexer
while (isspace(LastChar)) while (isspace(LastChar))
{ {
if (LastChar == '\n') if (LastChar == '\n')
CurLine++; SignalNextLine();
NextChar(); NextChar();
} }
@ -255,6 +266,9 @@ struct Lexer
return ReportError("unexpected newline in character literal (1)"); return ReportError("unexpected newline in character literal (1)");
if (LastChar == '\'') //end of character literal if (LastChar == '\'') //end of character literal
{ {
if (charLit.length() != 1)
return ReportError(StringUtils::sprintf("invalid character literal '%s'", charLit.c_str()));
CharLit = charLit[0];
NextChar(); NextChar();
return tok_charlit; return tok_charlit;
} }
@ -396,7 +410,7 @@ struct Lexer
//hex numbers //hex numbers
if (LastChar == '0' && PeekChar() == 'x') //0x if (LastChar == '0' && PeekChar() == 'x') //0x
{ {
ReadChar(); //consume the 'x' NextChar(); //consume the 'x'
NumStr.clear(); NumStr.clear();
while (isxdigit(NextChar())) //[0-9a-fA-F]* while (isxdigit(NextChar())) //[0-9a-fA-F]*
@ -408,6 +422,7 @@ struct Lexer
auto error = ConvertNumber(NumStr.c_str(), NumberVal, 16); auto error = ConvertNumber(NumStr.c_str(), NumberVal, 16);
if (error) if (error)
return ReportError(StringUtils::sprintf("ConvertNumber failed (%s) on hexadecimal number", error)); return ReportError(StringUtils::sprintf("ConvertNumber failed (%s) on hexadecimal number", error));
IsHexNumberVal = true;
return tok_number; return tok_number;
} }
if (isdigit(LastChar)) //[0-9] if (isdigit(LastChar)) //[0-9]
@ -420,6 +435,7 @@ struct Lexer
auto error = ConvertNumber(NumStr.c_str(), NumberVal, 10); auto error = ConvertNumber(NumStr.c_str(), NumberVal, 10);
if (error) if (error)
return ReportError(StringUtils::sprintf("ConvertNumber failed (%s) on decimal number", error)); return ReportError(StringUtils::sprintf("ConvertNumber failed (%s) on decimal number", error));
IsHexNumberVal = false;
return tok_number; return tok_number;
} }
@ -428,25 +444,27 @@ struct Lexer
{ {
do do
{ {
NextChar();
if (LastChar == '\n') if (LastChar == '\n')
CurLine++; SignalNextLine();
NextChar();
} while (!(LastChar == EOF || LastChar == '\n')); } while (!(LastChar == EOF || LastChar == '\n'));
NextChar();
return GetToken(); //interpret the next line return GetToken(); //interpret the next line
} }
if (LastChar == '/' && PeekChar() == '*') //block comment if (LastChar == '/' && PeekChar() == '*') //block comment
{ {
do do
{ {
NextChar();
if (LastChar == '\n') if (LastChar == '\n')
CurLine++; SignalNextLine();
NextChar();
} while (!(LastChar == EOF || LastChar == '*' && PeekChar() == '/')); } while (!(LastChar == EOF || LastChar == '*' && PeekChar() == '/'));
if (LastChar == EOF) //unexpected end of file if (LastChar == EOF) //unexpected end of file
{
LineIndex++;
return ReportError("unexpected end of file in block comment"); return ReportError("unexpected end of file in block comment");
}
NextChar(); NextChar();
NextChar(); NextChar();

View File

@ -40,8 +40,8 @@ DEF_OP_SINGLE(subopen, '[')
DEF_OP_SINGLE(subclose, ']') DEF_OP_SINGLE(subclose, ']')
DEF_OP_SINGLE(member, '.') DEF_OP_SINGLE(member, '.')
DEF_OP_SINGLE(comma, ',') DEF_OP_SINGLE(comma, ',')
DEF_OP_SINGLE(tenary1, '?') DEF_OP_SINGLE(tenary, '?')
DEF_OP_SINGLE(tenary2, ':') DEF_OP_SINGLE(colon, ':')
DEF_OP_SINGLE(assign, '=') DEF_OP_SINGLE(assign, '=')
DEF_OP_SINGLE(semic, ';') DEF_OP_SINGLE(semic, ';')