Improve syntax error reporting

This commit is contained in:
2020-08-28 20:51:02 +02:00
parent 593506a907
commit aebc1dd86d
5 changed files with 80 additions and 45 deletions

11
bin/error.wasm Normal file
View File

@@ -0,0 +1,11 @@
seti %A ';
seti %A ' ';
seti %A '
';
seti %A $a12;
seti %A [];
seti %A [abc];
seti %A [$0a4];
seti %A ];
seti %A [;
seti %A [$5;

View File

@@ -32,17 +32,19 @@ namespace Token
TokenValueType const valueType; TokenValueType const valueType;
bool isValid; bool isValid;
std::variant<OperandType, RegisterType, int, std::string> data; std::variant<OperandType, RegisterType, int, std::string> data;
std::string errorMessage;
Token(Token const & other); Token(Token const & other);
static Token CreateUnknownToken(int const lineNumber, int const lineColumn); static Token CreateEmptyToken(int const lineNumber, int const lineColumn);
static Token CreateErrorToken(std::string const & message, TokenType const type, int const lineNumber, int const lineColumn);
static Token CreateStatementEndToken(int const lineNumber, int const lineColumn); static Token CreateStatementEndToken(int const lineNumber, int const lineColumn);
static Token CreateLabelToken(std::string const & string, bool isValid, int const lineNumber, int const lineColumn); static Token CreateLabelToken(std::string const & string, int const lineNumber, int const lineColumn);
static Token CreateImmediateValueToken(int const value, bool isValid, int const lineNumber, int const lineColumn); static Token CreateImmediateValueToken(int const value, int const lineNumber, int const lineColumn);
static Token CreateRegisterToken(RegisterType const registerType, int const lineNumber, int const lineColumn); static Token CreateRegisterToken(RegisterType const registerType, int const lineNumber, int const lineColumn);
static Token CreateOperandToken(OperandType const operandType, int const lineNumber, int const lineColumn); static Token CreateOperandToken(OperandType const operandType, int const lineNumber, int const lineColumn);
static Token CreateMemoryToken(RegisterType const registerType, int const lineNumber, int const lineColumn); static Token CreateMemoryToken(RegisterType const registerType, int const lineNumber, int const lineColumn);
static Token CreateMemoryToken(int const value, bool isValid, int const lineNumber, int const lineColumn); static Token CreateMemoryToken(int const value, int const lineNumber, int const lineColumn);
void DebugPrint() const; void DebugPrint() const;
}; };

View File

