diff --git a/.gitignore b/.gitignore index a9ca0d7..57b7346 100644 --- a/.gitignore +++ b/.gitignore @@ -3,5 +3,5 @@ brb .vscode/settings.json *.dSYM -#*.brc +*.brc build/ \ No newline at end of file diff --git a/src/Error.cpp b/src/Error.cpp new file mode 100644 index 0000000..a4f5b06 --- /dev/null +++ b/src/Error.cpp @@ -0,0 +1,35 @@ +#include "Error.h" + +Error::Error(int line, int column, string lexme) : +kind(ErrorKind::LEXER_ERROR), line(line), column(column), lexme(lexme) { } + +Error::Error(shared_ptr actualToken, optional expectedTokenKind, optional message) : +kind(ErrorKind::PARSER_ERROR), actualToken(actualToken), expectedTokenKind(expectedTokenKind), message(message) { } + +ErrorKind Error::getKind() { + return kind; +} + +int Error::getLine() { + return line; +} + +int Error::getColumn() { + return column; +} + +string Error::getLexme() { + return lexme; +} + +shared_ptr Error::getActualToken() { + return actualToken; +} + +optional Error::getExpectedTokenKind() { + return expectedTokenKind; +} + +optional Error::getMessage() { + return message; +} \ No newline at end of file diff --git a/src/Error.h b/src/Error.h new file mode 100644 index 0000000..97dc968 --- /dev/null +++ b/src/Error.h @@ -0,0 +1,43 @@ +#ifndef ERROR_H +#define ERROR_H + +#include + +class Token; +enum class TokenKind; + +using namespace std; + +enum class ErrorKind { + LEXER_ERROR, + PARSER_ERROR +}; + +class Error { +private: + ErrorKind kind; + + int line; + int column; + string lexme; + + shared_ptr actualToken; + optional expectedTokenKind; + optional message; + +public: + Error(int line, int column, string lexme); + Error(shared_ptr actualToken, optional expectedTokenKind, optional message); + + ErrorKind getKind(); + + int getLine(); + int getColumn(); + string getLexme(); + + shared_ptr getActualToken(); + optional getExpectedTokenKind(); + optional getMessage(); +}; + +#endif \ No newline at end of file diff --git a/src/Lexer/Lexer.cpp b/src/Lexer/Lexer.cpp index d017d6f..8d16cef 100644 --- a/src/Lexer/Lexer.cpp +++ b/src/Lexer/Lexer.cpp @@ -1,5 +1,9 @@ #include "Lexer.h" +#include "Token.h" +#include "Error.h" +#include "Logger.h" + Lexer::Lexer(string source): source(source) { } @@ -8,34 +12,33 @@ vector> Lexer::getTokens() { currentLine = 0; currentColumn = 0; + errors.clear(); + vector> tokens; shared_ptr token; do { token = nextToken(); - // Got a nullptr, shouldn't have happened - if (!token) { - cerr << "Failed to scan tokens" << endl; - exit(1); + if (token != nullptr) { + // Don't add new line as the first token + if (tokens.empty() && token->isOfKind({TokenKind::NEW_LINE})) + continue; + + // Insert an additional new line just before end + if (token->getKind() == TokenKind::END && tokens.back()->getKind() != TokenKind::NEW_LINE) + tokens.push_back(make_shared(TokenKind::NEW_LINE, "\n", token->getLine(), token->getColumn())); + + // filter out multiple new lines + if (tokens.empty() || token->getKind() != TokenKind::NEW_LINE || tokens.back()->getKind() != token->getKind()) + tokens.push_back(token); } + } while (token == nullptr || token->getKind() != TokenKind::END); - // Abort scanning if we got an error - if (!token->isValid()) { - cerr << "Unexpected character '" << token->getLexme() << "' at " << token->getLine() << ":" << token->getColumn() << endl; - exit(1); - } + if (!errors.empty()) { + for (shared_ptr &error : errors) + Logger::print(error); + exit(1); + } - // Don't add new line as the first token - if (tokens.empty() && token->isOfKind({TokenKind::NEW_LINE})) - continue; - - // Insert an additional new line just before end - if (token->getKind() == TokenKind::END && tokens.back()->getKind() != TokenKind::NEW_LINE) - tokens.push_back(make_shared(TokenKind::NEW_LINE, "\n", token->getLine(), token->getColumn())); - - // filter out multiple new lines - if (tokens.empty() || token->getKind() != TokenKind::NEW_LINE || tokens.back()->getKind() != token->getKind()) - tokens.push_back(token); - } while (token->getKind() != TokenKind::END); return tokens; } @@ -49,7 +52,7 @@ shared_ptr Lexer::nextToken() { shared_ptr token; // ignore // comment - token = match(TokenKind::INVALID, "//", false); + token = match(TokenKind::END, "//", false); // dummy token kind if (token) { currentIndex += 2; do { @@ -69,7 +72,7 @@ shared_ptr Lexer::nextToken() { } // ignore /* */ comment - token = match(TokenKind::INVALID, "/*", false); + token = match(TokenKind::END, "/*", false); // dummy token kind if (token) { shared_ptr newLineToken = nullptr; // we want to return the first new line we come accross int depth = 1; // so we can embed comments inside each other @@ -78,23 +81,25 @@ shared_ptr Lexer::nextToken() { token = match(TokenKind::NEW_LINE, "\n", false); newLineToken = newLineToken ? newLineToken : token; if (token) { - continue;; + continue; } // eof token = matchEnd(); - if (token) - return make_shared(TokenKind::INVALID, "", currentLine, currentColumn); + if (token) { + markError(); + return token; + } // go deeper - token = match(TokenKind::INVALID, "/*", false); + token = match(TokenKind::END, "/*", false); // dummy token kind if (token) { depth++; continue; } // go back - token = match(TokenKind::INVALID, "*/", false); + token = match(TokenKind::END, "*/", false); // dummy token kind if (token) { depth--; } @@ -265,10 +270,14 @@ shared_ptr Lexer::nextToken() { if (token != nullptr) return token; - return matchInvalid(); + markError(); + return nullptr; } shared_ptr Lexer::match(TokenKind kind, string lexme, bool needsSeparator) { + if (currentIndex + lexme.length() > source.length()) + return nullptr; + bool isMatching = source.compare(currentIndex, lexme.length(), lexme) == 0; bool isSeparatorSatisfied = !needsSeparator || isSeparator(currentIndex + lexme.length()); @@ -359,8 +368,10 @@ shared_ptr Lexer::matchReal() { while (nextIndex < source.length() && isDecDigit(nextIndex)) nextIndex++; - if (!isSeparator(nextIndex)) - return matchInvalid(); + if (!isSeparator(nextIndex)) { + markError(); + return nullptr; + } string lexme = source.substr(currentIndex, nextIndex - currentIndex); shared_ptr token = make_shared(TokenKind::REAL, lexme, currentLine, currentColumn); @@ -390,10 +401,6 @@ shared_ptr Lexer::matchEnd() { return nullptr; } -shared_ptr Lexer::matchInvalid() { - return make_shared(TokenKind::INVALID, source.substr(currentIndex, 1), currentLine, currentColumn); -} - bool Lexer::isWhiteSpace(int index) { char character = source.at(index); return character == ' ' || character == '\t'; @@ -451,7 +458,7 @@ bool Lexer::isSeparator(int index) { } } - void Lexer::advanceWithToken(shared_ptr token) { +void Lexer::advanceWithToken(shared_ptr token) { if (token->getKind() == TokenKind::NEW_LINE) { currentLine++; currentColumn = 0; @@ -459,4 +466,20 @@ bool Lexer::isSeparator(int index) { currentColumn += token->getLexme().length(); } currentIndex += token->getLexme().length(); - } +} + +void Lexer::markError() { + int startIndex = currentIndex; + int startColumn = currentColumn; + string lexme; + if (currentIndex < source.length()) { + do { + currentIndex++; + currentColumn++; + } while (!isSeparator(currentIndex)); + lexme = source.substr(startIndex, currentIndex - startIndex); + } else { + lexme = "EOF"; + } + errors.push_back(make_shared(currentLine, startColumn, lexme)); +} diff --git a/src/Lexer/Lexer.h b/src/Lexer/Lexer.h index c117b08..1f7018a 100644 --- a/src/Lexer/Lexer.h +++ b/src/Lexer/Lexer.h @@ -3,7 +3,9 @@ #include -#include "Token.h" +class Token; +enum class TokenKind; +class Error; using namespace std; @@ -13,6 +15,7 @@ private: int currentIndex; int currentLine; int currentColumn; + vector> errors; shared_ptr nextToken(); shared_ptr match(TokenKind kind, string lexme, bool needsSeparator); @@ -22,7 +25,6 @@ private: shared_ptr matchReal(); shared_ptr matchIdentifier(); shared_ptr matchEnd(); - shared_ptr matchInvalid(); bool isWhiteSpace(int index); bool isDecDigit(int index); @@ -32,6 +34,8 @@ private: bool isSeparator(int index); void advanceWithToken(shared_ptr token); + void markError(); + public: Lexer(string source); vector> getTokens(); diff --git a/src/Lexer/Token.cpp b/src/Lexer/Token.cpp index aa08a24..2c1c229 100644 --- a/src/Lexer/Token.cpp +++ b/src/Lexer/Token.cpp @@ -63,10 +63,6 @@ int Token::getColumn() { return column; } -bool Token::isValid() { - return kind != TokenKind::INVALID; -} - bool Token::isOfKind(vector kinds) { for (TokenKind &kind : kinds) { if (kind == this->kind) @@ -75,82 +71,3 @@ bool Token::isOfKind(vector kinds) { return false; } - -string Token::toString() { - switch (kind) { - case TokenKind::PLUS: - return "+"; - case TokenKind::MINUS: - return "-"; - case TokenKind::STAR: - return "*"; - case TokenKind::SLASH: - return "/"; - case TokenKind::PERCENT: - return "%"; - - case TokenKind::EQUAL: - return "="; - case TokenKind::NOT_EQUAL: - return "≠"; - case TokenKind::LESS: - return "<"; - case TokenKind::LESS_EQUAL: - return "≤"; - case TokenKind::GREATER: - return ">"; - case TokenKind::GREATER_EQUAL: - return "≥"; - - case TokenKind::LEFT_PAREN: - return "("; - case TokenKind::RIGHT_PAREN: - return ")"; - case TokenKind::COMMA: - return ","; - case TokenKind::COLON: - return ":"; - case TokenKind::SEMICOLON: - return ";"; - case TokenKind::LEFT_ARROW: - return "←"; - case TokenKind::RIGHT_ARROW: - return "→"; - - case TokenKind::BOOL: - return "BOOL(" + lexme + ")"; - case TokenKind::INTEGER_DEC: - return "INTEGER_DEC(" + lexme + ")"; - case TokenKind::INTEGER_HEX: - return "INTEGER_HEX(" + lexme + ")"; - case TokenKind::INTEGER_BIN: - return "INTEGER_BIN(" + lexme + ")"; - case TokenKind::REAL: - return "REAL(" + lexme + ")"; - case TokenKind::IDENTIFIER: - return "IDENTIFIER(" + lexme + ")"; - case TokenKind::TYPE: - return "TYPE(" + lexme + ")"; - - case TokenKind::IF: - return "IF"; - case TokenKind::ELSE: - return "ELSE"; - case TokenKind::FUNCTION: - return "FUNCTION"; - case TokenKind::RETURN: - return "RETURN"; - case TokenKind::REPEAT: - return "REPEAT"; - - case TokenKind::M_EXTERN: - return "@EXTERN"; - - case TokenKind::NEW_LINE: - return "↲"; - case TokenKind::END: - return "END"; - case TokenKind::INVALID: - return "INVALID"; - } -} \ No newline at end of file diff --git a/src/Lexer/Token.h b/src/Lexer/Token.h index 1e3adbe..353832a 100644 --- a/src/Lexer/Token.h +++ b/src/Lexer/Token.h @@ -46,9 +46,7 @@ enum class TokenKind { M_EXTERN, NEW_LINE, - END, - - INVALID + END }; class Token { @@ -71,9 +69,7 @@ public: string getLexme(); int getLine(); int getColumn(); - bool isValid(); bool isOfKind(vector kinds); - string toString(); }; #endif \ No newline at end of file diff --git a/src/Logger.cpp b/src/Logger.cpp new file mode 100644 index 0000000..a744500 --- /dev/null +++ b/src/Logger.cpp @@ -0,0 +1,437 @@ +#include "Logger.h" + +#include + +#include "Lexer/Token.h" + +#include "Parser/Statement/Statement.h" +#include "Parser/Statement/StatementMetaExternFunction.h" +#include "Parser/Statement/StatementVariable.h" +#include "Parser/Statement/StatementFunction.h" +#include "Parser/Statement/StatementBlock.h" +#include "Parser/Statement/StatementAssignment.h" +#include "Parser/Statement/StatementReturn.h" +#include "Parser/Statement/StatementRepeat.h" +#include "Parser/Statement/StatementExpression.h" + +#include "Parser/Expression/Expression.h" +#include "Parser/Expression/ExpressionBinary.h" +#include "Parser/Expression/ExpressionIfElse.h" +#include "Parser/Expression/ExpressionVariable.h" +#include "Parser/Expression/ExpressionGrouping.h" +#include "Parser/Expression/ExpressionLiteral.h" +#include "Parser/Expression/ExpressionCall.h" +#include "Parser/Expression/ExpressionBlock.h" + +#include "Error.h" + +string Logger::toString(shared_ptr token) { + switch (token->getKind()) { + case TokenKind::PLUS: + return "+"; + case TokenKind::MINUS: + return "-"; + case TokenKind::STAR: + return "*"; + case TokenKind::SLASH: + return "/"; + case TokenKind::PERCENT: + return "%"; + + case TokenKind::EQUAL: + return "="; + case TokenKind::NOT_EQUAL: + return "≠"; + case TokenKind::LESS: + return "<"; + case TokenKind::LESS_EQUAL: + return "≤"; + case TokenKind::GREATER: + return ">"; + case TokenKind::GREATER_EQUAL: + return "≥"; + + case TokenKind::LEFT_PAREN: + return "("; + case TokenKind::RIGHT_PAREN: + return ")"; + case TokenKind::COMMA: + return ","; + case TokenKind::COLON: + return ":"; + case TokenKind::SEMICOLON: + return ";"; + case TokenKind::LEFT_ARROW: + return "←"; + case TokenKind::RIGHT_ARROW: + return "→"; + + case TokenKind::BOOL: + return "BOOL(" + token->getLexme() + ")"; + case TokenKind::INTEGER_DEC: + return "INT_DEC(" + token->getLexme() + ")"; + case TokenKind::INTEGER_HEX: + return "INT_HEX(" + token->getLexme() + ")"; + case TokenKind::INTEGER_BIN: + return "INT_BIN(" + token->getLexme() + ")"; + case TokenKind::REAL: + return "REAL(" + token->getLexme() + ")"; + case TokenKind::IDENTIFIER: + return "ID(" + token->getLexme() + ")"; + case TokenKind::TYPE: + return "TYPE(" + token->getLexme() + ")"; + + case TokenKind::IF: + return "IF"; + case TokenKind::ELSE: + return "ELSE"; + case TokenKind::FUNCTION: + return "FUN"; + case TokenKind::RETURN: + return "RET"; + case TokenKind::REPEAT: + return "REP"; + + case TokenKind::M_EXTERN: + return "@EXTERN"; + + case TokenKind::NEW_LINE: + return "↲"; + case TokenKind::END: + return "END"; + } +} + +string Logger::toString(TokenKind tokenKind) { + switch (tokenKind) { + case TokenKind::PLUS: + return "+"; + case TokenKind::MINUS: + return "-"; + case TokenKind::STAR: + return "*"; + case TokenKind::SLASH: + return "/"; + case TokenKind::PERCENT: + return "%"; + + case TokenKind::EQUAL: + return "="; + case TokenKind::NOT_EQUAL: + return "≠"; + case TokenKind::LESS: + return "<"; + case TokenKind::LESS_EQUAL: + return "≤"; + case TokenKind::GREATER: + return ">"; + case TokenKind::GREATER_EQUAL: + return "≥"; + + case TokenKind::LEFT_PAREN: + return "("; + case TokenKind::RIGHT_PAREN: + return ")"; + case TokenKind::COMMA: + return ","; + case TokenKind::COLON: + return ":"; + case TokenKind::SEMICOLON: + return ";"; + case TokenKind::LEFT_ARROW: + return "←"; + case TokenKind::RIGHT_ARROW: + return "→"; + + case TokenKind::BOOL: + return "LITERAL(BOOLEAN)"; + case TokenKind::INTEGER_DEC: + case TokenKind::INTEGER_HEX: + case TokenKind::INTEGER_BIN: + return "LITERAL(INTEGER)"; + case TokenKind::REAL: + return "LITERAL(REAL)"; + case TokenKind::IDENTIFIER: + return "LITERAL(ID)"; + case TokenKind::TYPE: + return "TYPE"; + + case TokenKind::IF: + return "IF"; + case TokenKind::ELSE: + return "ELSE"; + case TokenKind::FUNCTION: + return "FUN"; + case TokenKind::RETURN: + return "RET"; + case TokenKind::REPEAT: + return "REP"; + + case TokenKind::M_EXTERN: + return "@EXTERN"; + + case TokenKind::NEW_LINE: + return "↲"; + case TokenKind::END: + return "END"; + } +} + +string Logger::toString(shared_ptr statement) { + switch (statement->getKind()) { + case StatementKind::META_EXTERN_FUNCTION: + return toString(dynamic_pointer_cast(statement)); + case StatementKind::VARIABLE: + return toString(dynamic_pointer_cast(statement)); + case StatementKind::FUNCTION: + return toString(dynamic_pointer_cast(statement)); + case StatementKind::BLOCK: + return toString(dynamic_pointer_cast(statement)); + case StatementKind::ASSIGNMENT: + return toString(dynamic_pointer_cast(statement)); + case StatementKind::RETURN: + return toString(dynamic_pointer_cast(statement)); + case StatementKind::REPEAT: + return toString(dynamic_pointer_cast(statement)); + case StatementKind::EXPRESSION: + return toString(dynamic_pointer_cast(statement)); + } +} + +string Logger::toString(shared_ptr statement) { + string text; + + string argsString; + for (int i = 0; i < statement->getArguments().size(); i++) { + auto arg = statement->getArguments().at(i); + argsString += format("ARG({}, {})", arg.first, toString(arg.second)); + } + text += format("@EXTERN FUN(\"{}\"|{}|{})", statement->getName(), argsString, toString(statement->getReturnValueType())); + + + return text; +} + +string Logger::toString(shared_ptr statement) { + return format("{}({}|{})", statement->getName(), toString(statement->getValueType()), toString(statement->getExpression())); +} + +string Logger::toString(shared_ptr statement) { + string text; + + string argsString; + for (int i = 0; i < statement->getArguments().size(); i++) { + auto arg = statement->getArguments().at(i); + argsString += format("ARG({}, {})", arg.first, toString(arg.second)); + } + text += format("FUN(\"{}\"|{}|{}):\n", statement->getName(), argsString, toString(statement->getReturnValueType())); + text += toString(statement->getStatementBlock()); + + return text; +} + +string Logger::toString(shared_ptr statement) { + string text; + + for (int i=0; igetStatements().size(); i++) { + text += toString(statement->getStatements().at(i)); + if (i < statement->getStatements().size() - 1) + text += "\n"; + } + + return text; +} + +string Logger::toString(shared_ptr statement) { + return format("{} <- {}", statement->getName(), toString(statement->getExpression())); +} + +string Logger::toString(shared_ptr statement) { + string text = "RET"; + if (statement->getExpression() != nullptr) + text += format("({})", toString(statement->getExpression())); + return text; +} + +string Logger::toString(shared_ptr statement) { + string text; + + string initStatement; + string preCondition; + string postCondition; + + if (statement->getInitStatement() != nullptr) + initStatement = toString(statement->getInitStatement()); + + if (statement->getPostConditionExpression() != nullptr) + preCondition = toString(statement->getPreConditionExpression()); + + if (statement->getPostConditionExpression() != nullptr) + postCondition = toString(statement->getPostConditionExpression()); + + text += format("REP({}|{}|{}):\n", initStatement, preCondition, postCondition); + text += toString(statement->getBodyBlockStatement()); + + return text; +} + +string Logger::toString(shared_ptr statement) { + return format("EXPR({})", toString(statement->getExpression())); +} + +string Logger::toString(ValueType valueType) { + switch (valueType) { + case ValueType::NONE: + return "NONE"; + case ValueType::BOOL: + return "BOOL"; + case ValueType::SINT32: + return "SINT32"; + case ValueType::REAL32: + return "REAL32"; + } +} + +string Logger::toString(shared_ptr expression) { + switch (expression->getKind()) { + case ExpressionKind::BINARY: + return toString(dynamic_pointer_cast(expression)); + case ExpressionKind::IF_ELSE: + return toString(dynamic_pointer_cast(expression)); + case ExpressionKind::VAR: + return toString(dynamic_pointer_cast(expression)); + case ExpressionKind::GROUPING: + return toString(dynamic_pointer_cast(expression)); + case ExpressionKind::LITERAL: + return toString(dynamic_pointer_cast(expression)); + case ExpressionKind::CALL: + return toString(dynamic_pointer_cast(expression)); + case ExpressionKind::BLOCK: + return toString(dynamic_pointer_cast(expression)); + } +} + +string Logger::toString(shared_ptr expression) { + switch (expression->getOperation()) { + case ExpressionBinaryOperation::EQUAL: + return "{= " + toString(expression->getLeft()) + " " + toString(expression->getRight()) + "}"; + case ExpressionBinaryOperation::NOT_EQUAL: + return "{!= " + toString(expression->getLeft()) + " " + toString(expression->getRight()) + "}"; + case ExpressionBinaryOperation::LESS: + return "{< " + toString(expression->getLeft()) + " " + toString(expression->getRight()) + "}"; + case ExpressionBinaryOperation::LESS_EQUAL: + return "{<= " + toString(expression->getLeft()) + " " + toString(expression->getRight()) + "}"; + case ExpressionBinaryOperation::GREATER: + return "{> " + toString(expression->getLeft()) + " " + toString(expression->getRight()) + "}"; + case ExpressionBinaryOperation::GREATER_EQUAL: + return "{<= " + toString(expression->getLeft()) + " " + toString(expression->getRight()) + "}"; + case ExpressionBinaryOperation::ADD: + return "{+ " + toString(expression->getLeft()) + " " + toString(expression->getRight()) + "}"; + case ExpressionBinaryOperation::SUB: + return "{- " + toString(expression->getLeft()) + " " + toString(expression->getRight()) + "}"; + case ExpressionBinaryOperation::MUL: + return "{* " + toString(expression->getLeft()) + " " + toString(expression->getRight()) + "}"; + case ExpressionBinaryOperation::DIV: + return "{/ " + toString(expression->getLeft()) + " " + toString(expression->getRight()) + "}"; + case ExpressionBinaryOperation::MOD: + return "{% " + toString(expression->getLeft()) + " " + toString(expression->getRight()) + "}"; + } +} + +string Logger::toString(shared_ptr expression) { + string text; + + text += format("IF({}):\n", toString(expression->getCondition())); + text += toString(expression->getThenBlock()); + if (expression->getElseBlock() != nullptr) { + text += "\nELSE:\n"; + text += toString(expression->getElseBlock()); + } + text += "\n;"; + + return text; +} + +string Logger::toString(shared_ptr expression) { + return format("VAR({})", expression->getName()); +} + +string Logger::toString(shared_ptr expression) { + return format("({})", toString(expression->getExpression())); +} + +string Logger::toString(shared_ptr expression) { + switch (expression->getValueType()) { + case ValueType::NONE: + return "NONE"; + case ValueType::BOOL: + return expression->getBoolValue() ? "true" : "false"; + case ValueType::SINT32: + return to_string(expression->getSint32Value()); + case ValueType::REAL32: + return to_string(expression->getReal32Value()); + } +} + +string Logger::toString(shared_ptr expression) { + string argsString; + for (int i = 0; i < expression->getArgumentExpressions().size(); i++) { + argsString += toString(expression->getArgumentExpressions().at(i)); + if (i < expression->getArgumentExpressions().size() - 1) + argsString += ", "; + } + return format("CALL({}|{})", expression->getName(), argsString); +} + +string Logger::toString(shared_ptr expression) { + string text; + text += toString(expression->getStatementBlock()); + if (expression->getResultStatementExpression() != nullptr) + text += toString(expression->getResultStatementExpression()); + return text; +} + + +void Logger::print(vector> tokens) { + for (int i=0; i> statements) { + for (shared_ptr &statement : statements) { + cout << toString(statement) << endl << endl; + } +} + +void Logger::print(shared_ptr error) { + string message; + switch (error->getKind()) { + case ErrorKind::LEXER_ERROR: + message = format("Unexpected token \"{}\" at line: {}, column: {}", error->getLexme(), error->getLine() + 1, error->getColumn() + 1); + break; + case ErrorKind::PARSER_ERROR: + shared_ptr token = error->getActualToken(); + optional expectedTokenKind = error->getExpectedTokenKind(); + optional errorMessage = error->getMessage(); + + if (expectedTokenKind) { + message = format( + "Expected token {} but instead found \"{}\" at line: {}, column: {}", + toString(*expectedTokenKind), token->getLexme(), token->getLine() + 1, token->getColumn() + 1 + ); + } else { + message = format( + "Unexpected token \"{}\" found at line: {}, column: {}", + token->getLexme(), token->getLine() + 1, token->getColumn() + 1 + ); + } + if (errorMessage) + message += format(". {}", *errorMessage); + break; + } + cout << message << endl; +} \ No newline at end of file diff --git a/src/Logger.h b/src/Logger.h new file mode 100644 index 0000000..9d1735d --- /dev/null +++ b/src/Logger.h @@ -0,0 +1,65 @@ +#ifndef LOGGER_H +#define LOGGER_H + +#include + +class Token; +enum class TokenKind; +class Statement; +class StatementMetaExternFunction; +class StatementVariable; +class StatementFunction; +class StatementBlock; +class StatementAssignment; +class StatementReturn; +class StatementRepeat; +class StatementExpression; + +class Expression; +class ExpressionBinary; +class ExpressionIfElse; +class ExpressionVariable; +class ExpressionGrouping; +class ExpressionLiteral; +class ExpressionCall; +class ExpressionBlock; + +enum class ValueType; + +class Error; + +using namespace std; + +class Logger { +private: + static string toString(shared_ptr token); + static string toString(TokenKind tokenKind); + + static string toString(shared_ptr statement); + static string toString(shared_ptr statement); + static string toString(shared_ptr statement); + static string toString(shared_ptr statement); + static string toString(shared_ptr statement); + static string toString(shared_ptr statement); + static string toString(shared_ptr statement); + static string toString(shared_ptr statement); + static string toString(shared_ptr statement); + + static string toString(shared_ptr expression); + static string toString(shared_ptr expression); + static string toString(shared_ptr expression); + static string toString(shared_ptr expression); + static string toString(shared_ptr expression); + static string toString(shared_ptr expression); + static string toString(shared_ptr expression); + static string toString(shared_ptr expression); + + static string toString(ValueType valueType); + +public: + static void print(vector> tokens); + static void print(vector> statements); + static void print(shared_ptr error); +}; + +#endif \ No newline at end of file diff --git a/src/Parser/Expression/Expression.cpp b/src/Parser/Expression/Expression.cpp index 6e5a91c..f5a5913 100644 --- a/src/Parser/Expression/Expression.cpp +++ b/src/Parser/Expression/Expression.cpp @@ -11,11 +11,3 @@ ExpressionKind Expression::getKind() { ValueType Expression::getValueType() { return valueType; } - -bool Expression::isValid() { - return kind != ExpressionKind::INVALID; -} - -string Expression::toString(int indent) { - return "EXPRESSION"; -} diff --git a/src/Parser/Expression/Expression.h b/src/Parser/Expression/Expression.h index ccc92d5..0a7f16c 100644 --- a/src/Parser/Expression/Expression.h +++ b/src/Parser/Expression/Expression.h @@ -15,8 +15,7 @@ enum class ExpressionKind { IF_ELSE, VAR, CALL, - BLOCK, - INVALID + BLOCK }; class Expression { @@ -28,10 +27,9 @@ protected: public: Expression(ExpressionKind kind, ValueType valueType); + virtual ~Expression() { } ExpressionKind getKind(); ValueType getValueType(); - bool isValid(); - virtual string toString(int indent); }; #endif \ No newline at end of file diff --git a/src/Parser/Expression/ExpressionBinary.cpp b/src/Parser/Expression/ExpressionBinary.cpp index bd062b9..29a42be 100644 --- a/src/Parser/Expression/ExpressionBinary.cpp +++ b/src/Parser/Expression/ExpressionBinary.cpp @@ -71,30 +71,3 @@ shared_ptr ExpressionBinary::getLeft() { shared_ptr ExpressionBinary::getRight() { return right; } - -string ExpressionBinary::toString(int indent) { - switch (operation) { - case ExpressionBinaryOperation::EQUAL: - return "{= " + left->toString(0) + " " + right->toString(0) + "}"; - case ExpressionBinaryOperation::NOT_EQUAL: - return "{!= " + left->toString(0) + " " + right->toString(0) + "}"; - case ExpressionBinaryOperation::LESS: - return "{< " + left->toString(0) + " " + right->toString(0) + "}"; - case ExpressionBinaryOperation::LESS_EQUAL: - return "{<= " + left->toString(0) + " " + right->toString(0) + "}"; - case ExpressionBinaryOperation::GREATER: - return "{> " + left->toString(0) + " " + right->toString(0) + "}"; - case ExpressionBinaryOperation::GREATER_EQUAL: - return "{<= " + left->toString(0) + " " + right->toString(0) + "}"; - case ExpressionBinaryOperation::ADD: - return "{+ " + left->toString(0) + " " + right->toString(0) + "}"; - case ExpressionBinaryOperation::SUB: - return "{- " + left->toString(0) + " " + right->toString(0) + "}"; - case ExpressionBinaryOperation::MUL: - return "{* " + left->toString(0) + " " + right->toString(0) + "}"; - case ExpressionBinaryOperation::DIV: - return "{/ " + left->toString(0) + " " + right->toString(0) + "}"; - case ExpressionBinaryOperation::MOD: - return "{% " + left->toString(0) + " " + right->toString(0) + "}"; - } -} \ No newline at end of file diff --git a/src/Parser/Expression/ExpressionBinary.h b/src/Parser/Expression/ExpressionBinary.h index 5fbc44c..0c5bb4c 100644 --- a/src/Parser/Expression/ExpressionBinary.h +++ b/src/Parser/Expression/ExpressionBinary.h @@ -26,5 +26,4 @@ public: ExpressionBinaryOperation getOperation(); shared_ptr getLeft(); shared_ptr getRight(); - string toString(int indent) override; }; \ No newline at end of file diff --git a/src/Parser/Expression/ExpressionBlock.cpp b/src/Parser/Expression/ExpressionBlock.cpp index e3e40c3..c21d5ba 100644 --- a/src/Parser/Expression/ExpressionBlock.cpp +++ b/src/Parser/Expression/ExpressionBlock.cpp @@ -11,7 +11,7 @@ Expression(ExpressionKind::BLOCK, ValueType::NONE) { valueType = resultStatementExpression->getExpression()->getValueType(); statements.pop_back(); } else { - resultStatementExpression = make_shared(ExpressionLiteral::NONE); + resultStatementExpression = make_shared(make_shared()); } statementBlock = make_shared(statements); } @@ -23,7 +23,3 @@ shared_ptr ExpressionBlock::getStatementBlock() { shared_ptr ExpressionBlock::getResultStatementExpression() { return resultStatementExpression; } - -string ExpressionBlock::toString(int indent) { - return ""; -} \ No newline at end of file diff --git a/src/Parser/Expression/ExpressionBlock.h b/src/Parser/Expression/ExpressionBlock.h index 05f5663..42850b8 100644 --- a/src/Parser/Expression/ExpressionBlock.h +++ b/src/Parser/Expression/ExpressionBlock.h @@ -13,5 +13,4 @@ public: ExpressionBlock(vector> statements); shared_ptr getStatementBlock(); shared_ptr getResultStatementExpression(); - string toString(int indent) override; }; \ No newline at end of file diff --git a/src/Parser/Expression/ExpressionCall.cpp b/src/Parser/Expression/ExpressionCall.cpp index 315590b..ea917e9 100644 --- a/src/Parser/Expression/ExpressionCall.cpp +++ b/src/Parser/Expression/ExpressionCall.cpp @@ -10,17 +10,3 @@ string ExpressionCall::getName() { vector> ExpressionCall::getArgumentExpressions() { return argumentExpressions; } - -string ExpressionCall::toString(int indent) { - string value; - - value += "CALL(" + name + "):"; - for (shared_ptr &argumentExpression : argumentExpressions) { - value += "\n"; - for (int ind=0; indtoString(indent+1) + ","; - } - - return value; -} \ No newline at end of file diff --git a/src/Parser/Expression/ExpressionCall.h b/src/Parser/Expression/ExpressionCall.h index 5a06308..70df042 100644 --- a/src/Parser/Expression/ExpressionCall.h +++ b/src/Parser/Expression/ExpressionCall.h @@ -9,5 +9,4 @@ public: ExpressionCall(string name, vector> argumentExpressions); string getName(); vector> getArgumentExpressions(); - string toString(int indent) override; }; \ No newline at end of file diff --git a/src/Parser/Expression/ExpressionGrouping.cpp b/src/Parser/Expression/ExpressionGrouping.cpp index d5762fc..a9c783a 100644 --- a/src/Parser/Expression/ExpressionGrouping.cpp +++ b/src/Parser/Expression/ExpressionGrouping.cpp @@ -6,7 +6,3 @@ Expression(ExpressionKind::GROUPING, expression->getValueType()), expression(exp shared_ptr ExpressionGrouping::getExpression() { return expression; } - -string ExpressionGrouping::toString(int indent) { - return "( " + expression->toString(0) + " )"; -} diff --git a/src/Parser/Expression/ExpressionGrouping.h b/src/Parser/Expression/ExpressionGrouping.h index e30a6ec..490f3fc 100644 --- a/src/Parser/Expression/ExpressionGrouping.h +++ b/src/Parser/Expression/ExpressionGrouping.h @@ -7,5 +7,4 @@ private: public: ExpressionGrouping(shared_ptr expression); shared_ptr getExpression(); - string toString(int indent) override; }; \ No newline at end of file diff --git a/src/Parser/Expression/ExpressionIfElse.cpp b/src/Parser/Expression/ExpressionIfElse.cpp index 2d4d374..5c2d6d9 100644 --- a/src/Parser/Expression/ExpressionIfElse.cpp +++ b/src/Parser/Expression/ExpressionIfElse.cpp @@ -20,21 +20,3 @@ shared_ptr ExpressionIfElse::getThenBlock() { shared_ptr ExpressionIfElse::getElseBlock() { return elseBlock; } - -string ExpressionIfElse::toString(int indent) { - string value; - value += "IF(" + condition->toString(0) + "):\n"; - - value += thenBlock->toString(indent+1); - if (elseBlock != nullptr) { - for (int ind=0; indtoString(indent+1); - } - for (int ind=0; ind getCondition(); shared_ptr getThenBlock(); shared_ptr getElseBlock(); - string toString(int indent) override; }; \ No newline at end of file diff --git a/src/Parser/Expression/ExpressionInvalid.cpp b/src/Parser/Expression/ExpressionInvalid.cpp deleted file mode 100644 index 3f0ae4c..0000000 --- a/src/Parser/Expression/ExpressionInvalid.cpp +++ /dev/null @@ -1,13 +0,0 @@ -#include "ExpressionInvalid.h" - -ExpressionInvalid::ExpressionInvalid(shared_ptr token): -Expression(ExpressionKind::INVALID, ValueType::NONE), token(token) { -} - -shared_ptr ExpressionInvalid::getToken() { - return token; -} - -string ExpressionInvalid::toString(int indent) { - return "Invalid token " + token->toString() + " at " + to_string(token->getLine()) + ":" + to_string(token->getColumn()) + "\n"; -} \ No newline at end of file diff --git a/src/Parser/Expression/ExpressionInvalid.h b/src/Parser/Expression/ExpressionInvalid.h deleted file mode 100644 index 6e2f454..0000000 --- a/src/Parser/Expression/ExpressionInvalid.h +++ /dev/null @@ -1,11 +0,0 @@ -#include "Parser/Expression/Expression.h" - -class ExpressionInvalid: public Expression { -private: - shared_ptr token; - -public: - ExpressionInvalid(shared_ptr token); - shared_ptr getToken(); - string toString(int indent) override; -}; \ No newline at end of file diff --git a/src/Parser/Expression/ExpressionLiteral.cpp b/src/Parser/Expression/ExpressionLiteral.cpp index 0db92f7..df85403 100644 --- a/src/Parser/Expression/ExpressionLiteral.cpp +++ b/src/Parser/Expression/ExpressionLiteral.cpp @@ -1,7 +1,5 @@ #include "ExpressionLiteral.h" -shared_ptr ExpressionLiteral::NONE; - ExpressionLiteral::ExpressionLiteral(): Expression(ExpressionKind::LITERAL, ValueType::NONE) { } @@ -54,16 +52,3 @@ int32_t ExpressionLiteral::getSint32Value() { float ExpressionLiteral::getReal32Value() { return real32Value; } - -string ExpressionLiteral::toString(int indent) { - switch (valueType) { - case ValueType::NONE: - return "NONE"; - case ValueType::BOOL: - return boolValue ? "true" : "false"; - case ValueType::SINT32: - return to_string(sint32Value); - case ValueType::REAL32: - return to_string(real32Value); - } -} \ No newline at end of file diff --git a/src/Parser/Expression/ExpressionLiteral.h b/src/Parser/Expression/ExpressionLiteral.h index 0fc1578..77972d2 100644 --- a/src/Parser/Expression/ExpressionLiteral.h +++ b/src/Parser/Expression/ExpressionLiteral.h @@ -6,14 +6,11 @@ private: int32_t sint32Value; float real32Value; - ExpressionLiteral(); - + public: - static shared_ptr NONE; - ExpressionLiteral(shared_ptr token); + ExpressionLiteral(); bool getBoolValue(); int32_t getSint32Value(); float getReal32Value(); - string toString(int indent) override; }; \ No newline at end of file diff --git a/src/Parser/Expression/ExpressionVariable.cpp b/src/Parser/Expression/ExpressionVariable.cpp index e6a1838..da9e78e 100644 --- a/src/Parser/Expression/ExpressionVariable.cpp +++ b/src/Parser/Expression/ExpressionVariable.cpp @@ -6,7 +6,3 @@ Expression(ExpressionKind::VAR, ValueType::NONE), name(name) { } string ExpressionVariable::getName() { return name; } - -string ExpressionVariable::toString(int indent) { - return "VAR(" + name + ")"; -} \ No newline at end of file diff --git a/src/Parser/Expression/ExpressionVariable.h b/src/Parser/Expression/ExpressionVariable.h index 0b10e5d..bd0b99f 100644 --- a/src/Parser/Expression/ExpressionVariable.h +++ b/src/Parser/Expression/ExpressionVariable.h @@ -7,5 +7,4 @@ private: public: ExpressionVariable(string name); string getName(); - string toString(int indent) override; }; \ No newline at end of file diff --git a/src/Parser/Parser.cpp b/src/Parser/Parser.cpp index 7a2ae0a..2be34c2 100644 --- a/src/Parser/Parser.cpp +++ b/src/Parser/Parser.cpp @@ -1,5 +1,8 @@ #include "Parser.h" +#include "Error.h" +#include "Logger.h" + #include "Parser/Expression/ExpressionGrouping.h" #include "Parser/Expression/ExpressionLiteral.h" #include "Parser/Expression/ExpressionVariable.h" @@ -7,7 +10,6 @@ #include "Parser/Expression/ExpressionIfElse.h" #include "Parser/Expression/ExpressionBinary.h" #include "Parser/Expression/ExpressionBlock.h" -#include "Parser/Expression/ExpressionInvalid.h" #include "Parser/Statement/StatementFunction.h" #include "Parser/Statement/StatementVariable.h" @@ -17,7 +19,6 @@ #include "Parser/Statement/StatementMetaExternFunction.h" #include "Parser/Statement/StatementBlock.h" #include "Parser/Statement/StatementRepeat.h" -#include "Parser/Statement/StatementInvalid.h" Parser::Parser(vector> tokens): tokens(tokens) { } @@ -27,20 +28,21 @@ vector> Parser::getStatements() { while (!tryMatchingTokenKinds({TokenKind::END}, true, false)) { shared_ptr statement = nextStatement(); - // Abort parsing if we got an error - if (!statement->isValid()) { - cerr << statement->toString(0); - exit(1); - } - statements.push_back(statement); + if (statement != nullptr) { + statements.push_back(statement); - // Expect new line after statement - if (!tryMatchingTokenKinds({TokenKind::NEW_LINE}, true, true)) { - cerr << "Expected new line" << endl; - exit(1); + // Expect new line after statement + if (!tryMatchingTokenKinds({TokenKind::NEW_LINE}, true, true)) + markError(TokenKind::NEW_LINE, {}); } } + if (!errors.empty()) { + for (shared_ptr &error : errors) + Logger::print(error); + exit(1); + } + return statements; } @@ -48,47 +50,51 @@ vector> Parser::getStatements() { // Statement // shared_ptr Parser::nextStatement() { - shared_ptr statement; + shared_ptr statement; + int errorsCount = errors.size(); statement = matchStatementFunction(); - if (statement != nullptr) + if (statement != nullptr || errors.size() > errorsCount) return statement; statement = matchStatementVariable(); - if (statement != nullptr) + if (statement != nullptr || errors.size() > errorsCount) return statement; statement = matchStatementMetaExternFunction(); - if (statement != nullptr) + if (statement != nullptr || errors.size() > errorsCount) return statement; - return matchStatementInvalid("Unexpected token"); + markError({}, {}); + return nullptr; } shared_ptr Parser::nextInBlockStatement() { shared_ptr statement; + int errorsCount = errors.size(); statement = matchStatementVariable(); - if (statement != nullptr) + if (statement != nullptr || errors.size() > errorsCount) return statement; statement = matchStatementAssignment(); - if (statement != nullptr) + if (statement != nullptr || errors.size() > errorsCount) return statement; statement = matchStatementReturn(); - if (statement != nullptr) + if (statement != nullptr || errors.size() > errorsCount) return statement; statement = matchStatementRepeat(); - if (statement != nullptr) + if (statement != nullptr || errors.size() > errorsCount) return statement; statement = matchStatementExpression(); - if (statement != nullptr) + if (statement != nullptr || errors.size() > errorsCount) return statement; - return matchStatementInvalid("Unexpected token"); + markError({}, {}); + return nullptr; } shared_ptr Parser::matchStatementMetaExternFunction() { @@ -107,13 +113,17 @@ shared_ptr Parser::matchStatementMetaExternFunction() { if (tryMatchingTokenKinds({TokenKind::COLON}, true, true)) { do { tryMatchingTokenKinds({TokenKind::NEW_LINE}, true, true); // skip new line - if (!tryMatchingTokenKinds({TokenKind::IDENTIFIER, TokenKind::TYPE}, true, false)) - return matchStatementInvalid("Expected function argument"); + if (!tryMatchingTokenKinds({TokenKind::IDENTIFIER, TokenKind::TYPE}, true, false)) { + markError({}, "Expected function argument"); + return nullptr; + } shared_ptr identifierToken = tokens.at(currentIndex++); shared_ptr typeToken = tokens.at(currentIndex++); optional argumentType = valueTypeForToken(typeToken); - if (!argumentType) - return matchStatementInvalid("Invalid argument type"); + if (!argumentType) { + markError(TokenKind::TYPE, {}); + return nullptr; + } arguments.push_back(pair(identifierToken->getLexme(), *argumentType)); } while (tryMatchingTokenKinds({TokenKind::COMMA}, true, true)); @@ -125,8 +135,10 @@ shared_ptr Parser::matchStatementMetaExternFunction() { shared_ptr typeToken = tokens.at(currentIndex); optional type = valueTypeForToken(typeToken); - if (!type) - return matchStatementInvalid("Expected return type"); + if (!type) { + markError(TokenKind::TYPE, {}); + return nullptr; + } returnType = *type; currentIndex++; // type @@ -149,18 +161,22 @@ shared_ptr Parser::matchStatementVariable() { valueType = ValueType::SINT32; else if (valueTypeToken->getLexme().compare("real32") == 0) valueType = ValueType::REAL32; - else - return matchStatementInvalid("Invalid type"); + else { + markError(TokenKind::TYPE, {}); + return nullptr; + } currentIndex++; // type // Expect left arrow - if (!tryMatchingTokenKinds({TokenKind::LEFT_ARROW}, true, true)) - return matchStatementInvalid("Expected left arrow"); + if (!tryMatchingTokenKinds({TokenKind::LEFT_ARROW}, true, true)) { + markError(TokenKind::LEFT_ARROW, {}); + return nullptr; + } shared_ptr expression = nextExpression(); - if (expression == nullptr || !expression->isValid()) - return matchStatementInvalid("Invalid expression"); + if (expression == nullptr) + return nullptr; return make_shared(identifierToken->getLexme(), valueType, expression); } @@ -182,13 +198,17 @@ shared_ptr Parser::matchStatementFunction() { if (tryMatchingTokenKinds({TokenKind::COLON}, true, true)) { do { tryMatchingTokenKinds({TokenKind::NEW_LINE}, true, true); // skip new line - if (!tryMatchingTokenKinds({TokenKind::IDENTIFIER, TokenKind::TYPE}, true, false)) - return matchStatementInvalid("Expected function argument"); + if (!tryMatchingTokenKinds({TokenKind::IDENTIFIER, TokenKind::TYPE}, true, false)) { + markError({}, "Expected function argument"); + return nullptr; + } shared_ptr identifierToken = tokens.at(currentIndex++); shared_ptr typeToken = tokens.at(currentIndex++); optional argumentType = valueTypeForToken(typeToken); - if (!argumentType) - return matchStatementInvalid("Invalid argument type"); + if (!argumentType) { + markError(TokenKind::TYPE, {}); + return nullptr; + } arguments.push_back(pair(identifierToken->getLexme(), *argumentType)); } while (tryMatchingTokenKinds({TokenKind::COMMA}, true, true)); @@ -200,24 +220,30 @@ shared_ptr Parser::matchStatementFunction() { shared_ptr typeToken = tokens.at(currentIndex); optional type = valueTypeForToken(typeToken); - if (!type) - return matchStatementInvalid("Expected return type"); + if (!type) { + markError(TokenKind::TYPE, {}); + return nullptr; + } returnType = *type; currentIndex++; // type } // consume new line - if (!tryMatchingTokenKinds({TokenKind::NEW_LINE}, true, true)) - return matchStatementInvalid("Expected new line after function declaration"); + if (!tryMatchingTokenKinds({TokenKind::NEW_LINE}, true, true)) { + markError(TokenKind::NEW_LINE, {}); + return nullptr; + } // block statementBlock = matchStatementBlock({TokenKind::SEMICOLON}); - if (statementBlock == nullptr || !statementBlock->isValid()) - return statementBlock ?: matchStatementInvalid(); + if (statementBlock == nullptr) + return nullptr; - if(!tryMatchingTokenKinds({TokenKind::SEMICOLON}, false, true)) - return matchStatementInvalid("Expected a \";\" after a function declaration"); + if(!tryMatchingTokenKinds({TokenKind::SEMICOLON}, false, true)) { + markError(TokenKind::SEMICOLON, {}); + return nullptr; + } return make_shared(name, arguments, returnType, dynamic_pointer_cast(statementBlock)); } @@ -227,16 +253,17 @@ shared_ptr Parser::matchStatementBlock(vector terminalToke while (!tryMatchingTokenKinds(terminalTokenKinds, false, false)) { shared_ptr statement = nextInBlockStatement(); - if (statement == nullptr || !statement->isValid()) - return statement ?: matchStatementInvalid("Expected statement"); - statements.push_back(statement); + if (statement != nullptr) + statements.push_back(statement); if (tryMatchingTokenKinds(terminalTokenKinds, false, false)) break; // except new line - if (!tryMatchingTokenKinds({TokenKind::NEW_LINE}, true, true)) - return matchStatementInvalid("Expected new line"); + if (statement != nullptr && !tryMatchingTokenKinds({TokenKind::NEW_LINE}, true, true)) { + markError(TokenKind::NEW_LINE, {}); + return nullptr; + } } return make_shared(statements); @@ -250,8 +277,8 @@ shared_ptr Parser::matchStatementAssignment() { currentIndex++; // arrow shared_ptr expression = nextExpression(); - if (expression == nullptr || !expression->isValid()) - return matchStatementInvalid("Expected expression"); + if (expression == nullptr) + return nullptr; return make_shared(identifierToken->getLexme(), expression); } @@ -261,8 +288,8 @@ shared_ptr Parser::matchStatementReturn() { return nullptr; shared_ptr expression = nextExpression(); - if (expression != nullptr && !expression->isValid()) - return matchStatementInvalid("Expected expression"); + if (expression == nullptr) + return nullptr; return make_shared(expression); } @@ -280,38 +307,38 @@ shared_ptr Parser::matchStatementRepeat() { // initial initStatement = matchStatementVariable() ?: matchStatementAssignment(); - if (initStatement != nullptr && !initStatement->isValid()) - initStatement = nullptr; if (!tryMatchingTokenKinds({TokenKind::COLON}, false, true)) { // got initial, expect comma - if (initStatement != nullptr && !tryMatchingTokenKinds({TokenKind::COMMA}, true, true)) - return matchStatementInvalid("Expected comma after initial statement"); + if (initStatement != nullptr && !tryMatchingTokenKinds({TokenKind::COMMA}, true, true)) { + markError(TokenKind::COMMA, {}); + return nullptr; + } // optional new line tryMatchingTokenKinds({TokenKind::NEW_LINE}, true, true); // pre condition preConditionExpression = nextExpression(); - if (preConditionExpression != nullptr && !preConditionExpression->isValid()) - return matchStatementInvalid("Expected pre-condition expression"); if (!tryMatchingTokenKinds({TokenKind::COLON}, true, true)) { // got pre-condition, expect comma - if (!tryMatchingTokenKinds({TokenKind::COMMA}, true, true)) - return matchStatementInvalid("Expected comma after pre-condition statement"); + if (!tryMatchingTokenKinds({TokenKind::COMMA}, true, true)) { + markError(TokenKind::COMMA, {}); + return nullptr; + } // optional new line tryMatchingTokenKinds({TokenKind::NEW_LINE}, true, true); // post condition postConditionExpression = nextExpression(); - if (postConditionExpression == nullptr || !postConditionExpression->isValid()) - return matchStatementInvalid("Expected post-condition expression"); // expect colon - if (!tryMatchingTokenKinds({TokenKind::COLON}, true, true)) - return matchStatementInvalid("Expected \":\""); + if (!tryMatchingTokenKinds({TokenKind::COLON}, true, true)) { + markError(TokenKind::COLON, {}); + return nullptr; + } } } @@ -323,8 +350,8 @@ shared_ptr Parser::matchStatementRepeat() { else bodyBlockStatement = matchStatementBlock({TokenKind::NEW_LINE}); - if (bodyBlockStatement == nullptr || !bodyBlockStatement->isValid()) - return bodyBlockStatement ?: matchStatementInvalid("Expected block statement"); + if (bodyBlockStatement == nullptr) + return nullptr; tryMatchingTokenKinds({TokenKind::SEMICOLON}, false, true); @@ -336,46 +363,39 @@ shared_ptr Parser::matchStatementExpression() { if (expression == nullptr) return nullptr; - else if (!expression->isValid()) - return make_shared(tokens.at(currentIndex), expression->toString(0)); - - // Consume new line - tryMatchingTokenKinds({TokenKind::NEW_LINE}, true, true); return make_shared(expression); } -shared_ptr Parser::matchStatementInvalid(string message) { - return make_shared(tokens.at(currentIndex), message); -} - // // Expression // shared_ptr Parser::nextExpression() { shared_ptr expression; + int errorsCount = errors.size(); expression = matchEquality(); - if (expression != nullptr) + if (expression != nullptr || errors.size() > errorsCount) return expression; expression = matchExpressionIfElse(); - if (expression != nullptr) + if (expression != nullptr || errors.size() > errorsCount) return expression; expression = matchExpressionVariable(); - if (expression != nullptr) + if (expression != nullptr || errors.size() > errorsCount) return expression; + markError({}, {}); return nullptr; } shared_ptr Parser::matchEquality() { shared_ptr expression = matchComparison(); - if (expression == nullptr || !expression->isValid()) - return expression; + if (expression == nullptr) + return nullptr; - while (tryMatchingTokenKinds({Token::tokensEquality}, false, false)) + if (tryMatchingTokenKinds({Token::tokensEquality}, false, false)) expression = matchExpressionBinary(expression); return expression; @@ -383,10 +403,10 @@ shared_ptr Parser::matchEquality() { shared_ptr Parser::matchComparison() { shared_ptr expression = matchTerm(); - if (expression == nullptr || !expression->isValid()) - return expression; + if (expression == nullptr) + return nullptr; - while (tryMatchingTokenKinds({Token::tokensComparison}, false, false)) + if (tryMatchingTokenKinds({Token::tokensComparison}, false, false)) expression = matchExpressionBinary(expression); return expression; @@ -394,10 +414,10 @@ shared_ptr Parser::matchComparison() { shared_ptr Parser::matchTerm() { shared_ptr expression = matchFactor(); - if (expression == nullptr || !expression->isValid()) - return expression; + if (expression == nullptr) + return nullptr; - while (tryMatchingTokenKinds({Token::tokensTerm}, false, false)) + if (tryMatchingTokenKinds({Token::tokensTerm}, false, false)) expression = matchExpressionBinary(expression); return expression; @@ -405,10 +425,10 @@ shared_ptr Parser::matchTerm() { shared_ptr Parser::matchFactor() { shared_ptr expression = matchPrimary(); - if (expression == nullptr || !expression->isValid()) - return expression; + if (expression == nullptr) + return nullptr; - while (tokens.at(currentIndex)->isOfKind(Token::tokensFactor)) + if (tokens.at(currentIndex)->isOfKind(Token::tokensFactor)) expression = matchExpressionBinary(expression); return expression; @@ -441,12 +461,12 @@ shared_ptr Parser::matchExpressionGrouping() { if (tryMatchingTokenKinds({TokenKind::LEFT_PAREN}, true, true)) { shared_ptr expression = matchTerm(); // has grouped expression failed? - if (expression == nullptr || !expression->isValid()) { - return expression ?: matchExpressionInvalid("Expected expression"); + if (expression == nullptr) { + return nullptr; } else if (tryMatchingTokenKinds({TokenKind::RIGHT_PAREN}, true, true)) { return make_shared(expression); } else { - return matchExpressionInvalid("Unexpected token"); + markError(TokenKind::RIGHT_PAREN, {}); } } @@ -484,14 +504,16 @@ shared_ptr Parser::matchExpressionCall() { tryMatchingTokenKinds({TokenKind::NEW_LINE}, true, true); // optional new line shared_ptr argumentExpression = nextExpression(); - if (argumentExpression == nullptr || !argumentExpression->isValid()) - return argumentExpression; + if (argumentExpression == nullptr) + return nullptr; argumentExpressions.push_back(argumentExpression); } while (tryMatchingTokenKinds({TokenKind::COMMA}, true, true)); tryMatchingTokenKinds({TokenKind::NEW_LINE}, true, true); // optional new line - if (!tryMatchingTokenKinds({TokenKind::RIGHT_PAREN}, true, true)) - return matchExpressionInvalid("Expected \")\""); + if (!tryMatchingTokenKinds({TokenKind::RIGHT_PAREN}, true, true)) { + markError(TokenKind::RIGHT_PAREN, {}); + return nullptr; + } return make_shared(identifierToken->getLexme(), argumentExpressions); } @@ -506,30 +528,29 @@ shared_ptr Parser::matchExpressionIfElse() { // condition expression condition = nextExpression(); - if (condition == nullptr || !condition->isValid()) - return condition ?: matchExpressionInvalid("Expected condition expression"); + if (condition == nullptr) + return nullptr; - if (!tryMatchingTokenKinds({TokenKind::COLON}, true, true)) - return matchExpressionInvalid("Expected \":\""); + if (!tryMatchingTokenKinds({TokenKind::COLON}, true, true)) { + markError(TokenKind::COLON, {}); + return nullptr; + } // then - bool isMultiLine = false; - - if (tryMatchingTokenKinds({TokenKind::NEW_LINE}, true, true)) - isMultiLine = true; + bool isMultiLine = tryMatchingTokenKinds({TokenKind::NEW_LINE}, true, true); // then block if (isMultiLine) thenBlock = matchExpressionBlock({TokenKind::ELSE, TokenKind::SEMICOLON}); else thenBlock = matchExpressionBlock({TokenKind::ELSE, TokenKind::NEW_LINE}); - if (thenBlock == nullptr || !thenBlock->isValid()) - return thenBlock ?: matchExpressionInvalid("Expected then block"); + + if (thenBlock == nullptr) + return nullptr; // else if (tryMatchingTokenKinds({TokenKind::ELSE}, true, true)) { - if (tryMatchingTokenKinds({TokenKind::NEW_LINE}, true, true)) - isMultiLine = true; + isMultiLine = (tryMatchingTokenKinds({TokenKind::NEW_LINE}, true, true)); // else block if (isMultiLine) @@ -537,8 +558,8 @@ shared_ptr Parser::matchExpressionIfElse() { else elseBlock = matchExpressionBlock({TokenKind::NEW_LINE}); - if (elseBlock == nullptr || !elseBlock->isValid()) - return elseBlock ?: matchExpressionInvalid("Expected else block"); + if (elseBlock == nullptr) + return nullptr; } tryMatchingTokenKinds({TokenKind::SEMICOLON}, false, true); @@ -560,9 +581,7 @@ shared_ptr Parser::matchExpressionBinary(shared_ptr left } if (right == nullptr) { - return matchExpressionInvalid("Expected right-side expression"); - } else if (!right->isValid()) { - return right; + return nullptr; } else { return make_shared(token, left, right); } @@ -575,18 +594,23 @@ shared_ptr Parser::matchExpressionBlock(vector terminalTo while (!tryMatchingTokenKinds(terminalTokenKinds, false, false)) { shared_ptr statement = nextInBlockStatement(); - if (statement == nullptr || !statement->isValid()) - return matchExpressionInvalid("Expected statement"); - statements.push_back(statement); + + if (statement != nullptr) + statements.push_back(statement); + + if (tryMatchingTokenKinds(terminalTokenKinds, false, false)) + break; + + // except new line + if (statement != nullptr && !tryMatchingTokenKinds({TokenKind::NEW_LINE}, true, true)) { + markError(TokenKind::NEW_LINE, {}); + return nullptr; + } } return make_shared(statements); } -shared_ptr Parser::matchExpressionInvalid(string message) { - return make_shared(tokens.at(currentIndex)); -} - bool Parser::tryMatchingTokenKinds(vector kinds, bool shouldMatchAll, bool shouldAdvance) { int requiredCount = shouldMatchAll ? kinds.size() : 1; if (currentIndex + requiredCount > tokens.size()) @@ -628,3 +652,19 @@ optional Parser::valueTypeForToken(shared_ptr token) { return {}; } + +void Parser::markError(optional expectedTokenKind, optional message) { + shared_ptr actualToken = tokens.at(currentIndex); + + // Try reaching the next safe token + vector safeKinds = {TokenKind::END}; + if (!actualToken->isOfKind({TokenKind::NEW_LINE})) + safeKinds.push_back(TokenKind::NEW_LINE); + if (!actualToken->isOfKind({TokenKind::SEMICOLON})) + safeKinds.push_back(TokenKind::SEMICOLON); + + while (!tryMatchingTokenKinds(safeKinds, false, true)) + currentIndex++; + + errors.push_back(make_shared(actualToken, expectedTokenKind, message)); +} diff --git a/src/Parser/Parser.h b/src/Parser/Parser.h index 6ff976f..dd9cc58 100644 --- a/src/Parser/Parser.h +++ b/src/Parser/Parser.h @@ -2,14 +2,14 @@ #define PARSER_H #include +#include "Types.h" -#include "Lexer/Token.h" +class Token; +enum class TokenKind; +class Error; class Expression; -class ExpressionInvalid; - class Statement; -class StatementInvalid; using namespace std; @@ -17,6 +17,7 @@ class Parser { private: vector> tokens; int currentIndex = 0; + vector> errors; shared_ptr nextStatement(); shared_ptr nextInBlockStatement(); @@ -30,7 +31,6 @@ private: shared_ptr matchStatementReturn(); shared_ptr matchStatementRepeat(); shared_ptr matchStatementExpression(); - shared_ptr matchStatementInvalid(string message = ""); shared_ptr nextExpression(); shared_ptr matchEquality(); // =, != @@ -46,11 +46,12 @@ private: shared_ptr matchExpressionIfElse(); shared_ptr matchExpressionBinary(shared_ptr left); shared_ptr matchExpressionBlock(vector terminalTokenKinds); - shared_ptr matchExpressionInvalid(string message); bool tryMatchingTokenKinds(vector kinds, bool shouldMatchAll, bool shouldAdvance); optional valueTypeForToken(shared_ptr token); + void markError(optional expectedTokenKind, optional message); + public: Parser(vector> tokens); vector> getStatements(); diff --git a/src/Parser/Statement/Statement.cpp b/src/Parser/Statement/Statement.cpp index ed664f8..eb807db 100644 --- a/src/Parser/Statement/Statement.cpp +++ b/src/Parser/Statement/Statement.cpp @@ -6,11 +6,3 @@ kind(kind) { } StatementKind Statement::getKind() { return kind; } - -bool Statement::isValid() { - return kind != StatementKind::INVALID; -} - -string Statement::toString(int indent) { - return "STATEMENT"; -} diff --git a/src/Parser/Statement/Statement.h b/src/Parser/Statement/Statement.h index 4c6289d..f1e9b29 100644 --- a/src/Parser/Statement/Statement.h +++ b/src/Parser/Statement/Statement.h @@ -15,8 +15,7 @@ enum class StatementKind { VARIABLE, ASSIGNMENT, REPEAT, - META_EXTERN_FUNCTION, - INVALID + META_EXTERN_FUNCTION }; class Statement { @@ -25,9 +24,8 @@ private: public: Statement(StatementKind kind); + virtual ~Statement() { } StatementKind getKind(); - bool isValid(); - virtual string toString(int indent); }; #endif \ No newline at end of file diff --git a/src/Parser/Statement/StatementBlock.cpp b/src/Parser/Statement/StatementBlock.cpp index 3c8839b..ae409d0 100644 --- a/src/Parser/Statement/StatementBlock.cpp +++ b/src/Parser/Statement/StatementBlock.cpp @@ -8,16 +8,3 @@ Statement(StatementKind::BLOCK), statements(statements) { } vector> StatementBlock::getStatements() { return statements; } - -string StatementBlock::toString(int indent) { - string value; - for (int i=0; itoString(indent); - } - for (int ind=0; ind> statements); vector> getStatements(); - string toString(int indent) override; }; \ No newline at end of file diff --git a/src/Parser/Statement/StatementExpression.cpp b/src/Parser/Statement/StatementExpression.cpp index d1415be..fb5b481 100644 --- a/src/Parser/Statement/StatementExpression.cpp +++ b/src/Parser/Statement/StatementExpression.cpp @@ -8,12 +8,3 @@ Statement(StatementKind::EXPRESSION), expression(expression) { } shared_ptr StatementExpression::getExpression() { return expression; } - -string StatementExpression::toString(int indent) { - string value; - for (int ind=0; indtoString(indent); - value += "\n"; - return value; -} \ No newline at end of file diff --git a/src/Parser/Statement/StatementExpression.h b/src/Parser/Statement/StatementExpression.h index c38dd75..bc97e3a 100644 --- a/src/Parser/Statement/StatementExpression.h +++ b/src/Parser/Statement/StatementExpression.h @@ -9,5 +9,4 @@ private: public: StatementExpression(shared_ptr expression); shared_ptr getExpression(); - string toString(int indent) override; }; \ No newline at end of file diff --git a/src/Parser/Statement/StatementFunction.cpp b/src/Parser/Statement/StatementFunction.cpp index d6a6f9f..df5b24f 100644 --- a/src/Parser/Statement/StatementFunction.cpp +++ b/src/Parser/Statement/StatementFunction.cpp @@ -43,17 +43,3 @@ ValueType StatementFunction::getReturnValueType() { shared_ptr StatementFunction::getStatementBlock() { return statementBlock; } - -string StatementFunction::toString(int indent) { - string value = ""; - for (int ind=0; indtoString(indent+1); - for (int ind=0; ind> getArguments(); ValueType getReturnValueType(); shared_ptr getStatementBlock(); - string toString(int indent) override; }; \ No newline at end of file diff --git a/src/Parser/Statement/StatementInvalid.cpp b/src/Parser/Statement/StatementInvalid.cpp deleted file mode 100644 index 324e8d6..0000000 --- a/src/Parser/Statement/StatementInvalid.cpp +++ /dev/null @@ -1,14 +0,0 @@ -#include "Parser/Statement/StatementInvalid.h" - -#include "Lexer/Token.h" - -StatementInvalid::StatementInvalid(shared_ptr token, string message): -Statement(StatementKind::INVALID), token(token), message(message) { } - -string StatementInvalid::toString(int indent) { - return "Error for token " + token->toString() + " at " + to_string(token->getLine()) + ":" + to_string(token->getColumn()) + ": " + message + "\n"; -} - -string StatementInvalid::getMessage() { - return message; -} \ No newline at end of file diff --git a/src/Parser/Statement/StatementInvalid.h b/src/Parser/Statement/StatementInvalid.h deleted file mode 100644 index c917de7..0000000 --- a/src/Parser/Statement/StatementInvalid.h +++ /dev/null @@ -1,14 +0,0 @@ -#include "Parser/Statement/Statement.h" - -class Token; - -class StatementInvalid: public Statement { -private: - shared_ptr token; - string message; - -public: - StatementInvalid(shared_ptr token, string message); - string toString(int indent) override; - string getMessage(); -}; diff --git a/src/Parser/Statement/StatementMetaExternFunction.cpp b/src/Parser/Statement/StatementMetaExternFunction.cpp index ea09299..6285def 100644 --- a/src/Parser/Statement/StatementMetaExternFunction.cpp +++ b/src/Parser/Statement/StatementMetaExternFunction.cpp @@ -27,14 +27,3 @@ vector> StatementMetaExternFunction::getArguments() { ValueType StatementMetaExternFunction::getReturnValueType() { return returnValueType; } - -string StatementMetaExternFunction::toString(int indent) { - string value; - for (int ind=0; ind> getArguments(); ValueType getReturnValueType(); - string toString(int indent) override; }; \ No newline at end of file diff --git a/src/Parser/Statement/StatementRepeat.cpp b/src/Parser/Statement/StatementRepeat.cpp index 6f52ed9..8299466 100644 --- a/src/Parser/Statement/StatementRepeat.cpp +++ b/src/Parser/Statement/StatementRepeat.cpp @@ -21,19 +21,3 @@ shared_ptr StatementRepeat::getPostConditionExpression() { shared_ptr StatementRepeat::getBodyBlockStatement() { return bodyBlockStatement; } - -string StatementRepeat::toString(int indent) { - string value; - for (int ind=0; indtoString(0), ", "; - if (preConditionExpression != nullptr) - value += preConditionExpression->toString(0) + ", "; - if (postConditionExpression != nullptr) - value += postConditionExpression->toString(0); - value += "):\n"; - value += bodyBlockStatement->toString(indent+1); - return value; -} \ No newline at end of file diff --git a/src/Parser/Statement/StatementRepeat.h b/src/Parser/Statement/StatementRepeat.h index 399a8c8..c85de7d 100644 --- a/src/Parser/Statement/StatementRepeat.h +++ b/src/Parser/Statement/StatementRepeat.h @@ -16,5 +16,4 @@ public: shared_ptr getPreConditionExpression(); shared_ptr getPostConditionExpression(); shared_ptr getBodyBlockStatement(); - string toString(int indent) override; }; \ No newline at end of file diff --git a/src/Parser/Statement/StatementReturn.cpp b/src/Parser/Statement/StatementReturn.cpp index ce83b08..609db65 100644 --- a/src/Parser/Statement/StatementReturn.cpp +++ b/src/Parser/Statement/StatementReturn.cpp @@ -8,18 +8,3 @@ Statement(StatementKind::RETURN), expression(expression) { } shared_ptr StatementReturn::getExpression() { return expression; } - -string StatementReturn::toString(int indent) { - string value; - for (int ind=0; indtoString(indent+1); - } - value += "\n"; - return value; -} \ No newline at end of file diff --git a/src/Parser/Statement/StatementReturn.h b/src/Parser/Statement/StatementReturn.h index 73160a5..fca4ffe 100644 --- a/src/Parser/Statement/StatementReturn.h +++ b/src/Parser/Statement/StatementReturn.h @@ -9,5 +9,4 @@ private: public: StatementReturn(shared_ptr expression); shared_ptr getExpression(); - string toString(int indent) override; }; \ No newline at end of file diff --git a/src/Parser/Statement/StatementVariable.cpp b/src/Parser/Statement/StatementVariable.cpp index a6353ac..c188af3 100644 --- a/src/Parser/Statement/StatementVariable.cpp +++ b/src/Parser/Statement/StatementVariable.cpp @@ -29,17 +29,3 @@ ValueType StatementVariable::getValueType() { shared_ptr StatementVariable::getExpression() { return expression; } - -string StatementVariable::toString(int indent) { - string value; - for (int ind=0; indtoString(indent+1); - value += "\n"; - return value; -} \ No newline at end of file diff --git a/src/Parser/Statement/StatementVariable.h b/src/Parser/Statement/StatementVariable.h index dc98b7d..5e3b7c0 100644 --- a/src/Parser/Statement/StatementVariable.h +++ b/src/Parser/Statement/StatementVariable.h @@ -13,5 +13,4 @@ public: string getName(); ValueType getValueType(); shared_ptr getExpression(); - string toString(int indent) override; }; \ No newline at end of file diff --git a/src/main.cpp b/src/main.cpp index df6119c..bbc238d 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -13,6 +13,7 @@ #include "Compiler/ModuleBuilder.h" #include "Compiler/CodeGenerator.h" +#include "Logger.h" using namespace std; @@ -56,22 +57,15 @@ int main(int argc, char **argv) { Lexer lexer(source); vector> tokens = lexer.getTokens(); if (isVerbose) { - for (int i=0; itoString(); - if (i < tokens.size() - 1) - cout << ", "; - } - cout << endl << endl; + Logger::print(tokens); + cout << endl; } Parser parser(tokens); vector> statements = parser.getStatements(); if (isVerbose) { - for (shared_ptr &statement : statements) { - cout << statement->toString(0); - cout << endl; - } - cout << endl << endl; + Logger::print(statements); + cout << endl; } ModuleBuilder moduleBuilder(moduleName, inputFilePath, statements); diff --git a/test.brc b/test.brc deleted file mode 100644 index 7ae6cd8..0000000 --- a/test.brc +++ /dev/null @@ -1,7 +0,0 @@ -//dummy sint32 <- 55 -stuff fun: num1 sint32, num2 sint32 -> sint32 - rep: - i <- i + 1 - ; - ret 42 -; \ No newline at end of file