diff --git a/.gitignore b/.gitignore index 57b7346..0f82e52 100644 --- a/.gitignore +++ b/.gitignore @@ -3,5 +3,4 @@ brb .vscode/settings.json *.dSYM -*.brc build/ \ No newline at end of file diff --git a/samples/fib.brc b/samples/fib.brc new file mode 100644 index 0000000..11fd516 --- /dev/null +++ b/samples/fib.brc @@ -0,0 +1,34 @@ +@extern putchar fun: character sint32 -> sint32 + +fib fun: number sint32 -> sint32 + ret if number < 2: + number + else + fib(number - 1) + fib(number - 2) + ; +; + +printNum fun: number sint32 + biggest sint32 <- 10 + rep biggest <= number: biggest <- biggest * 10 + biggest <- biggest / 10 + + rep biggest > 0: + digit sint32 <- number / biggest + putchar(digit + '0') + number <- number % biggest + biggest <- biggest / 10 + ; +; + +// Print first 20 fibonaci numbers +main fun -> sint32 + rep i sint32 <- 0, i < 20: + res sint32 <- fib(i) + printNum(res) + putchar('\n') + i <- i + 1 + ; + + ret 0 +; \ No newline at end of file diff --git a/src/Compiler/ModuleBuilder.cpp b/src/Compiler/ModuleBuilder.cpp index eaebd4b..5777fe5 100644 --- a/src/Compiler/ModuleBuilder.cpp +++ b/src/Compiler/ModuleBuilder.cpp @@ -1,5 +1,7 @@ #include "ModuleBuilder.h" +#include "Error.h" +#include "Logger.h" #include "Parser/ValueType.h" #include "Parser/Expression/ExpressionGrouping.h" @@ -33,9 +35,16 @@ moduleName(moduleName), sourceFileName(sourceFileName), statements(statements) { } shared_ptr ModuleBuilder::getModule() { - for (shared_ptr &statement : statements) { + scopes.push(Scope()); + for (shared_ptr &statement : statements) buildStatement(statement); + + if (!errors.empty()) { + for (shared_ptr &error : errors) + Logger::print(error); + exit(1); } + return module; } @@ -66,7 +75,7 @@ void ModuleBuilder::buildStatement(shared_ptr statement) { buildExpression(dynamic_pointer_cast(statement)); return; default: - failWithMessage("Unexpected statement"); + markError(0, 0, "Unexpected statement"); } } @@ -80,12 +89,15 @@ void ModuleBuilder::buildFunctionDeclaration(shared_ptr state // build function declaration llvm::FunctionType *funType = llvm::FunctionType::get(typeForValueType(statement->getReturnValueType()), types, false); llvm::Function *fun = llvm::Function::Create(funType, llvm::GlobalValue::ExternalLinkage, statement->getName(), module.get()); - funMap[statement->getName()] = fun; + if (!setFun(statement->getName(), fun)) + return; // define function body llvm::BasicBlock *block = llvm::BasicBlock::Create(*context, statement->getName(), fun); builder->SetInsertPoint(block); + scopes.push(Scope()); + // build arguments int i=0; for (auto &arg : fun->args()) { @@ -94,7 +106,8 @@ void ModuleBuilder::buildFunctionDeclaration(shared_ptr state arg.setName(name); llvm::AllocaInst *alloca = builder->CreateAlloca(type, nullptr, name); - allocaMap[name] = alloca; + if (!setAlloca(name, alloca)) + return; builder->CreateStore(&arg, alloca); i++; @@ -103,24 +116,28 @@ void ModuleBuilder::buildFunctionDeclaration(shared_ptr state // build function body buildStatement(statement->getStatementBlock()); + scopes.pop(); + // verify string errorMessage; llvm::raw_string_ostream llvmErrorMessage(errorMessage); if (llvm::verifyFunction(*fun, &llvmErrorMessage)) - failWithMessage(errorMessage); + markError(0, 0, errorMessage); } void ModuleBuilder::buildVarDeclaration(shared_ptr statement) { llvm::Value *value = valueForExpression(statement->getExpression()); llvm::AllocaInst *alloca = builder->CreateAlloca(typeForValueType(statement->getValueType()), nullptr, statement->getName()); - allocaMap[statement->getName()] = alloca; + + if (!setAlloca(statement->getName(), alloca)) + return; builder->CreateStore(value, alloca); } void ModuleBuilder::buildAssignment(shared_ptr statement) { - llvm::AllocaInst *alloca = allocaMap[statement->getName()]; + llvm::AllocaInst *alloca = getAlloca(statement->getName()); if (alloca == nullptr) - failWithMessage("Variable " + statement->getName() + " not defined"); + return; llvm::Value *value = valueForExpression(statement->getExpression()); builder->CreateStore(value, alloca); @@ -151,6 +168,8 @@ void ModuleBuilder::buildLoop(shared_ptr statement) { llvm::BasicBlock *bodyBlock = llvm::BasicBlock::Create(*context, "loopBody"); llvm::BasicBlock *afterBlock = llvm::BasicBlock::Create(*context, "loopPost"); + scopes.push(Scope()); + // loop init if (initStatement != nullptr) buildStatement(statement->getInitStatement()); @@ -181,6 +200,8 @@ void ModuleBuilder::buildLoop(shared_ptr statement) { // loop post fun->insert(fun->end(), afterBlock); builder->SetInsertPoint(afterBlock); + + scopes.pop(); } void ModuleBuilder::buildMetaExternFunction(shared_ptr statement) { @@ -193,7 +214,8 @@ void ModuleBuilder::buildMetaExternFunction(shared_ptrgetReturnValueType()), types, false); llvm::Function *fun = llvm::Function::Create(funType, llvm::GlobalValue::ExternalLinkage, statement->getName(), module.get()); - funMap[statement->getName()] = fun; + if (!setFun(statement->getName(), fun)) + return; // build arguments int i=0; @@ -223,11 +245,15 @@ llvm::Value *ModuleBuilder::valueForExpression(shared_ptr expression case ExpressionKind::CALL: return valueForCall(dynamic_pointer_cast(expression)); default: - failWithMessage("Unexpected expression"); + markError(0, 0, "Unexpected expression"); + return nullptr; } } llvm::Value *ModuleBuilder::valueForLiteral(shared_ptr expression) { + if (expression->getValueType() == nullptr) + return llvm::UndefValue::get(typeVoid); + switch (expression->getValueType()->getKind()) { case ValueTypeKind::NONE: return llvm::UndefValue::get(typeVoid); @@ -258,7 +284,8 @@ llvm::Value *ModuleBuilder::valueForBinary(shared_ptr expressi return valueForBinaryReal(expression->getOperation(), leftValue, rightValue); } - failWithMessage("Unexpected operation"); + markError(0, 0, "Unexpected operation"); + return nullptr; } llvm::Value *ModuleBuilder::valueForBinaryBool(ExpressionBinaryOperation operation, llvm::Value *leftValue, llvm::Value *rightValue) { @@ -268,7 +295,8 @@ llvm::Value *ModuleBuilder::valueForBinaryBool(ExpressionBinaryOperation operati case ExpressionBinaryOperation::NOT_EQUAL: return builder->CreateICmpNE(leftValue, rightValue); default: - failWithMessage("Undefined operation for boolean operands"); + markError(0, 0, "Unexpecgted operation for boolean operands"); + return nullptr; } } @@ -340,13 +368,16 @@ llvm::Value *ModuleBuilder::valueForIfElse(shared_ptr expressi builder->CreateCondBr(conditionValue, thenBlock, elseBlock); // Then + scopes.push(Scope()); builder->SetInsertPoint(thenBlock); buildStatement(expression->getThenBlock()->getStatementBlock()); llvm::Value *thenValue = valueForExpression(expression->getThenBlock()->getResultStatementExpression()->getExpression()); builder->CreateBr(mergeBlock); thenBlock = builder->GetInsertBlock(); + scopes.pop(); // Else + scopes.push(Scope()); fun->insert(fun->end(), elseBlock); builder->SetInsertPoint(elseBlock); llvm::Value *elseValue = nullptr; @@ -357,6 +388,7 @@ llvm::Value *ModuleBuilder::valueForIfElse(shared_ptr expressi } builder->CreateBr(mergeBlock); elseBlock = builder->GetInsertBlock(); + scopes.pop(); // Merge fun->insert(fun->end(), mergeBlock); @@ -375,17 +407,17 @@ llvm::Value *ModuleBuilder::valueForIfElse(shared_ptr expressi } llvm::Value *ModuleBuilder::valueForVar(shared_ptr expression) { - llvm::AllocaInst *alloca = allocaMap[expression->getName()]; + llvm::AllocaInst *alloca = getAlloca(expression->getName()); if (alloca == nullptr) - failWithMessage("Variable " + expression->getName() + " not defined"); + return nullptr; return builder->CreateLoad(alloca->getAllocatedType(), alloca, expression->getName()); } llvm::Value *ModuleBuilder::valueForCall(shared_ptr expression) { - llvm::Function *fun = funMap[expression->getName()]; + llvm::Function *fun = getFun(expression->getName()); if (fun == nullptr) - failWithMessage("Function " + expression->getName() + " not defined"); + return nullptr; llvm::FunctionType *funType = fun->getFunctionType(); vector argValues; for (shared_ptr &argumentExpression : expression->getArgumentExpressions()) { @@ -395,6 +427,54 @@ llvm::Value *ModuleBuilder::valueForCall(shared_ptr expression) return builder->CreateCall(funType, fun, llvm::ArrayRef(argValues)); } +bool ModuleBuilder::setAlloca(string name, llvm::AllocaInst *alloca) { + if (scopes.top().allocaMap[name] != nullptr) { + markError(0, 0, format("Variable \"{}\" already defined", name)); + return false; + } + + scopes.top().allocaMap[name] = alloca; + return true; +} + +llvm::AllocaInst* ModuleBuilder::getAlloca(string name) { + stack scopes = this->scopes; + + while (!scopes.empty()) { + llvm::AllocaInst *alloca = scopes.top().allocaMap[name]; + if (alloca != nullptr) + return alloca; + scopes.pop(); + } + + markError(0, 0, format("Variable \"{}\" not defined in scope", name)); + return nullptr; +} + +bool ModuleBuilder::setFun(string name, llvm::Function *fun) { + if (scopes.top().funMap[name] != nullptr) { + markError(0, 0, format("Function \"{}\" already defined", name)); + return false; + } + + scopes.top().funMap[name] = fun; + return true; +} + +llvm::Function* ModuleBuilder::getFun(string name) { + stack scopes = this->scopes; + + while (!scopes.empty()) { + llvm::Function *fun = scopes.top().funMap[name]; + if (fun != nullptr) + return fun; + scopes.pop(); + } + + markError(0, 0, format("Function \"{}\" not defined in scope", name)); + return nullptr; +} + llvm::Type *ModuleBuilder::typeForValueType(shared_ptr valueType) { switch (valueType->getKind()) { case ValueTypeKind::NONE: @@ -408,7 +488,6 @@ llvm::Type *ModuleBuilder::typeForValueType(shared_ptr valueType) { } } -void ModuleBuilder::failWithMessage(string message) { - cerr << "Error! Building module \"" << moduleName << "\" from \"" + sourceFileName + "\" failed:" << endl << message << endl; - exit(1); +void ModuleBuilder::markError(int line, int column, string message) { + errors.push_back(Error::builderError(line, column, message)); } diff --git a/src/Compiler/ModuleBuilder.h b/src/Compiler/ModuleBuilder.h index 1850951..ddc70df 100644 --- a/src/Compiler/ModuleBuilder.h +++ b/src/Compiler/ModuleBuilder.h @@ -2,6 +2,7 @@ #define MODULE_BUILDER_H #include +#include #include #include @@ -10,6 +11,7 @@ #include #include +class Error; class ValueType; class Expression; @@ -33,8 +35,14 @@ class StatementBlock; using namespace std; +typedef struct { + map allocaMap; + map funMap; +} Scope; + class ModuleBuilder { private: + vector> errors; string moduleName; string sourceFileName; @@ -48,8 +56,7 @@ private: llvm::Type *typeReal32; vector> statements; - map allocaMap; - map funMap; + stack scopes; void buildStatement(shared_ptr statement); void buildFunctionDeclaration(shared_ptr statement); @@ -72,8 +79,15 @@ private: llvm::Value *valueForVar(shared_ptr expression); llvm::Value *valueForCall(shared_ptr expression); + bool setAlloca(string name, llvm::AllocaInst *alloca); + llvm::AllocaInst *getAlloca(string name); + + bool setFun(string name, llvm::Function *fun); + llvm::Function *getFun(string name); + llvm::Type *typeForValueType(shared_ptr valueType); - void failWithMessage(string message); + + void markError(int line, int column, string message); public: ModuleBuilder(string moduleName, string sourceFileName, vector> statements); diff --git a/src/Error.cpp b/src/Error.cpp index a4f5b06..3078e95 100644 --- a/src/Error.cpp +++ b/src/Error.cpp @@ -1,10 +1,43 @@ #include "Error.h" -Error::Error(int line, int column, string lexme) : -kind(ErrorKind::LEXER_ERROR), line(line), column(column), lexme(lexme) { } +shared_ptr Error::lexerError(int line, int column, string lexme) { + return make_shared( + ErrorKind::LEXER_ERROR, + line, + column, + lexme, + nullptr, + optional(), + optional() + ); +} -Error::Error(shared_ptr actualToken, optional expectedTokenKind, optional message) : -kind(ErrorKind::PARSER_ERROR), actualToken(actualToken), expectedTokenKind(expectedTokenKind), message(message) { } +shared_ptr Error::parserError(shared_ptr actualToken, optional expectedTokenKind, optional message) { + return make_shared( + ErrorKind::PARSER_ERROR, + 0, + 0, + optional(), + actualToken, + expectedTokenKind, + message + ); +} + +shared_ptr Error::builderError(int line, int column, string message) { + return make_shared( + ErrorKind::BUILDER_ERROR, + line, + column, + optional(), + nullptr, + optional(), + message + ); +} + +Error::Error(ErrorKind kind, int line, int column, optional lexme, shared_ptr actualToken, optional expectedTokenKind, optional message): +kind(kind), line(line), column(column), lexme(lexme), actualToken(actualToken), expectedTokenKind(expectedTokenKind), message(message) { } ErrorKind Error::getKind() { return kind; @@ -18,7 +51,7 @@ int Error::getColumn() { return column; } -string Error::getLexme() { +optional Error::getLexme() { return lexme; } diff --git a/src/Error.h b/src/Error.h index 97dc968..4e83c68 100644 --- a/src/Error.h +++ b/src/Error.h @@ -10,7 +10,8 @@ using namespace std; enum class ErrorKind { LEXER_ERROR, - PARSER_ERROR + PARSER_ERROR, + BUILDER_ERROR }; class Error { @@ -19,21 +20,24 @@ private: int line; int column; - string lexme; + optional lexme; shared_ptr actualToken; optional expectedTokenKind; optional message; public: - Error(int line, int column, string lexme); - Error(shared_ptr actualToken, optional expectedTokenKind, optional message); + static shared_ptr lexerError(int line, int column, string lexme); + static shared_ptr parserError(shared_ptr actualToken, optional expectedTokenKind, optional message); + static shared_ptr builderError(int line, int column, string message); + + Error(ErrorKind kind, int line, int column, optional lexme, shared_ptr actualToken, optional expectedTokenKind, optional message); ErrorKind getKind(); int getLine(); int getColumn(); - string getLexme(); + optional getLexme(); shared_ptr getActualToken(); optional getExpectedTokenKind(); diff --git a/src/Lexer/Lexer.cpp b/src/Lexer/Lexer.cpp index e90acb5..8d4ec3a 100644 --- a/src/Lexer/Lexer.cpp +++ b/src/Lexer/Lexer.cpp @@ -1,9 +1,10 @@ #include "Lexer.h" -#include "Token.h" #include "Error.h" #include "Logger.h" +#include "Token.h" + Lexer::Lexer(string source): source(source) { } @@ -506,5 +507,5 @@ void Lexer::markError() { } else { lexme = "EOF"; } - errors.push_back(make_shared(currentLine, startColumn, lexme)); + errors.push_back(Error::lexerError(currentLine, startColumn, lexme)); } diff --git a/src/Logger.cpp b/src/Logger.cpp index f2d7727..b776a35 100644 --- a/src/Logger.cpp +++ b/src/Logger.cpp @@ -2,6 +2,8 @@ #include +#include "Error.h" + #include "Lexer/Token.h" #include "Parser/ValueType.h" @@ -24,8 +26,6 @@ #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: @@ -367,6 +367,9 @@ string Logger::toString(shared_ptr expression) { } string Logger::toString(shared_ptr expression) { + if (expression->getValueType() == nullptr) + return "?"; + switch (expression->getValueType()->getKind()) { case ValueTypeKind::NONE: return "NONE"; @@ -392,6 +395,8 @@ string Logger::toString(shared_ptr expression) { string Logger::toString(shared_ptr expression) { string text; text += toString(expression->getStatementBlock()); + if (!text.empty()) + text += '\n'; if (expression->getResultStatementExpression() != nullptr) text += toString(expression->getResultStatementExpression()); return text; @@ -416,10 +421,12 @@ void Logger::print(vector> statements) { 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); + case ErrorKind::LEXER_ERROR: { + string lexme = error->getLexme() ? *(error->getLexme()) : ""; + message = format("Unexpected token \"{}\" at line: {}, column: {}", lexme, error->getLine() + 1, error->getColumn() + 1); break; - case ErrorKind::PARSER_ERROR: + } + case ErrorKind::PARSER_ERROR: { shared_ptr token = error->getActualToken(); optional expectedTokenKind = error->getExpectedTokenKind(); optional errorMessage = error->getMessage(); @@ -438,6 +445,12 @@ void Logger::print(shared_ptr error) { if (errorMessage) message += format(". {}", *errorMessage); break; + } + case ErrorKind::BUILDER_ERROR: { + string errorMessage = error->getMessage() ? *(error->getMessage()) : ""; + message = format("Error at line {}, column {}: {}", error->getLine(), error->getColumn(), errorMessage); + break; + } } cout << message << endl; } \ No newline at end of file diff --git a/src/Parser/Expression/ExpressionBinary.cpp b/src/Parser/Expression/ExpressionBinary.cpp index aa162fe..4530801 100644 --- a/src/Parser/Expression/ExpressionBinary.cpp +++ b/src/Parser/Expression/ExpressionBinary.cpp @@ -54,13 +54,15 @@ Expression(ExpressionKind::BINARY, nullptr), operation(ExpressionBinaryOperation break; } - // Types must match - if (left->getValueType() != right->getValueType()) - valueType = ValueType::NONE; + if (left->getValueType() != nullptr && right->getValueType() != nullptr) { + // Types must match + if (left->getValueType() != right->getValueType()) + valueType = ValueType::NONE; - // Booleans can only do = or != - if (valueType->getKind() == ValueTypeKind::BOOL && (token->getKind() != TokenKind::EQUAL || token->getKind() != TokenKind::NOT_EQUAL)) - valueType = ValueType::NONE; + // Booleans can only do = or != + if (valueType->getKind() == ValueTypeKind::BOOL && (token->getKind() != TokenKind::EQUAL || token->getKind() != TokenKind::NOT_EQUAL)) + valueType = ValueType::NONE; + } } ExpressionBinaryOperation ExpressionBinary::getOperation() { diff --git a/src/Parser/Parser.cpp b/src/Parser/Parser.cpp index 402f882..979b15c 100644 --- a/src/Parser/Parser.cpp +++ b/src/Parser/Parser.cpp @@ -501,19 +501,21 @@ shared_ptr Parser::matchExpressionCall() { currentIndex++; // left parenthesis vector> argumentExpressions; - do { - tryMatchingTokenKinds({TokenKind::NEW_LINE}, true, true); // optional new line - - shared_ptr argumentExpression = nextExpression(); - 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)) { - markError(TokenKind::RIGHT_PAREN, {}); - return nullptr; + do { + tryMatchingTokenKinds({TokenKind::NEW_LINE}, true, true); // optional new line + + shared_ptr argumentExpression = nextExpression(); + 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)) { + markError(TokenKind::RIGHT_PAREN, {}); + return nullptr; + } } return make_shared(identifierToken->getLexme(), argumentExpressions); @@ -653,5 +655,5 @@ void Parser::markError(optional expectedTokenKind, optional m while (!tryMatchingTokenKinds(safeKinds, false, true)) currentIndex++; - errors.push_back(make_shared(actualToken, expectedTokenKind, message)); + errors.push_back(Error::parserError(actualToken, expectedTokenKind, message)); } diff --git a/src/Parser/Parser.h b/src/Parser/Parser.h index 1d6533c..79dddee 100644 --- a/src/Parser/Parser.h +++ b/src/Parser/Parser.h @@ -14,9 +14,9 @@ using namespace std; class Parser { private: + vector> errors; vector> tokens; int currentIndex = 0; - vector> errors; shared_ptr nextStatement(); shared_ptr nextInBlockStatement();