@@ -9,7 +9,8 @@ namespace Token
type(_type), type(_type),
valueType(TokenValueType::None), valueType(TokenValueType::None),
isValid(validness), isValid(validness),
data(0) data(0),
errorMessage()
{ {
} }
@@ -19,7 +20,8 @@ namespace Token
type(_type), type(_type),
valueType(TokenValueType::String), valueType(TokenValueType::String),
isValid(validness), isValid(validness),
data(string) data(string),
errorMessage()
{ {
} }
@@ -29,7 +31,8 @@ namespace Token
type(_type), type(_type),
valueType(TokenValueType::Integer), valueType(TokenValueType::Integer),
isValid(validness), isValid(validness),
data(value) data(value),
errorMessage()
{ {
} }
@@ -39,7 +42,8 @@ namespace Token
type(_type), type(_type),
valueType(TokenValueType::Register), valueType(TokenValueType::Register),
isValid(validness), isValid(validness),
data(registerType) data(registerType),
errorMessage()
{ {
} }
@@ -49,7 +53,8 @@ namespace Token
type(_type), type(_type),
valueType(TokenValueType::Operand), valueType(TokenValueType::Operand),
isValid(validness), isValid(validness),
data(operandType) data(operandType),
errorMessage()
{ {
} }
@@ -59,28 +64,36 @@ namespace Token
type(other.type), type(other.type),
valueType(other.valueType), valueType(other.valueType),
isValid(other.isValid), isValid(other.isValid),
data(other.data) data(other.data),
errorMessage(other.errorMessage)
{ {
} }
Token Token::CreateUnknownToken(int const lineNumber, int const lineColumn) Token Token::CreateEmptyToken(int const lineNumber, int const lineColumn)
{ {
return Token(TokenType::Unknown, false, lineNumber, lineColumn); return Token(TokenType::Unknown, false, lineNumber, lineColumn);
} }
Token Token::CreateErrorToken(std::string const & message, TokenType const type, int const lineNumber, int const lineColumn)
{
Token token(type, false, lineNumber, lineColumn);
token.errorMessage = message;
return token;
}
Token Token::CreateStatementEndToken(int const lineNumber, int const lineColumn) Token Token::CreateStatementEndToken(int const lineNumber, int const lineColumn)
{ {
return Token(TokenType::StatementEnd, true, lineNumber, lineColumn); return Token(TokenType::StatementEnd, true, lineNumber, lineColumn);
} }
Token Token::CreateLabelToken(std::string const & string, bool isValid, int const lineNumber, int const lineColumn) Token Token::CreateLabelToken(std::string const & string, int const lineNumber, int const lineColumn)
{ {
return Token(TokenType::Label, string, isValid, lineNumber, lineColumn); return Token(TokenType::Label, string, true, lineNumber, lineColumn);
} }
Token Token::CreateImmediateValueToken(int const value, bool isValid, int const lineNumber, int const lineColumn) Token Token::CreateImmediateValueToken(int const value, int const lineNumber, int const lineColumn)
{ {
return Token(TokenType::ImmediateInteger, value, isValid, lineNumber, lineColumn); return Token(TokenType::ImmediateInteger, value, true, lineNumber, lineColumn);
} }
Token Token::CreateRegisterToken(RegisterType const registerType, int const lineNumber, int const lineColumn) Token Token::CreateRegisterToken(RegisterType const registerType, int const lineNumber, int const lineColumn)
@@ -98,9 +111,9 @@ namespace Token
return Token(TokenType::Memory, registerType, registerType != RegisterType::Unknown, lineNumber, lineColumn); return Token(TokenType::Memory, registerType, registerType != RegisterType::Unknown, lineNumber, lineColumn);
} }
Token Token::CreateMemoryToken(int const value, bool isValid, int const lineNumber, int const lineColumn) Token Token::CreateMemoryToken(int const value, int const lineNumber, int const lineColumn)
{ {
return Token(TokenType::Memory, value, isValid, lineNumber, lineColumn); return Token(TokenType::Memory, value, true, lineNumber, lineColumn);
} }
void Token::DebugPrint() const void Token::DebugPrint() const

View File

