mirror of
https://github.com/PashaBibko/LX.git
synced 2026-04-03 17:39:02 +00:00
Tided up Parser project
This commit is contained in:
@@ -147,9 +147,9 @@
|
||||
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">Create</PrecompiledHeader>
|
||||
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Release|x64'">Create</PrecompiledHeader>
|
||||
</ClCompile>
|
||||
<ClCompile Include="src\AST-Constructors.cpp" />
|
||||
<ClCompile Include="src\AST-LLVM.cpp" />
|
||||
<ClCompile Include="src\AST-Loggers.cpp" />
|
||||
<ClCompile Include="src\AST\AST-Constructors.cpp" />
|
||||
<ClCompile Include="src\AST\AST-LLVM.cpp" />
|
||||
<ClCompile Include="src\AST\AST-Loggers.cpp" />
|
||||
<ClCompile Include="src\GenIR.cpp" />
|
||||
<ClCompile Include="src\Parser.cpp" />
|
||||
<ClCompile Include="src\ParserErrors.cpp" />
|
||||
@@ -157,6 +157,8 @@
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="inc\AST.h" />
|
||||
<ClInclude Include="inc\ParserErrors.h" />
|
||||
<ClInclude Include="inc\ParserInfo.h" />
|
||||
</ItemGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
|
||||
<ImportGroup Label="ExtensionTargets">
|
||||
|
||||
@@ -9,23 +9,17 @@
|
||||
<UniqueIdentifier>{93995380-89BD-4b04-88EB-625FBE52EBFB}</UniqueIdentifier>
|
||||
<Extensions>h;hh;hpp;hxx;h++;hm;inl;inc;ipp;xsd</Extensions>
|
||||
</Filter>
|
||||
<Filter Include="Source Files\AST">
|
||||
<UniqueIdentifier>{344a1f33-e6b1-4bf7-b3b4-ec5b8c726d40}</UniqueIdentifier>
|
||||
</Filter>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="src\Parser.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="src\AST-Constructors.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="src\AST-LLVM.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="src\GenIR.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="src\AST-Loggers.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="src\Scope.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
@@ -35,10 +29,25 @@
|
||||
<ClCompile Include="inc\pch.cpp">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="src\AST\AST-Constructors.cpp">
|
||||
<Filter>Source Files\AST</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="src\AST\AST-LLVM.cpp">
|
||||
<Filter>Source Files\AST</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="src\AST\AST-Loggers.cpp">
|
||||
<Filter>Source Files\AST</Filter>
|
||||
</ClCompile>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="inc\AST.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="inc\ParserErrors.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="inc\ParserInfo.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
43
Parser/inc/ParserErrors.h
Normal file
43
Parser/inc/ParserErrors.h
Normal file
@@ -0,0 +1,43 @@
|
||||
#pragma once
|
||||
|
||||
#include <LX-Common.h>
|
||||
|
||||
#include <ParserInfo.h>
|
||||
#include <Lexer.h>
|
||||
|
||||
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;
|
||||
};
|
||||
}
|
||||
33
Parser/inc/ParserInfo.h
Normal file
33
Parser/inc/ParserInfo.h
Normal file
@@ -0,0 +1,33 @@
|
||||
#pragma once
|
||||
|
||||
#include <LX-Common.h>
|
||||
|
||||
// Includes Lexer so it can use LX::Token //
|
||||
#include <Lexer.h>
|
||||
|
||||
namespace LX
|
||||
{
|
||||
// Local struct so everything can be public //
|
||||
struct ParserInfo
|
||||
{
|
||||
// Passes constructor args to members //
|
||||
ParserInfo(const std::vector<Token>& _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<Token>& 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;
|
||||
};
|
||||
}
|
||||
@@ -2,6 +2,7 @@
|
||||
|
||||
#include <Parser.h>
|
||||
|
||||
#include <ParserErrors.h>
|
||||
#include <AST.h>
|
||||
|
||||
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<Scope::VariableDoesntExist>(asignee == nullptr);
|
||||
ThrowIf<VariableDoesntExist>(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<Scope::VariableDoesntExist>(var == nullptr);
|
||||
ThrowIf<VariableDoesntExist>(var == nullptr);
|
||||
|
||||
// Creates the load within the AST //
|
||||
return LLVM.builder.CreateLoad(llvm::Type::getInt32Ty(LLVM.context), var, m_Name + "_val");
|
||||
@@ -2,6 +2,7 @@
|
||||
|
||||
#include <Parser.h>
|
||||
|
||||
#include <ParserErrors.h>
|
||||
#include <AST.h>
|
||||
|
||||
namespace LX
|
||||
|
||||
@@ -2,6 +2,8 @@
|
||||
|
||||
#include <Parser.h>
|
||||
|
||||
#include <ParserErrors.h>
|
||||
#include <ParserInfo.h>
|
||||
#include <AST.h>
|
||||
|
||||
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<Token>& _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<Token>& 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<AST::Node> ParsePrimary(Parser& p)
|
||||
static std::unique_ptr<AST::Node> 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<UnexpectedToken>(p.scopeDepth == 0, Token::UNDEFINED, "need a different error", p.tokens[p.index], p.file);
|
||||
ThrowIf<UnexpectedToken>(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<AST::Node> ParseOperation(Parser& p)
|
||||
static std::unique_ptr<AST::Node> 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<AST::Node> lhs = ParsePrimary(p);
|
||||
ThrowIf<UnexpectedToken>(lhs == nullptr, Token::UNDEFINED, "value", p.tokens[p.index - 1], p.file);
|
||||
ThrowIf<UnexpectedToken>(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<AST::Node> rhs = ParseOperation(p);
|
||||
ThrowIf<UnexpectedToken>(rhs == nullptr, Token::UNDEFINED, "value", p.tokens[p.index - 1], p.file);
|
||||
ThrowIf<UnexpectedToken>(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<AST::Operation>(std::move(lhs), op, std::move(rhs));
|
||||
@@ -112,7 +90,7 @@ namespace LX
|
||||
}
|
||||
|
||||
// Handles return statements, if not calls ParseOperation //
|
||||
static std::unique_ptr<AST::Node> ParseReturn(Parser& p)
|
||||
static std::unique_ptr<AST::Node> 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<AST::Node> ParseVarDeclaration(Parser& p)
|
||||
static std::unique_ptr<AST::Node> 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<UnexpectedToken>(p.tokens[p.index].type != Token::IDENTIFIER, Token::IDENTIFIER, "", p.tokens[p.index], p.file);
|
||||
ThrowIf<UnexpectedToken>(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<AST::Node> defaultVal = ParsePrimary(p);
|
||||
ThrowIf<UnexpectedToken>(defaultVal.get() == nullptr, Token::UNDEFINED, "value", p.tokens[p.index - 1], p.file);
|
||||
ThrowIf<UnexpectedToken>(defaultVal.get() == nullptr, Token::UNDEFINED, p.tokens[p.index - 1], "value", p);
|
||||
|
||||
return std::make_unique<AST::VariableDeclaration>(name);
|
||||
}
|
||||
@@ -162,7 +140,7 @@ namespace LX
|
||||
}
|
||||
|
||||
// Handles variable assignments, if not calls ParseVarDeclaration //
|
||||
static std::unique_ptr<AST::Node> ParseVarAssignment(Parser& p)
|
||||
static std::unique_ptr<AST::Node> 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<UnexpectedToken>(p.tokens[p.index].type != Token::IDENTIFIER, Token::IDENTIFIER, "", p.tokens[p.index], p.file);
|
||||
ThrowIf<UnexpectedToken>(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<AST::Node> Parse(Parser& p)
|
||||
static inline std::unique_ptr<AST::Node> Parse(ParserInfo& p)
|
||||
{
|
||||
// Parses the current token //
|
||||
std::unique_ptr<AST::Node> out = ParseVarAssignment(p);
|
||||
|
||||
// Checks it is valid before returning //
|
||||
ThrowIf<UnexpectedToken>(out == nullptr, Token::UNDEFINED, "top level statement", p.tokens[p.index - 1], p.file);
|
||||
ThrowIf<UnexpectedToken>(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<UnexpectedToken>(p.tokens[p.index].type != Token::IDENTIFIER, Token::IDENTIFIER, "", p.tokens[p.index], p.file);
|
||||
ThrowIf<UnexpectedToken>(p.tokens[p.index].type != Token::IDENTIFIER, Token::IDENTIFIER, p);
|
||||
func.name = p.tokens[p.index++].GetContents();
|
||||
|
||||
// Checks for opening paren '(' //
|
||||
ThrowIf<UnexpectedToken>(p.tokens[p.index].type != Token::OPEN_PAREN, Token::OPEN_PAREN, "", p.tokens[p.index], p.file);
|
||||
ThrowIf<UnexpectedToken>(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<UnexpectedToken>(p.tokens[p.index].type != Token::OPEN_BRACKET, Token::OPEN_BRACKET, "", p.tokens[p.index], p.file);
|
||||
ThrowIf<UnexpectedToken>(p.tokens[p.index].type != Token::OPEN_BRACKET, Token::OPEN_BRACKET, p);
|
||||
p.index++;
|
||||
|
||||
// Loops over the body until it reaches the end //
|
||||
|
||||
@@ -1,6 +1,9 @@
|
||||
#include <LX-Common.h>
|
||||
|
||||
#include <Parser.h>
|
||||
#include <ParserErrors.h>
|
||||
|
||||
#include <ParserInfo.h>
|
||||
#include <Lexer.h>
|
||||
|
||||
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<Color::WHITE>(override.c_str()); }
|
||||
if (expected == LX::Token::UNDEFINED) { PrintAsColor<Color::WHITE>(custom); }
|
||||
else { PrintAsColor<Color::WHITE>(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";
|
||||
}
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
|
||||
#include <Parser.h>
|
||||
|
||||
#include <ParserErrors.h>
|
||||
#include <AST.h>
|
||||
|
||||
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<Scope::VariableAlreadyExists>(GetVar(name) != nullptr);
|
||||
ThrowIf<VariableAlreadyExists>(GetVar(name) != nullptr);
|
||||
|
||||
// Else inserts it into the local set //
|
||||
m_LocalVariables[name] = LLVM.builder.CreateAlloca(LLVM.builder.getInt32Ty(), nullptr, name);
|
||||
|
||||
Reference in New Issue
Block a user