From c47889a4fff75d37be26af66c76aec4c3c3b5ccd Mon Sep 17 00:00:00 2001 From: Pasha Bibko <156938226+PashaBibko@users.noreply.github.com> Date: Sat, 10 May 2025 15:09:50 +0100 Subject: [PATCH] Function parameters can now be read --- IR-Generator/inc/Parser.h | 8 ++- Parser/Parser.vcxproj | 2 + Parser/Parser.vcxproj.filters | 6 ++ Parser/inc/AST.h | 16 +++--- Parser/inc/Scope.h | 104 ++++++++++++++++++++++++++++++++++ Parser/src/AST/AST-LLVM.cpp | 28 ++++----- Parser/src/GenIR.cpp | 18 +++--- Parser/src/Scope.cpp | 17 ++++++ 8 files changed, 168 insertions(+), 31 deletions(-) create mode 100644 Parser/inc/Scope.h create mode 100644 Parser/src/Scope.cpp diff --git a/IR-Generator/inc/Parser.h b/IR-Generator/inc/Parser.h index b58ddf6..9c9a361 100644 --- a/IR-Generator/inc/Parser.h +++ b/IR-Generator/inc/Parser.h @@ -6,7 +6,11 @@ #include // Foward declares the wrapper around the LLVM objects we need to pass around // -namespace LX { struct InfoLLVM; } +namespace LX +{ + struct InfoLLVM; + class FunctionScope; +} // The nodes of the abstract syntax tree constructed by the parser from the tokens // namespace LX::AST @@ -48,7 +52,7 @@ namespace LX::AST virtual ~Node() = default; // Function for generating LLVN IR (Intermediate representation) // - virtual llvm::Value* GenIR(InfoLLVM& LLVM) = 0; + virtual llvm::Value* GenIR(InfoLLVM& LLVM, FunctionScope& func) = 0; // Function to log the node to a file // virtual void Log(unsigned depth) = 0; diff --git a/Parser/Parser.vcxproj b/Parser/Parser.vcxproj index 7bd6eb5..e986e31 100644 --- a/Parser/Parser.vcxproj +++ b/Parser/Parser.vcxproj @@ -153,11 +153,13 @@ + + diff --git a/Parser/Parser.vcxproj.filters b/Parser/Parser.vcxproj.filters index a80584e..691863b 100644 --- a/Parser/Parser.vcxproj.filters +++ b/Parser/Parser.vcxproj.filters @@ -35,6 +35,9 @@ Source Files\AST + + Source Files + @@ -46,5 +49,8 @@ Header Files + + Header Files + \ No newline at end of file diff --git a/Parser/inc/AST.h b/Parser/inc/AST.h index b86a32b..b919755 100644 --- a/Parser/inc/AST.h +++ b/Parser/inc/AST.h @@ -1,3 +1,5 @@ +#pragma once + #include #include @@ -25,7 +27,7 @@ namespace LX::AST MultiNode(); // Function for generating LLVM IR (Intermediate representation), will throw error if called on this class // - llvm::Value* GenIR(InfoLLVM& LLVM) override; + llvm::Value* GenIR(InfoLLVM& LLVM, FunctionScope& func) override; // Function to log the node to a file, will throw an error if called on this class // void Log(unsigned depth) override; @@ -42,7 +44,7 @@ namespace LX::AST NumberLiteral(std::string num); // Function for generating LLVM IR (Intermediate representation) // - llvm::Value* GenIR(InfoLLVM& LLVM) override; + llvm::Value* GenIR(InfoLLVM& LLVM, FunctionScope& func) override; // Function to log the node to a file // void Log(unsigned depth) override; @@ -61,7 +63,7 @@ namespace LX::AST Operation(std::unique_ptr lhs, Token::TokenType op, std::unique_ptr rhs); // Function for generating LLVM IR (Intermediate representation) // - llvm::Value* GenIR(InfoLLVM& LLVM) override; + llvm::Value* GenIR(InfoLLVM& LLVM, FunctionScope& func) override; // Function to log the node to a file // void Log(unsigned depth) override; @@ -83,7 +85,7 @@ namespace LX::AST ReturnStatement(std::unique_ptr val); // Function for generating LLVM IR (Intermediate representation) // - llvm::Value* GenIR(InfoLLVM& LLVM) override; + llvm::Value* GenIR(InfoLLVM& LLVM, FunctionScope& func) override; // Function to log the node to a file // void Log(unsigned depth) override; @@ -101,7 +103,7 @@ namespace LX::AST VariableDeclaration(const std::string& name); // Function for generating LLVM IR (Intermediate representation) // - llvm::Value* GenIR(InfoLLVM& LLVM) override; + llvm::Value* GenIR(InfoLLVM& LLVM, FunctionScope& func) override; // Function to log the node to a file // void Log(unsigned depth) override; @@ -121,7 +123,7 @@ namespace LX::AST VariableAssignment(const std::string& name, std::unique_ptr val); // Function for generating LLVM IR (Intermediate representation) // - llvm::Value* GenIR(InfoLLVM& LLVM) override; + llvm::Value* GenIR(InfoLLVM& LLVM, FunctionScope& func) override; // Function to log the node to a file // void Log(unsigned depth) override; @@ -142,7 +144,7 @@ namespace LX::AST VariableAccess(const std::string& name); // Function for generating LLVM IR (Intermediate representation) // - llvm::Value* GenIR(InfoLLVM& LLVM) override; + llvm::Value* GenIR(InfoLLVM& LLVM, FunctionScope& func) override; // Function to log the node to a file // void Log(unsigned depth) override; diff --git a/Parser/inc/Scope.h b/Parser/inc/Scope.h new file mode 100644 index 0000000..af1ecf7 --- /dev/null +++ b/Parser/inc/Scope.h @@ -0,0 +1,104 @@ +#pragma once + +#include + +#include + +namespace LX +{ + CREATE_EMPTY_LX_ERROR_TYPE(VariableError); + + class FunctionScope + { + public: + FunctionScope(const std::vector paramNames, llvm::Function* func) + { + // Counter for the args // + unsigned argCounter = 0; + + // Checks the parameter does not exist before inserting // + for (const std::string& param : paramNames) + { + ThrowIf(GetVarLocation(param) != NONE); + + // Adds the argument to the map and sets its name // + m_Params[param] = func->getArg(argCounter); + m_Params[param]->setName(param); + + // Iterates to the next one // + argCounter++; + } + } + + llvm::Value* DecVar(const std::string& name, InfoLLVM& LLVM) + { + // Finds out if the variable already exists // + ThrowIf(GetVarLocation(name) != NONE); + + // Allocates the variable and then returns a pointer to it's allocation // + llvm::AllocaInst* inst = LLVM.builder.CreateAlloca(LLVM.builder.getInt32Ty(), nullptr, name); + m_LocalVars[name] = inst; + return inst; + } + + llvm::Value* AccessVar(const std::string& name, InfoLLVM& LLVM) + { + VariableLocation l = GetVarLocation(name); + + switch (l) + { + case LOCAL: + return LLVM.builder.CreateLoad(LLVM.builder.getInt32Ty(), m_LocalVars[name], name + "_v"); + + case PARAMS: + return m_Params[name]; + + default: + throw VariableError(); + } + } + + llvm::Value* AssignVar(const std::string& name, AST::Node* value, InfoLLVM& LLVM, FunctionScope& scope) + { + // Checks it is a local variable and not a parameter // + ThrowIf(GetVarLocation(name) != LOCAL); + + // Returns a pointer to the assignment in the builder // + return LLVM.builder.CreateStore(value->GenIR(LLVM, scope), m_LocalVars[name]); + } + + protected: + enum VariableLocation + { + NONE = 0, + PARAMS = 1, + LOCAL = 2 + }; + + VariableLocation GetVarLocation(const std::string& name) + { + // Searches in the variable maps // + auto pIt = m_Params.find(name); + auto lIt = m_LocalVars.find(name); + + if (pIt != m_Params.end()) + { + return PARAMS; + } + + if (lIt != m_LocalVars.end()) + { + return LOCAL; + } + + return NONE; + } + + private: + // Holds the parameters of the functions // + std::unordered_map m_Params; + + // Holds all local variables // + std::unordered_map m_LocalVars; + }; +} diff --git a/Parser/src/AST/AST-LLVM.cpp b/Parser/src/AST/AST-LLVM.cpp index 435eed1..c8bfc25 100644 --- a/Parser/src/AST/AST-LLVM.cpp +++ b/Parser/src/AST/AST-LLVM.cpp @@ -3,18 +3,18 @@ #include #include -#include +#include namespace LX::AST { // Function for genrating LLVM IR (Intermediate representation), will throw an error if called on this class // - llvm::Value* MultiNode::GenIR(InfoLLVM & LLVM) + llvm::Value* MultiNode::GenIR(InfoLLVM& LLVM, FunctionScope& func) { throw int(); // <- TODO: Make an error type } // Function for generating LLVM IR (Intermediate representation) // - llvm::Value* NumberLiteral::GenIR(InfoLLVM& LLVM) + llvm::Value* NumberLiteral::GenIR(InfoLLVM& LLVM, FunctionScope& func) { // Converts the string to it's int equivalent // // TODO: Support floating point values // @@ -29,11 +29,11 @@ namespace LX::AST } // Function for generating LLVM IR (Intermediate representation) // - llvm::Value* Operation::GenIR(InfoLLVM& LLVM) + llvm::Value* Operation::GenIR(InfoLLVM& LLVM, FunctionScope& func) { // Generates the IR for both sides of the operation // - llvm::Value* lhs = m_Lhs->GenIR(LLVM); - llvm::Value* rhs = m_Rhs->GenIR(LLVM); + llvm::Value* lhs = m_Lhs->GenIR(LLVM, func); + llvm::Value* rhs = m_Rhs->GenIR(LLVM, func); // If either side is null then return null to prevent invalid IR // // TODO: Make the error actually output information // @@ -76,7 +76,7 @@ namespace LX::AST } // Function for generating LLVM IR (Intermediate representation) // - llvm::Value* ReturnStatement::GenIR(InfoLLVM& LLVM) + llvm::Value* ReturnStatement::GenIR(InfoLLVM& LLVM, FunctionScope& func) { // Checks if it is a void return // if (m_Val == nullptr) @@ -92,25 +92,25 @@ namespace LX::AST { // Generates the value and creates a return for it // // TODO: Make the error actually output information // - llvm::Value* out = LLVM.builder.CreateRet(m_Val->GenIR(LLVM)); + llvm::Value* out = LLVM.builder.CreateRet(m_Val->GenIR(LLVM, func)); ThrowIf(out == nullptr); return out; } } // Function for generating LLVM IR (Intermediate representation) // - llvm::Value* VariableDeclaration::GenIR(InfoLLVM& LLVM) + llvm::Value* VariableDeclaration::GenIR(InfoLLVM& LLVM, FunctionScope& func) { - return nullptr; + return func.DecVar(m_Name, LLVM); } - llvm::Value* VariableAssignment::GenIR(InfoLLVM& LLVM) + llvm::Value* VariableAssignment::GenIR(InfoLLVM& LLVM, FunctionScope& func) { - return nullptr; + return func.AssignVar(m_Name, m_Value.get(), LLVM, func); } - llvm::Value* VariableAccess::GenIR(InfoLLVM& LLVM) + llvm::Value* VariableAccess::GenIR(InfoLLVM& LLVM, FunctionScope& func) { - return nullptr; + return func.AccessVar(m_Name, LLVM); } } diff --git a/Parser/src/GenIR.cpp b/Parser/src/GenIR.cpp index 2664d01..0ee3188 100644 --- a/Parser/src/GenIR.cpp +++ b/Parser/src/GenIR.cpp @@ -3,7 +3,7 @@ #include #include -#include +#include namespace LX { @@ -32,22 +32,24 @@ namespace LX { // Creates the functions signature and return type // - llvm::FunctionType* retType = llvm::FunctionType::get(llvm::Type::getInt32Ty(LLVM.context), false); // <- Defaults to int currently + std::cout << funcAST.params.size() << std::endl; + + std::vector funcParams(funcAST.params.size(), LLVM.builder.getInt32Ty()); + + llvm::FunctionType* retType = llvm::FunctionType::get(llvm::Type::getInt32Ty(LLVM.context), funcParams, false); // <- Defaults to int currently llvm::Function* func = llvm::Function::Create(retType, GetLinkageType(funcAST.name), funcAST.name, LLVM.module); llvm::BasicBlock* entry = llvm::BasicBlock::Create(LLVM.context, funcAST.name + "-entry", func); LLVM.builder.SetInsertPoint(entry); - // Adds the function's parameters to the scope // - for (std::string& param : funcAST.params) - { - //LLVM.scope->CreateVar(param, LLVM); - } + // Creates the storer of the variables/parameters // + + FunctionScope funcScope(funcAST.params, func); // Generates the IR within the function by looping over the nodes // for (auto& node : funcAST.body) { ThrowIf(IsValidTopLevelNode(node->m_Type) == false); // <- TODO: replace with actual error type - node->GenIR(LLVM); + node->GenIR(LLVM, funcScope); } // Adds a terminator if there is none // diff --git a/Parser/src/Scope.cpp b/Parser/src/Scope.cpp new file mode 100644 index 0000000..80c2a71 --- /dev/null +++ b/Parser/src/Scope.cpp @@ -0,0 +1,17 @@ +#include + +#include + +#include + +namespace LX +{ + const char* VariableError::ErrorType() const + { + return "Variable Error"; + } + + void VariableError::PrintToConsole() const + { + } +}