@@ -25,7 +25,8 @@ namespace Token
{ {
if (string.size() == 0) if (string.size() == 0)
{ {
return Token::CreateUnknownToken(lineNumber, lineColumn); // TODO Should this become an error token?
return Token::CreateEmptyToken(lineNumber, lineColumn);
} }
for(std::size_t i = 0; i < substitutions.size(); ++i) for(std::size_t i = 0; i < substitutions.size(); ++i)
@@ -48,14 +49,13 @@ namespace Token
{ {
return Token::CreateImmediateValueToken( return Token::CreateImmediateValueToken(
result.value(), result.value(),
true,
lineNumber, lineNumber,
lineColumn); lineColumn);
} }
return Token::CreateImmediateValueToken( return Token::CreateErrorToken(
0, "Immediate cannot be parsed as an integer",
false, TokenType::ImmediateInteger,
lineNumber, lineNumber,
lineColumn); lineColumn);
} }
@@ -79,7 +79,6 @@ namespace Token
// TODO check if label is an Operand? // TODO check if label is an Operand?
return Token::CreateLabelToken( return Token::CreateLabelToken(
string.substr(0, string.size() - 1), string.substr(0, string.size() - 1),
true,
lineNumber, lineNumber,
lineColumn); lineColumn);
} }
@@ -88,7 +87,11 @@ namespace Token
{ {
if(string.size() < 4) if(string.size() < 4)
{ {
return Token::CreateMemoryToken(0, false, lineNumber, lineColumn + 2u); return Token::CreateErrorToken(
"Memory address statement is empty",
TokenType::Memory,
lineNumber,
lineColumn);
} }
char const memoryPrefix = string[1]; char const memoryPrefix = string[1];
@@ -101,14 +104,13 @@ namespace Token
{ {
return Token::CreateMemoryToken( return Token::CreateMemoryToken(
result.value(), result.value(),
true,
lineNumber, lineNumber,
lineColumn); lineColumn);
} }
return Token::CreateMemoryToken( return Token::CreateErrorToken(
0, "Memory immediate address cannot be parsed as an integer",
false, TokenType::Memory,
lineNumber, lineNumber,
lineColumn); lineColumn);
} }
@@ -121,13 +123,21 @@ namespace Token
} }
else else
{ {
return Token::CreateMemoryToken(0, false, lineNumber, lineColumn + 1u); return Token::CreateErrorToken(
"Memory immediate address contains an unexpected value",
TokenType::Memory,
lineNumber,
lineColumn + 1u);
} }
} }
else if (prefix == '[' || postfix == ']') else if (prefix == '[' || postfix == ']')
{ {
int const errorLineColumn = (prefix == '[') ? lineColumn : (lineColumn + string.size() - 1u); int const errorLineColumn = (prefix == '[') ? lineColumn : (lineColumn + string.size() - 1u);
return Token::CreateMemoryToken(0, false, lineNumber, errorLineColumn); return Token::CreateErrorToken(
"Non terminated memory address brackets",
TokenType::Memory,
lineNumber,
errorLineColumn);
} }
OperandType const opType = GetOperandType(string); OperandType const opType = GetOperandType(string);
@@ -137,7 +147,7 @@ namespace Token
} }
// Last resort: it must be a label // Last resort: it must be a label
return Token::CreateLabelToken(string, true, lineNumber, lineColumn); return Token::CreateLabelToken(string, lineNumber, lineColumn);
} }
bool IsWhiteSpace(char const c) bool IsWhiteSpace(char const c)
@@ -256,23 +266,20 @@ end_state_loop:
{ {
if (line[i] == '\'') if (line[i] == '\'')
{ {
// Character literal must be exactly length 3 for now (2x ' + 1
// character in between)
if (lineColumn + 2u != i) if (lineColumn + 2u != i)
{ {
tokens.emplace_back(Token::CreateImmediateValueToken( tokens.push_back(Token::CreateErrorToken(
0, "Character literal must be exactly 1 character long between single quotes",
false, TokenType::ImmediateInteger,
lineNumber, lineNumber,
lineColumn)); lineColumn + 1u));
} }
else else
{ {
tokens.emplace_back(Token::CreateImmediateValueToken( tokens.push_back(Token::CreateImmediateValueToken(
line[i - 1], line[i - 1],
true,
lineNumber, lineNumber,
lineColumn)); lineColumn + 1));
} }
lineColumn = i; lineColumn = i;
@@ -280,10 +287,9 @@ end_state_loop:
} }
} }
// Non terminated character literal! tokens.push_back(Token::CreateErrorToken(
tokens.emplace_back(Token::CreateImmediateValueToken( "Non terminated character literal",
0, TokenType::ImmediateInteger,
false,
lineNumber, lineNumber,
lineColumn)); lineColumn));

View File

@@ -5,9 +5,11 @@
void PrintBadToken(Token::Token const & token, std::vector<std::string> const & lines) void PrintBadToken(Token::Token const & token, std::vector<std::string> const & lines)
{ {
std::printf("at line number %i, column %i:\n", std::printf("at line number %i, column %i: ",
token.lineNumber + 1, token.lineNumber + 1,
token.lineColumn + 1); token.lineColumn + 1);
std::puts(token.errorMessage.c_str());
std::printf("%s\n", lines[token.lineNumber].c_str()); std::printf("%s\n", lines[token.lineNumber].c_str());
for(int i = 0; i < token.lineColumn; ++i) for(int i = 0; i < token.lineColumn; ++i)
{ {
@@ -109,6 +111,7 @@ bool Wassembler::LoadFromFile(std::string const & filePath)
catch(Interpret::InterpretationError & e) catch(Interpret::InterpretationError & e)
{ {
PrintBadToken(e.errorToken, lines); PrintBadToken(e.errorToken, lines);
std::puts("Aborting due to semantic error(s)");
return false; return false;
} }