From 14b2b36748f6b19593f0b4bf8abb8cf81c97dfde Mon Sep 17 00:00:00 2001 From: Pasha Bibko <156938226+PashaBibko@users.noreply.github.com> Date: Thu, 17 Apr 2025 18:34:56 +0100 Subject: [PATCH] IT CRASHES WHYYYYYYYYYYYYYYYYYYYYYY --- LX-LLVM.vcxproj | 1 + Main.cpp | 11 ++++-- Parser/Parser.vcxproj | 3 ++ Parser/Parser.vcxproj.filters | 9 +++++ Parser/src/AST-Constructors.cpp | 16 +++++++++ Parser/src/AST-LLVM.cpp | 54 ++++++++++++++++++++++++++++ Parser/src/GenIR.cpp | 64 +++++++++++++++++++++++++++++++++ build-test/Log.txt | 17 --------- build-test/main.lx | 2 +- common/LLVM.h | 2 +- common/Parser.h | 41 ++++++++++----------- 11 files changed, 177 insertions(+), 43 deletions(-) create mode 100644 Parser/src/AST-Constructors.cpp create mode 100644 Parser/src/AST-LLVM.cpp create mode 100644 Parser/src/GenIR.cpp diff --git a/LX-LLVM.vcxproj b/LX-LLVM.vcxproj index 68cec45..1fb1e60 100644 --- a/LX-LLVM.vcxproj +++ b/LX-LLVM.vcxproj @@ -45,6 +45,7 @@ true v143 Unicode + false Application diff --git a/Main.cpp b/Main.cpp index 9b6f741..e0d91ef 100644 --- a/Main.cpp +++ b/Main.cpp @@ -55,6 +55,12 @@ int main(int argc, char** argv) // Turns the tokens into an AST LX::FileAST AST = LX::TurnTokensIntoAbstractSyntaxTree(tokens, log.get()); + + // Turns the AST into something + LX::GenerateIR(AST); + + // Returns success + return 0; } catch (LX::IncorrectCommandLineArgs) @@ -104,6 +110,7 @@ int main(int argc, char** argv) return 6; } - - return 0; + + // -1 means an error slipped through (IDK how, it's here just in case) + return -1; } diff --git a/Parser/Parser.vcxproj b/Parser/Parser.vcxproj index e594b2a..c5ffbbe 100644 --- a/Parser/Parser.vcxproj +++ b/Parser/Parser.vcxproj @@ -131,6 +131,9 @@ + + + diff --git a/Parser/Parser.vcxproj.filters b/Parser/Parser.vcxproj.filters index 23540ae..9159eb8 100644 --- a/Parser/Parser.vcxproj.filters +++ b/Parser/Parser.vcxproj.filters @@ -14,5 +14,14 @@ Source Files + + Source Files + + + Source Files + + + Source Files + \ No newline at end of file diff --git a/Parser/src/AST-Constructors.cpp b/Parser/src/AST-Constructors.cpp new file mode 100644 index 0000000..60200bf --- /dev/null +++ b/Parser/src/AST-Constructors.cpp @@ -0,0 +1,16 @@ +#include + +namespace LX::AST +{ + NumberLiteral::NumberLiteral(std::string num) + : Node(Node::NUMBER_LITERAL), m_Number(num) + {} + + Operation::Operation(std::unique_ptr lhs, Token::TokenType op, std::unique_ptr rhs) + : Node(Node::OPERATION), m_Lhs(std::move(lhs)), m_Operand(op), m_Rhs(std::move(rhs)) + {} + + ReturnStatement::ReturnStatement(std::unique_ptr val) + : Node(Node::RETURN_STATEMENT), m_Val(std::move(val)) + {} +} diff --git a/Parser/src/AST-LLVM.cpp b/Parser/src/AST-LLVM.cpp new file mode 100644 index 0000000..0ba3f17 --- /dev/null +++ b/Parser/src/AST-LLVM.cpp @@ -0,0 +1,54 @@ +#include + +#include +#include + +namespace LX::AST +{ + llvm::Value* NumberLiteral::GenIR(llvm::LLVMContext& context, llvm::Module& module, llvm::IRBuilder<>& builder) + { + // Converts the string to it's int equivalent + // Will eventually need to do floating point stuff here as well + int number = std::stoi(m_Number); + + // Returns it as a llvm value (if valid) + llvm::Value* out = llvm::ConstantInt::get(llvm::Type::getInt32Ty(context), number, true); + ThrowIf(out == nullptr); + return out; + } + + llvm::Value* Operation::GenIR(llvm::LLVMContext& context, llvm::Module& module, llvm::IRBuilder<>& builder) + { + // Gets the IR for both sides of the operation + llvm::Value* lhs = m_Lhs->GenIR(context, module, builder); + llvm::Value* rhs = m_Rhs->GenIR(context, module, builder); + + // If either side is null then return null to prevent invalid IR // + if (lhs == nullptr || rhs == nullptr) + { + ThrowIf(true); + return nullptr; + } + + // Will eventually get the correct operator but for now everything is add + llvm::Value* out = builder.CreateAdd(lhs, rhs); + ThrowIf(out == nullptr); + return out; + } + + llvm::Value* ReturnStatement::GenIR(llvm::LLVMContext& context, llvm::Module& module, llvm::IRBuilder<>& builder) + { + if (m_Val == nullptr) + { + ThrowIf(true); + return nullptr; + } + + else + { + llvm::Value* out = builder.CreateRet(m_Val->GenIR(context, module, builder)); + ThrowIf(out == nullptr); + return out; + } + } +} diff --git a/Parser/src/GenIR.cpp b/Parser/src/GenIR.cpp new file mode 100644 index 0000000..ae8d646 --- /dev/null +++ b/Parser/src/GenIR.cpp @@ -0,0 +1,64 @@ +#include + +#include + +namespace LX +{ + void GenerateIR(FileAST& ast) + { + // Generates stuff // + + llvm::LLVMContext context; + llvm::IRBuilder<> builder(context); + + { + std::unique_ptr module = std::make_unique("add_ints", context); + + // Defines main function // + + llvm::FunctionType* funcType = llvm::FunctionType::get(llvm::Type::getInt32Ty(context), false); + llvm::Function* mainFunc = llvm::Function::Create(funcType, llvm::Function::ExternalLinkage, "main", module.get()); + llvm::BasicBlock* entry = llvm::BasicBlock::Create(context, "entry", mainFunc); + builder.SetInsertPoint(entry); + + // Loops over AST to generate IR // + + for (auto& node : ast.functions[0].body) + { + switch (node->m_Type) + { + case AST::Node::RETURN_STATEMENT: + { + node->GenIR(context, *module, builder); + break; + } + + default: + { + break; + } + } + } + + if (entry->getTerminator() == nullptr) + { + builder.CreateRet(llvm::ConstantInt::get(llvm::Type::getInt32Ty(context), 0, true)); + } + + // Verification of the IR // + + if (llvm::verifyFunction(*mainFunc, &llvm::errs()) || llvm::verifyModule(*module, &llvm::errs())) + { + std::cerr << "Error: IR generation failed" << std::endl; + return; + } + + // Outputs the IR to the console // + + module->print(llvm::outs(), nullptr); + + } // <- Crashes here + + std::cout << "Finished generating IR" << std::endl; + } +} diff --git a/build-test/Log.txt b/build-test/Log.txt index a060136..e69de29 100644 --- a/build-test/Log.txt +++ b/build-test/Log.txt @@ -1,17 +0,0 @@ - --=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- -Started lexing file --=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- - -Token::FUNCTION -Token::IDENTIFIER: main -Unknown: 3 -Token::NUMBER_LITERAL: 34 -Token::ADD -Token::NUMBER_LITERAL: 4324 - --=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- -Started parsing tokens --=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- - -AST length: 1 diff --git a/build-test/main.lx b/build-test/main.lx index 538eb44..fd50a1a 100644 --- a/build-test/main.lx +++ b/build-test/main.lx @@ -1,2 +1,2 @@ func main - return 34 + 4324 + return 3 + 4 diff --git a/common/LLVM.h b/common/LLVM.h index 6999738..bccd7cc 100644 --- a/common/LLVM.h +++ b/common/LLVM.h @@ -2,7 +2,7 @@ // Helper file for including all neccesarry parts of LLVM // #ifdef _MSC_VER - + // Disables all warnings as LLVM files have a lot of Data-loss casts that won't cause issues // #pragma warning(push) #pragma warning(disable : 4244) diff --git a/common/Parser.h b/common/Parser.h index 62dcbf3..1d62caf 100644 --- a/common/Parser.h +++ b/common/Parser.h @@ -2,11 +2,13 @@ // Lexer foward declares fstream components so we can use them here // #include +#include #include // Foward declares all items of the llvm lib that we need // // Done to avoid including LLVM.h to shorten compile times // +/* namespace llvm { class Value; @@ -18,7 +20,7 @@ namespace llvm template class IRBuilder; -} +}*/ // The nodes of the abstract syntax tree constructed by the parser from the tokens // namespace LX::AST @@ -65,14 +67,11 @@ namespace LX::AST class NumberLiteral : public Node { public: - NumberLiteral(std::string num) - : Node(Node::NUMBER_LITERAL), m_Number(num) - {} + // Constructor to set values and automatically set type + NumberLiteral(std::string num); - llvm::Value* GenIR(llvm::LLVMContext& context, llvm::Module& module, llvm::IRBuilder<>& builder) - { - return nullptr; - } + // Function for generating LLVN IR (Intermediate representation) // + llvm::Value* GenIR(llvm::LLVMContext& context, llvm::Module& module, llvm::IRBuilder<>& builder) override; private: // The number it stores @@ -85,14 +84,11 @@ namespace LX::AST class Operation : public Node { public: - Operation(std::unique_ptr lhs, Token::TokenType op, std::unique_ptr rhs) - : Node(Node::OPERATION), m_Lhs(std::move(lhs)), m_Operand(op), m_Rhs(std::move(rhs)) - {} + // Constructor to set values and automatically set type + Operation(std::unique_ptr lhs, Token::TokenType op, std::unique_ptr rhs); - llvm::Value* GenIR(llvm::LLVMContext& context, llvm::Module& module, llvm::IRBuilder<>& builder) - { - return nullptr; - } + // Function for generating LLVN IR (Intermediate representation) // + llvm::Value* GenIR(llvm::LLVMContext& context, llvm::Module& module, llvm::IRBuilder<>& builder) override; private: // The sides of the operation @@ -107,14 +103,11 @@ namespace LX::AST class ReturnStatement : public Node { public: - ReturnStatement(std::unique_ptr val) - : Node(Node::RETURN_STATEMENT), m_Val(std::move(val)) - {} + // Constructor to set values and automatically set type + ReturnStatement(std::unique_ptr val); - llvm::Value* GenIR(llvm::LLVMContext& context, llvm::Module& module, llvm::IRBuilder<>& builder) - { - return nullptr; - } + // Function for generating LLVN IR (Intermediate representation) // + llvm::Value* GenIR(llvm::LLVMContext& context, llvm::Module& module, llvm::IRBuilder<>& builder) override; private: // What it is returning (can be null) @@ -124,6 +117,8 @@ namespace LX::AST namespace LX { + struct IRGenerationError {}; + struct FunctionDefinition { FunctionDefinition() @@ -143,4 +138,6 @@ namespace LX }; FileAST TurnTokensIntoAbstractSyntaxTree(std::vector& tokens, std::ofstream* log); + + void GenerateIR(FileAST& ast); }