From 3ec6cc0c6eb25ddbc7a4964b96269a8d9f45e361 Mon Sep 17 00:00:00 2001 From: Pasha Bibko <156938226+PashaBibko@users.noreply.github.com> Date: Mon, 28 Apr 2025 19:59:45 +0100 Subject: [PATCH] Added VarAssign, VarAccess and MultiNode --- IR-Generator/inc/Parser.h | 9 ++++ Parser/inc/AST.h | 63 ++++++++++++++++++++++++++-- Parser/src/AST-Constructors.cpp | 15 +++++++ Parser/src/AST-LLVM.cpp | 24 +++++++++-- Parser/src/AST-Loggers.cpp | 19 ++++++++- Parser/src/Parser.cpp | 74 +++++++++++++++++++++++++++++---- example/main.lx | 2 +- 7 files changed, 186 insertions(+), 20 deletions(-) diff --git a/IR-Generator/inc/Parser.h b/IR-Generator/inc/Parser.h index 530eafa..18487ec 100644 --- a/IR-Generator/inc/Parser.h +++ b/IR-Generator/inc/Parser.h @@ -26,11 +26,20 @@ namespace LX::AST // Used so a pointer to Node can be used and then turned into it's true type // enum NodeType { + // "Nodes" // + + MULTI_NODE, + // General Nodes // NUMBER_LITERAL, OPERATION, + + // Variable manipulation // + VARIABLE_DECLARATION, + VARIABLE_ASSIGNMENT, + VARIABLE_ACCESS, // Control flow Nodes // diff --git a/Parser/inc/AST.h b/Parser/inc/AST.h index 9544602..ef08d62 100644 --- a/Parser/inc/AST.h +++ b/Parser/inc/AST.h @@ -23,6 +23,22 @@ namespace LX namespace LX::AST { + class MultiNode : public Node + { + public: + // Constructor to auto set type // + MultiNode(); + + // Function for generating LLVM IR (Intermediate representation), will throw error if called on this class // + llvm::Value* GenIR(InfoLLVM& LLVM) override; + + // Function to log the node to a file, will throw an error if called on this class // + void Log(std::ofstream* log, unsigned depth) override; + + // The nodes that are contained within this node // + std::vector> nodes; + }; + // Node to represent any number within the AST // class NumberLiteral : public Node { @@ -30,7 +46,7 @@ namespace LX::AST // Constructor to set values and automatically set type // NumberLiteral(std::string num); - // Function for generating LLVN IR (Intermediate representation) // + // Function for generating LLVM IR (Intermediate representation) // llvm::Value* GenIR(InfoLLVM& LLVM) override; // Function to log the node to a file // @@ -49,7 +65,7 @@ namespace LX::AST // Constructor to set values and automatically set type // Operation(std::unique_ptr lhs, Token::TokenType op, std::unique_ptr rhs); - // Function for generating LLVN IR (Intermediate representation) // + // Function for generating LLVM IR (Intermediate representation) // llvm::Value* GenIR(InfoLLVM& LLVM) override; // Function to log the node to a file // @@ -71,7 +87,7 @@ namespace LX::AST // Constructor to set values and automatically set type // ReturnStatement(std::unique_ptr val); - // Function for generating LLVN IR (Intermediate representation) // + // Function for generating LLVM IR (Intermediate representation) // llvm::Value* GenIR(InfoLLVM& LLVM) override; // Function to log the node to a file // @@ -89,7 +105,7 @@ namespace LX::AST // Constructor to set values and automatically set type // VariableDeclaration(const std::string& name); - // Function for generating LLVN IR (Intermediate representation) // + // Function for generating LLVM IR (Intermediate representation) // llvm::Value* GenIR(InfoLLVM& LLVM) override; // Function to log the node to a file // @@ -101,4 +117,43 @@ namespace LX::AST // Doesnt need to store type as everything is currently int // }; + + // Node to represent the assignment of a variable within the AST // + class VariableAssignment : public Node + { + public: + // Constructor to set values and automatically set type // + VariableAssignment(const std::string& name, std::unique_ptr val); + + // Function for generating LLVM IR (Intermediate representation) // + llvm::Value* GenIR(InfoLLVM& LLVM) override; + + // Function to log the node to a file // + void Log(std::ofstream* log, unsigned depth) override; + + private: + // Name of the variable // + std::string m_Name; + + // The value that will be assigned to the value // + std::unique_ptr m_Value; + }; + + // Node to represent accessing a variable within the AST // + class VariableAccess : public Node + { + public: + // Constructor to set values and automatically set type // + VariableAccess(const std::string& name); + + // Function for generating LLVM IR (Intermediate representation) // + llvm::Value* GenIR(InfoLLVM& LLVM) override; + + // Function to log the node to a file // + void Log(std::ofstream* log, unsigned depth) override; + + private: + // The name of the variable // + std::string m_Name; + }; } \ No newline at end of file diff --git a/Parser/src/AST-Constructors.cpp b/Parser/src/AST-Constructors.cpp index 58650fe..8bef2e3 100644 --- a/Parser/src/AST-Constructors.cpp +++ b/Parser/src/AST-Constructors.cpp @@ -27,6 +27,11 @@ namespace LX::AST : m_Type(type) {} + // Automatically sets type // + MultiNode::MultiNode() + : Node(Node::MULTI_NODE), nodes{} + {} + // Passes constructor args to values and sets type // NumberLiteral::NumberLiteral(std::string num) : Node(Node::NUMBER_LITERAL), m_Number(num) @@ -46,4 +51,14 @@ namespace LX::AST VariableDeclaration::VariableDeclaration(const std::string& name) : Node(Node::VARIABLE_DECLARATION), m_Name(name) {} + + // Passes constructor args to values and sets type // + VariableAssignment::VariableAssignment(const std::string& name, std::unique_ptr val) + : Node(Node::VARIABLE_ASSIGNMENT), m_Name(name), m_Value(std::move(val)) + {} + + // Passes constructor args to values and sets type // + VariableAccess::VariableAccess(const std::string& name) + : Node(Node::VARIABLE_ACCESS), m_Name(name) + {} } diff --git a/Parser/src/AST-LLVM.cpp b/Parser/src/AST-LLVM.cpp index 9d6f6e8..fea25b5 100644 --- a/Parser/src/AST-LLVM.cpp +++ b/Parser/src/AST-LLVM.cpp @@ -6,7 +6,13 @@ namespace LX::AST { - // Function for generating LLVN IR (Intermediate representation) // + // Function for genrating LLVM IR (Intermediate representation), will throw an error if called on this class // + llvm::Value* MultiNode::GenIR(InfoLLVM & LLVM) + { + throw int(); // <- TODO: Make an error type + } + + // Function for generating LLVM IR (Intermediate representation) // llvm::Value* NumberLiteral::GenIR(InfoLLVM& LLVM) { // Converts the string to it's int equivalent // @@ -21,7 +27,7 @@ namespace LX::AST return out; } - // Function for generating LLVN IR (Intermediate representation) // + // Function for generating LLVM IR (Intermediate representation) // llvm::Value* Operation::GenIR(InfoLLVM& LLVM) { // Generates the IR for both sides of the operation // @@ -44,7 +50,7 @@ namespace LX::AST return out; } - // Function for generating LLVN IR (Intermediate representation) // + // Function for generating LLVM IR (Intermediate representation) // llvm::Value* ReturnStatement::GenIR(InfoLLVM& LLVM) { // Checks if it is a void return // @@ -67,7 +73,7 @@ namespace LX::AST } } - // Function for generating LLVN IR (Intermediate representation) // + // Function for generating LLVM IR (Intermediate representation) // llvm::Value* VariableDeclaration::GenIR(InfoLLVM& LLVM) { // Creates the variable within the scope // @@ -76,4 +82,14 @@ namespace LX::AST // Creates the declaration within the IR // return LLVM.builder.CreateAlloca(LLVM.builder.getInt32Ty(), nullptr, m_Name); } + + llvm::Value* VariableAssignment::GenIR(InfoLLVM& LLVM) + { + return nullptr; + } + + llvm::Value* VariableAccess::GenIR(InfoLLVM& LLVM) + { + return nullptr; + } } diff --git a/Parser/src/AST-Loggers.cpp b/Parser/src/AST-Loggers.cpp index 6f9c20b..1c0940f 100644 --- a/Parser/src/AST-Loggers.cpp +++ b/Parser/src/AST-Loggers.cpp @@ -4,9 +4,9 @@ namespace LX::AST { - void Node::Log(std::ofstream* log, unsigned depth) + void MultiNode::Log(std::ofstream* log, unsigned depth) { - (*log) << std::string(depth, '\t') << "NULL node"; + throw int(); // <- TODO: Make an error for this } void NumberLiteral::Log(std::ofstream* log, unsigned depth) @@ -46,4 +46,19 @@ namespace LX::AST (*log) << std::string(depth, '\t'); (*log) << "Variable declaration: " << m_Name << "\n"; } + + void VariableAssignment::Log(std::ofstream* log, unsigned depth) + { + (*log) << std::string(depth, '\t'); + (*log) << "Variable assignment:\n"; + (*log) << std::string(depth + 1, '\t') << "To: " << m_Name << "\n"; + (*log) << std::string(depth + 1, '\t') << "Value:\n"; + m_Value.get()->Log(log, depth + 2); + } + + void VariableAccess::Log(std::ofstream* log, unsigned depth) + { + (*log) << std::string(depth, '\t'); + (*log) << "Variable: " << m_Name << '\n'; + } } diff --git a/Parser/src/Parser.cpp b/Parser/src/Parser.cpp index 4fa0cd8..9934497 100644 --- a/Parser/src/Parser.cpp +++ b/Parser/src/Parser.cpp @@ -67,7 +67,6 @@ namespace LX { // Checks if the next token is an operator // // TODO: Add more than just add // - // TODO: Make this not crash when at the end // if (p.index + 1 < p.len) [[likely]] { if (p.tokens[p.index + 1].type == Token::ADD) @@ -120,21 +119,61 @@ namespace LX // Checks for the variable name // ThrowIf(p.tokens[p.index].type != Token::IDENTIFIER, Token::IDENTIFIER, "", p.tokens[p.index]); + std::string name = p.tokens[p.index].GetContents(); p.index++; // <- Goes over the identifier token - // Returns the variable declaration as an AST node by creating it with it's name // - return std::make_unique(p.tokens[p.index - 1].GetContents()); + // Returns the declaration if there is no default assignment to the variable // + if (p.tokens[p.index].type != Token::ASSIGN) + { + // Creates the variable name from the contents of the token and returns it // + return std::make_unique(name); + } + + p.index++; // Skips over Token::ASSIGN + + // Gets the value to be assigned to the variable // + std::unique_ptr defaultVal = ParsePrimary(p); + ThrowIf(defaultVal.get() == nullptr, Token::UNDEFINED, "value", p.tokens[p.index - 1]); + + return std::make_unique(name); } // Else goes down the call stack // return ParseReturn(p); } + + // Handles variable assignments, if not calls ParseVarDeclaration // + static std::unique_ptr ParseVarAssignment(Parser& p) + { + // Checks if the next token is an equals // + if (p.index + 1 < p.len) [[likely]] + { + if (p.tokens[p.index + 1].type == Token::ASSIGN) + { + // Gets the variable that is being assigned too // + ThrowIf(p.tokens[p.index].type != Token::IDENTIFIER, Token::IDENTIFIER, "", p.tokens[p.index]); + std::string name = p.tokens[p.index].GetContents(); + + // Skips over the assign token and name of the variable // + p.index = p.index + 2; + + // Gets the value that is being assigned // + std::unique_ptr value = ParseOperation(p); + + // Returns an AST node of the variable assignment with it's name and value // + return std::make_unique(name, std::move(value)); + } + } + + // Else goes down the call stack // + return ParseVarDeclaration(p); + } // Helper function to call the top of the Parse-Call-Stack // static inline std::unique_ptr Parse(Parser& p) { // Parses the current token // - std::unique_ptr out = ParseVarDeclaration(p); + std::unique_ptr out = ParseVarAssignment(p); // Checks it is valid before returning // ThrowIf(out == nullptr, Token::UNDEFINED, "top level statement", p.tokens[p.index - 1]); @@ -191,14 +230,31 @@ namespace LX // Loops over the body until it reaches the end // while (p.index < p.len && (p.tokens[p.index].type == Token::CLOSE_BRACKET && p.scopeDepth == 0) == false) { - // Actually parses the function + // Actually parses the function // std::unique_ptr node = Parse(p); - // Logs the node to the log // - if (log != nullptr) { node->Log(log, 0); } + // Expands the node if it contains multiple // + if (node->m_Type == AST::Node::MULTI_NODE) + { + for (std::unique_ptr& containedNode : ((AST::MultiNode*)node.get())->nodes) + { + // Logs the node to the log // + if (log != nullptr) { node->Log(log, 0); } - // Adds it to the vector - func.body.push_back(std::move(node)); + // Adds it to the vector // + func.body.push_back(std::move(containedNode)); + } + } + + // Else adds the singular node to the vector // + else + { + // Logs the node to the log // + if (log != nullptr) { node->Log(log, 0); } + + // Adds it to the vector // + func.body.push_back(std::move(node)); + } } // Skips over closing bracket // diff --git a/example/main.lx b/example/main.lx index ad87d1d..5f87439 100644 --- a/example/main.lx +++ b/example/main.lx @@ -1,4 +1,4 @@ func main() { - int result + result = 3 }