mirror of
https://github.com/PashaBibko/LX.git
synced 2026-04-04 01:49:05 +00:00
Organized project files
This commit is contained in:
27
IR-Generator/inc/Console.h
Normal file
27
IR-Generator/inc/Console.h
Normal file
@@ -0,0 +1,27 @@
|
||||
#pragma once
|
||||
|
||||
#include <string>
|
||||
|
||||
namespace LX
|
||||
{
|
||||
enum class Color
|
||||
{
|
||||
BLACK = 0,
|
||||
BLUE = 1,
|
||||
GREEN = 2,
|
||||
AQUA = 3,
|
||||
RED = 4,
|
||||
PURPLE = 5,
|
||||
YELLOW = 6,
|
||||
LIGHT_GRAY = 7,
|
||||
LIGHT_BLUE = 9,
|
||||
LIGHT_GREEN = 10,
|
||||
LIGHT_AQUA = 11,
|
||||
LIGHT_RED = 12,
|
||||
LIGHT_PURPLE = 13,
|
||||
LIGHT_YELLOW = 14,
|
||||
WHITE = 15
|
||||
};
|
||||
|
||||
void PrintStringAsColor(const std::string& str, Color c);
|
||||
}
|
||||
25
IR-Generator/inc/LLVM.h
Normal file
25
IR-Generator/inc/LLVM.h
Normal file
@@ -0,0 +1,25 @@
|
||||
#pragma once
|
||||
|
||||
// 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)
|
||||
#pragma warning(disable : 4267)
|
||||
#pragma warning(disable : 4624)
|
||||
#pragma warning(disable : 4800)
|
||||
|
||||
// Includes the LLVM files //
|
||||
|
||||
#include <llvm/IR/IRBuilder.h>
|
||||
#include <llvm/IR/LLVMContext.h>
|
||||
#include <llvm/IR/Module.h>
|
||||
#include <llvm/IR/Verifier.h>
|
||||
|
||||
// Re-enables all warnings //
|
||||
#pragma warning(pop)
|
||||
|
||||
#else
|
||||
#error This code is only designed to work with MSVC due to the use of vcpkg and other aspects
|
||||
#endif // _MSC_VER
|
||||
122
IR-Generator/inc/Lexer.h
Normal file
122
IR-Generator/inc/Lexer.h
Normal file
@@ -0,0 +1,122 @@
|
||||
#pragma once
|
||||
|
||||
#include <vector>
|
||||
#include <string>
|
||||
|
||||
// Foward declarations of STD classes to minimise includes //
|
||||
namespace std
|
||||
{
|
||||
template<typename T1>
|
||||
struct char_traits;
|
||||
|
||||
template<typename T1, typename T2>
|
||||
class basic_ofstream;
|
||||
|
||||
using ofstream = basic_ofstream<char, char_traits<char>>;
|
||||
}
|
||||
|
||||
// This file contains everything that is exported from Lexer.lib
|
||||
// The rest of the items within the Lexer project are internal only
|
||||
|
||||
namespace LX
|
||||
{
|
||||
// Error type with index and character to alert the user that LX does not understand that symbol //
|
||||
struct InvalidCharInSource
|
||||
{
|
||||
std::streamsize col;
|
||||
std::streamsize line;
|
||||
std::streamsize index;
|
||||
|
||||
char invalid;
|
||||
};
|
||||
|
||||
// Struct to store the current information of the lexer //
|
||||
struct LexerInfo
|
||||
{
|
||||
// Current trackers of where in the source it is //
|
||||
|
||||
std::streamsize line = 1; // <- Lines start on 1 (probably because of non-programmer's)
|
||||
std::streamsize index = 0;
|
||||
std::streamsize column = 0; // <- Columns start on 1 (probably because of non-programmer's)
|
||||
|
||||
// Trackers for when a multi-char token started //
|
||||
|
||||
std::streamsize startOfWord = 0;
|
||||
std::streamsize startOfNumberLiteral = 0;
|
||||
std::streamsize startOfStringLiteral = 0;
|
||||
|
||||
// Different flags of the lexer //
|
||||
// Stored as a bitset to minimse memory allocated (basically no difference, because only one exists at any given time) //
|
||||
|
||||
bool isAlpha : 1 = false;
|
||||
bool isNumeric : 1 = false;
|
||||
bool inComment : 1 = false;
|
||||
bool inStringLiteral : 1 = false;
|
||||
bool isNextCharAlpha : 1 = false;
|
||||
bool isNextCharNumeric : 1 = false;
|
||||
bool wasLastCharAlpha : 1 = false;
|
||||
bool wasLastCharNumeric : 1 = false;
|
||||
bool lexingNumber : 1 = false;
|
||||
};
|
||||
|
||||
// Data type to store a more computer readable version of files
|
||||
struct __declspec(novtable) Token final
|
||||
{
|
||||
//
|
||||
static std::string* source;
|
||||
|
||||
// Enum to hold the type of the token //
|
||||
enum TokenType : short
|
||||
{
|
||||
// General tokens //
|
||||
|
||||
STRING_LITERAL,
|
||||
NUMBER_LITERAL,
|
||||
IDENTIFIER,
|
||||
RETURN,
|
||||
|
||||
// Operators //
|
||||
|
||||
ADD, SUB, MUL, DIV,
|
||||
|
||||
// Keywords //
|
||||
|
||||
FOR, WHILE,
|
||||
IF, ELSE, ELIF,
|
||||
|
||||
FUNCTION,
|
||||
|
||||
// You made a mistake somehow //
|
||||
|
||||
UNDEFINED = -1
|
||||
};
|
||||
|
||||
// Constructor of the tokens to set their info //
|
||||
Token(const TokenType _type, const LexerInfo& info, std::streamsize _length);
|
||||
|
||||
//
|
||||
std::string GetContents() const;
|
||||
|
||||
// Type of the token //
|
||||
// Const to avoid external changes //
|
||||
const TokenType type;
|
||||
|
||||
// Index in the source of the token //
|
||||
const std::streamsize index;
|
||||
|
||||
// The length of the token on the line //
|
||||
const std::streamsize length;
|
||||
|
||||
// The line the token is located on //
|
||||
const std::streamsize line;
|
||||
|
||||
// The column on the line where it is located //
|
||||
const std::streamsize column;
|
||||
};
|
||||
|
||||
// Logging function to turn a tokentype enum val into it's string //
|
||||
std::string ToString(Token::TokenType t);
|
||||
|
||||
// Lexer function to take in a file and output a vector of tokens //
|
||||
const std::vector<Token> LexicalAnalyze(const std::string& contents, const std::streamsize len, std::ofstream* log);
|
||||
}
|
||||
106
IR-Generator/inc/Parser.h
Normal file
106
IR-Generator/inc/Parser.h
Normal file
@@ -0,0 +1,106 @@
|
||||
#pragma once
|
||||
|
||||
// Lexer foward declares fstream components so we can use them here //
|
||||
#include <Lexer.h>
|
||||
|
||||
#include <memory>
|
||||
|
||||
// Foward declares STD stuff that is passed around //
|
||||
namespace std::filesystem { class path; }
|
||||
|
||||
// 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; }
|
||||
|
||||
// Foward declares the wrapper around the LLVM objects we need to pass around //
|
||||
namespace LX { struct InfoLLVM; }
|
||||
|
||||
// The nodes of the abstract syntax tree constructed by the parser from the tokens //
|
||||
namespace LX::AST
|
||||
{
|
||||
// Base node that everything else inherits from
|
||||
struct Node
|
||||
{
|
||||
// Enum for storing the type of node //
|
||||
// Used so a pointer to Node can be used and then turned into it's true type //
|
||||
enum NodeType
|
||||
{
|
||||
// General Nodes //
|
||||
|
||||
IDENTIFIER,
|
||||
NUMBER_LITERAL,
|
||||
OPERATION,
|
||||
|
||||
// Control flow Nodes //
|
||||
|
||||
RETURN_STATEMENT,
|
||||
|
||||
// If an error happened somewhere //
|
||||
UNDEFINED = -1
|
||||
};
|
||||
|
||||
// Constructor to set the node type (no others provided) //
|
||||
Node(NodeType type);
|
||||
|
||||
// Virtual destructor because of polymorphism //
|
||||
virtual ~Node() = default;
|
||||
|
||||
// Function for generating LLVN IR (Intermediate representation) //
|
||||
virtual llvm::Value* GenIR(InfoLLVM& LLVM) = 0;
|
||||
|
||||
// Function for generating C/C++ code (Currently not implemented) //
|
||||
//virtual void GenC() = 0;
|
||||
|
||||
// The type of the node //
|
||||
const NodeType m_Type;
|
||||
};
|
||||
}
|
||||
|
||||
namespace LX
|
||||
{
|
||||
// Thrown if there was an error during IR Generation //
|
||||
struct IRGenerationError {};
|
||||
|
||||
// Thrown if there was an unexpected (incorrect) token //
|
||||
struct UnexpectedToken
|
||||
{
|
||||
// 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;
|
||||
};
|
||||
|
||||
// Holds all needed info about a function //
|
||||
// Currently only holds the body but in the future will hold: name, params, namespace/class-member
|
||||
struct FunctionDefinition
|
||||
{
|
||||
// Defualt constructor (none other given) //
|
||||
FunctionDefinition();
|
||||
|
||||
// The name of the function //
|
||||
std::string name;
|
||||
|
||||
// The instructions of the body of the function //
|
||||
std::vector<std::unique_ptr<AST::Node>> body;
|
||||
};
|
||||
|
||||
struct FileAST
|
||||
{
|
||||
// Default constructor (none other given) //
|
||||
FileAST();
|
||||
|
||||
// All the functions within this file //
|
||||
std::vector<FunctionDefinition> functions;
|
||||
};
|
||||
|
||||
// Turns the tokens of a file into it's abstract syntax tree equivalent //
|
||||
FileAST TurnTokensIntoAbstractSyntaxTree(std::vector<Token>& tokens, std::ofstream* log);
|
||||
|
||||
// Turns an abstract binary tree into LLVM intermediate representation //
|
||||
void GenerateIR(FileAST& ast, const std::string& name, const std::filesystem::path& IRPath);
|
||||
}
|
||||
34
IR-Generator/inc/Util.h
Normal file
34
IR-Generator/inc/Util.h
Normal file
@@ -0,0 +1,34 @@
|
||||
#pragma once
|
||||
|
||||
#include <fstream>
|
||||
|
||||
// Defining this is only if you are at the point where you should be using a debugger //
|
||||
#define LOG_EVERYTHING
|
||||
|
||||
namespace LX
|
||||
{
|
||||
template<typename T, typename... Args>
|
||||
// Helper function to throw given error if condition is true //
|
||||
// Also micro-optimises to predict there is no errors thrown //
|
||||
inline void ThrowIf(const bool condition, Args... args)
|
||||
{ if (condition) [[unlikely]] { throw T(args...); }}
|
||||
|
||||
template<typename... Args>
|
||||
// Helper function for logging //
|
||||
// Only logs the given args if the log is not null //
|
||||
inline void SafeLog(std::ofstream* log, Args... args)
|
||||
{
|
||||
if (log != nullptr) { (*log << ... << args); *log << "\n"; }
|
||||
}
|
||||
|
||||
inline void SafeFlush(std::ofstream* log)
|
||||
{
|
||||
if (log != nullptr)
|
||||
{
|
||||
log->flush();
|
||||
}
|
||||
}
|
||||
|
||||
// Gives a standard way to mark a change between different sections within the log output //
|
||||
constexpr const char* LOG_BREAK = "\n-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-\n";
|
||||
}
|
||||
Reference in New Issue
Block a user