From 4509250c4e08675219ec92d60e5fbb74663758d3 Mon Sep 17 00:00:00 2001 From: Pasha Bibko <156938226+PashaBibko@users.noreply.github.com> Date: Wed, 7 May 2025 20:33:39 +0100 Subject: [PATCH] Tided up Parser project --- IR-Generator/inc/Parser.h | 32 +----------- Parser/Parser.vcxproj | 8 +-- Parser/Parser.vcxproj.filters | 27 ++++++---- Parser/inc/ParserErrors.h | 43 ++++++++++++++++ Parser/inc/ParserInfo.h | 33 +++++++++++++ Parser/src/{ => AST}/AST-Constructors.cpp | 0 Parser/src/{ => AST}/AST-LLVM.cpp | 5 +- Parser/src/{ => AST}/AST-Loggers.cpp | 0 Parser/src/GenIR.cpp | 1 + Parser/src/Parser.cpp | 60 +++++++---------------- Parser/src/ParserErrors.cpp | 25 +++++++--- Parser/src/Scope.cpp | 3 +- 12 files changed, 142 insertions(+), 95 deletions(-) create mode 100644 Parser/inc/ParserErrors.h create mode 100644 Parser/inc/ParserInfo.h rename Parser/src/{ => AST}/AST-Constructors.cpp (100%) rename Parser/src/{ => AST}/AST-LLVM.cpp (96%) rename Parser/src/{ => AST}/AST-Loggers.cpp (100%) diff --git a/IR-Generator/inc/Parser.h b/IR-Generator/inc/Parser.h index 9f51097..e2bc5b6 100644 --- a/IR-Generator/inc/Parser.h +++ b/IR-Generator/inc/Parser.h @@ -2,7 +2,7 @@ #include -// Lexer foward declares fstream components so we can use them here // +// Includes Lexer so it can use LX::Token // #include // Foward declares the wrapper around the LLVM objects we need to pass around // @@ -63,39 +63,9 @@ namespace LX::AST namespace LX { - // Thrown if there was an error during IR Generation // - CREATE_EMPTY_LX_ERROR_TYPE(IRGenerationError); - - // Thrown if there was an unexpected (incorrect) token // - struct UnexpectedToken : public RuntimeError - { - GENERATE_LX_ERROR_REQUIRED_FUNCTION_DECLARATIONS; - - UnexpectedToken(Token::TokenType _expected, std::string _override, Token _got, const std::filesystem::path& _file); - - // - const std::filesystem::path file; - - // The token type that should be there // - Token::TokenType expected; - - // If there are multiple expected types there is an option for a custom message // - std::string override; - - // What token was actually at that position // - // Stored as Token not TokenType to store the location of it within the source // - Token got; - }; - class Scope { public: - // Error thrown if the user tried to create a variable that already existed // - CREATE_EMPTY_LX_ERROR_TYPE(VariableAlreadyExists); - - // Error thrown if user tries to access variable that does not exist // - CREATE_EMPTY_LX_ERROR_TYPE(VariableDoesntExist); - // Default constructor // Scope() : m_LocalVariables{}, m_Child(nullptr) diff --git a/Parser/Parser.vcxproj b/Parser/Parser.vcxproj index 6fa41f1..3d6a285 100644 --- a/Parser/Parser.vcxproj +++ b/Parser/Parser.vcxproj @@ -147,9 +147,9 @@ Create Create - - - + + + @@ -157,6 +157,8 @@ + + diff --git a/Parser/Parser.vcxproj.filters b/Parser/Parser.vcxproj.filters index e84a95d..c979894 100644 --- a/Parser/Parser.vcxproj.filters +++ b/Parser/Parser.vcxproj.filters @@ -9,23 +9,17 @@ {93995380-89BD-4b04-88EB-625FBE52EBFB} h;hh;hpp;hxx;h++;hm;inl;inc;ipp;xsd + + {344a1f33-e6b1-4bf7-b3b4-ec5b8c726d40} + Source Files - - Source Files - - - Source Files - Source Files - - Source Files - Source Files @@ -35,10 +29,25 @@ Header Files + + Source Files\AST + + + Source Files\AST + + + Source Files\AST + Header Files + + Header Files + + + Header Files + \ No newline at end of file diff --git a/Parser/inc/ParserErrors.h b/Parser/inc/ParserErrors.h new file mode 100644 index 0000000..7fbae24 --- /dev/null +++ b/Parser/inc/ParserErrors.h @@ -0,0 +1,43 @@ +#pragma once + +#include + +#include +#include + +namespace LX +{ + // Thrown if there was an error during IR Generation // + CREATE_EMPTY_LX_ERROR_TYPE(IRGenerationError); + + // Error thrown if the user tried to create a variable that already existed // + CREATE_EMPTY_LX_ERROR_TYPE(VariableAlreadyExists); + + // Error thrown if user tries to access variable that does not exist // + CREATE_EMPTY_LX_ERROR_TYPE(VariableDoesntExist); + + // Thrown if there was an unexpected (incorrect) token // + struct UnexpectedToken : public RuntimeError + { + GENERATE_LX_ERROR_REQUIRED_FUNCTION_DECLARATIONS; + + // Constructor to set the members of the error // + UnexpectedToken(Token::TokenType _expected, const ParserInfo& p); + + // Constructor for custom messages in the cmd // + UnexpectedToken(Token::TokenType _expected, Token _got, const std::string& message, const ParserInfo& p); + + // The file that the tokens come from // + const std::filesystem::path file; + + // The token type that should be there // + const Token::TokenType expected; + + // If there are multiple expected types there is an option for a custom message // + const std::string custom; + + // What token was actually at that position // + // Stored as Token not TokenType to store the location of it within the source // + const Token got; + }; +} diff --git a/Parser/inc/ParserInfo.h b/Parser/inc/ParserInfo.h new file mode 100644 index 0000000..db880bf --- /dev/null +++ b/Parser/inc/ParserInfo.h @@ -0,0 +1,33 @@ +#pragma once + +#include + +// Includes Lexer so it can use LX::Token // +#include + +namespace LX +{ + // Local struct so everything can be public // + struct ParserInfo + { + // Passes constructor args to members // + ParserInfo(const std::vector& _tokens, const std::filesystem::path& path) + : tokens(_tokens), index(0), len(_tokens.size()), scopeDepth(0), file(path) + {} + + // The file that the tokens were generated from // + const std::filesystem::path file; + + // Tokens created by the lexer // + const std::vector& tokens; + + // Length of the the token vector // + const size_t len; + + // Current index within the token vector // + size_t index; + + // Current scope depth // + size_t scopeDepth; + }; +} diff --git a/Parser/src/AST-Constructors.cpp b/Parser/src/AST/AST-Constructors.cpp similarity index 100% rename from Parser/src/AST-Constructors.cpp rename to Parser/src/AST/AST-Constructors.cpp diff --git a/Parser/src/AST-LLVM.cpp b/Parser/src/AST/AST-LLVM.cpp similarity index 96% rename from Parser/src/AST-LLVM.cpp rename to Parser/src/AST/AST-LLVM.cpp index 62c8d7b..429ce06 100644 --- a/Parser/src/AST-LLVM.cpp +++ b/Parser/src/AST/AST-LLVM.cpp @@ -2,6 +2,7 @@ #include +#include #include namespace LX::AST @@ -108,7 +109,7 @@ namespace LX::AST { // Gets the variable from the current scope // llvm::AllocaInst* asignee = LLVM.scope->GetVar(m_Name); - ThrowIf(asignee == nullptr); + ThrowIf(asignee == nullptr); // Creates the assignment // return LLVM.builder.CreateStore(m_Value->GenIR(LLVM), asignee); @@ -118,7 +119,7 @@ namespace LX::AST { // Loads the variable from the current scope // llvm::AllocaInst* var = LLVM.scope->GetVar(m_Name); - ThrowIf(var == nullptr); + ThrowIf(var == nullptr); // Creates the load within the AST // return LLVM.builder.CreateLoad(llvm::Type::getInt32Ty(LLVM.context), var, m_Name + "_val"); diff --git a/Parser/src/AST-Loggers.cpp b/Parser/src/AST/AST-Loggers.cpp similarity index 100% rename from Parser/src/AST-Loggers.cpp rename to Parser/src/AST/AST-Loggers.cpp diff --git a/Parser/src/GenIR.cpp b/Parser/src/GenIR.cpp index a5d1b72..d4ec4a9 100644 --- a/Parser/src/GenIR.cpp +++ b/Parser/src/GenIR.cpp @@ -2,6 +2,7 @@ #include +#include #include namespace LX diff --git a/Parser/src/Parser.cpp b/Parser/src/Parser.cpp index c7ce21b..2d50b61 100644 --- a/Parser/src/Parser.cpp +++ b/Parser/src/Parser.cpp @@ -2,6 +2,8 @@ #include +#include +#include #include namespace LX @@ -22,32 +24,8 @@ namespace LX } } - // Local struct so everything can be public // - struct Parser - { - // Passes constructor args to members // - Parser(std::vector& _tokens, const std::filesystem::path& path) - : tokens(_tokens), index(0), len(_tokens.size()), scopeDepth(0), file(path) - {} - - // The file that the tokens were generated from // - const std::filesystem::path file; - - // Tokens created by the lexer // - std::vector& tokens; - - // Length of the the token vector // - const size_t len; - - // Current index within the token vector // - size_t index; - - // Current scope depth // - size_t scopeDepth; - }; - // Base of the call stack to handle the simplest of tokens // - static std::unique_ptr ParsePrimary(Parser& p) + static std::unique_ptr ParsePrimary(ParserInfo& p) { // There are lots of possible token's that can be here so a switch is used // switch (p.tokens[p.index].type) @@ -69,7 +47,7 @@ namespace LX // TODO: Fix this // case Token::CLOSE_BRACE: - ThrowIf(p.scopeDepth == 0, Token::UNDEFINED, "need a different error", p.tokens[p.index], p.file); + ThrowIf(p.scopeDepth == 0, Token::UNDEFINED, p.tokens[p.index], "need a different error", p); p.scopeDepth--; p.index++; return nullptr; @@ -82,7 +60,7 @@ namespace LX } // Handles operations, if it is not currently at an operation goes to ParsePrimary // - static std::unique_ptr ParseOperation(Parser& p) + static std::unique_ptr ParseOperation(ParserInfo& p) { // Checks if the next token is an operator // // TODO: Add more than just add // @@ -92,7 +70,7 @@ namespace LX { // Parses the left hand side of the operation // std::unique_ptr lhs = ParsePrimary(p); - ThrowIf(lhs == nullptr, Token::UNDEFINED, "value", p.tokens[p.index - 1], p.file); + ThrowIf(lhs == nullptr, Token::UNDEFINED, p.tokens[p.index - 1], "value", p); // Stores the operator to pass into the AST node // Token::TokenType op = p.tokens[p.index].type; @@ -100,7 +78,7 @@ namespace LX // Parses the right hand of the operation // std::unique_ptr rhs = ParseOperation(p); - ThrowIf(rhs == nullptr, Token::UNDEFINED, "value", p.tokens[p.index - 1], p.file); + ThrowIf(rhs == nullptr, Token::UNDEFINED, p.tokens[p.index - 1], "value", p); // Returns an AST node as all of the components combined together // return std::make_unique(std::move(lhs), op, std::move(rhs)); @@ -112,7 +90,7 @@ namespace LX } // Handles return statements, if not calls ParseOperation // - static std::unique_ptr ParseReturn(Parser& p) + static std::unique_ptr ParseReturn(ParserInfo& p) { // Checks if the current token is a return // if (p.tokens[p.index].type == Token::RETURN) @@ -128,7 +106,7 @@ namespace LX } // Handles variable declarations, if not calls ParseReturn // - static std::unique_ptr ParseVarDeclaration(Parser& p) + static std::unique_ptr ParseVarDeclaration(ParserInfo& p) { // Checks if the current token is a declaration // if (p.tokens[p.index].type == Token::INT_DEC) @@ -137,7 +115,7 @@ namespace LX p.index++; // Checks for the variable name // - ThrowIf(p.tokens[p.index].type != Token::IDENTIFIER, Token::IDENTIFIER, "", p.tokens[p.index], p.file); + ThrowIf(p.tokens[p.index].type != Token::IDENTIFIER, Token::IDENTIFIER, p); std::string name = p.tokens[p.index].GetContents(); p.index++; // <- Goes over the identifier token @@ -152,7 +130,7 @@ namespace LX // 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], p.file); + ThrowIf(defaultVal.get() == nullptr, Token::UNDEFINED, p.tokens[p.index - 1], "value", p); return std::make_unique(name); } @@ -162,7 +140,7 @@ namespace LX } // Handles variable assignments, if not calls ParseVarDeclaration // - static std::unique_ptr ParseVarAssignment(Parser& p) + static std::unique_ptr ParseVarAssignment(ParserInfo& p) { // Checks if the next token is an equals // if (p.index + 1 < p.len) [[likely]] @@ -170,7 +148,7 @@ namespace LX 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], p.file); + ThrowIf(p.tokens[p.index].type != Token::IDENTIFIER, Token::IDENTIFIER, p); std::string name = p.tokens[p.index].GetContents(); // Skips over the assign token and name of the variable // @@ -189,13 +167,13 @@ namespace LX } // Helper function to call the top of the Parse-Call-Stack // - static inline std::unique_ptr Parse(Parser& p) + static inline std::unique_ptr Parse(ParserInfo& p) { // Parses the current token // 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], p.file); + ThrowIf(out == nullptr, Token::UNDEFINED, p.tokens[p.index - 1], "top level statement", p); return out; } @@ -207,7 +185,7 @@ namespace LX // Creates the output storer and the parser // FileAST output; - Parser p(tokens, path); + ParserInfo p(tokens, path); // Loops over the tokens and calls the correct parsing function // // Which depends on their type and current state of the parser // @@ -225,11 +203,11 @@ namespace LX FunctionDefinition& func = output.functions.back(); // Assigns the function name // - ThrowIf(p.tokens[p.index].type != Token::IDENTIFIER, Token::IDENTIFIER, "", p.tokens[p.index], p.file); + ThrowIf(p.tokens[p.index].type != Token::IDENTIFIER, Token::IDENTIFIER, p); func.name = p.tokens[p.index++].GetContents(); // Checks for opening paren '(' // - ThrowIf(p.tokens[p.index].type != Token::OPEN_PAREN, Token::OPEN_PAREN, "", p.tokens[p.index], p.file); + ThrowIf(p.tokens[p.index].type != Token::OPEN_PAREN, Token::OPEN_PAREN, p); p.index++; // Loops over all the arguments of the function // @@ -243,7 +221,7 @@ namespace LX p.index++; // Checks for opening bracket '{' // - ThrowIf(p.tokens[p.index].type != Token::OPEN_BRACKET, Token::OPEN_BRACKET, "", p.tokens[p.index], p.file); + ThrowIf(p.tokens[p.index].type != Token::OPEN_BRACKET, Token::OPEN_BRACKET, p); p.index++; // Loops over the body until it reaches the end // diff --git a/Parser/src/ParserErrors.cpp b/Parser/src/ParserErrors.cpp index b5dd0d5..b931eb7 100644 --- a/Parser/src/ParserErrors.cpp +++ b/Parser/src/ParserErrors.cpp @@ -1,6 +1,9 @@ #include -#include +#include + +#include +#include namespace LX { @@ -13,8 +16,14 @@ namespace LX return "IR Generation Error"; } - UnexpectedToken::UnexpectedToken(Token::TokenType _expected, std::string _override, Token _got, const std::filesystem::path& _file) - : expected(_expected), override(_override), got(_got), file(_file) + // Constructor to set the members of the error // + UnexpectedToken::UnexpectedToken(Token::TokenType _expected, const ParserInfo& p) + : file(p.file), expected(Token::UNDEFINED), custom(""), got(p.tokens[p.index]) + {} + + // Constructor for custom messages in the cmd // + UnexpectedToken::UnexpectedToken(Token::TokenType _expected, Token _got, const std::string& message, const ParserInfo& p) + : file(p.file), expected(_expected), custom(message), got(_got) {} void UnexpectedToken::PrintToConsole() const @@ -40,7 +49,7 @@ namespace LX std::cout << " expected: "; // Allows the error to have a custom type that is printed to the console // - if (expected == LX::Token::UNDEFINED) { PrintAsColor(override.c_str()); } + if (expected == LX::Token::UNDEFINED) { PrintAsColor(custom); } else { PrintAsColor(ToString(expected).c_str()); } std::cout << "\n"; @@ -57,20 +66,20 @@ namespace LX return "Unexpected Token"; } - void Scope::VariableAlreadyExists::PrintToConsole() const + void VariableAlreadyExists::PrintToConsole() const { } - const char* Scope::VariableAlreadyExists::ErrorType() const + const char* VariableAlreadyExists::ErrorType() const { return "Variable Already Exists"; } - void Scope::VariableDoesntExist::PrintToConsole() const + void VariableDoesntExist::PrintToConsole() const { } - const char* Scope::VariableDoesntExist::ErrorType() const + const char* VariableDoesntExist::ErrorType() const { return "Variable Doesn't exist"; } diff --git a/Parser/src/Scope.cpp b/Parser/src/Scope.cpp index bfe65ab..25e4f5e 100644 --- a/Parser/src/Scope.cpp +++ b/Parser/src/Scope.cpp @@ -2,6 +2,7 @@ #include +#include #include namespace LX @@ -29,7 +30,7 @@ namespace LX llvm::AllocaInst* Scope::CreateVar(const std::string& name, InfoLLVM& LLVM) { // Checks variable of the same name doesn't exist // - ThrowIf(GetVar(name) != nullptr); + ThrowIf(GetVar(name) != nullptr); // Else inserts it into the local set // m_LocalVariables[name] = LLVM.builder.CreateAlloca(LLVM.builder.getInt32Ty(), nullptr, name);