diff --git a/Common/Common.vcxproj b/Common/Common.vcxproj
new file mode 100644
index 0000000..9b8525d
--- /dev/null
+++ b/Common/Common.vcxproj
@@ -0,0 +1,144 @@
+
+
+
+
+ Debug
+ Win32
+
+
+ Release
+ Win32
+
+
+ Debug
+ x64
+
+
+ Release
+ x64
+
+
+
+ 17.0
+ Win32Proj
+ {3125ca11-9f6d-4a4f-afc1-37feb3bbd9fa}
+ Common
+ 10.0
+
+
+
+ Application
+ true
+ v143
+ Unicode
+
+
+ Application
+ false
+ v143
+ true
+ Unicode
+
+
+ StaticLibrary
+ true
+ v143
+ Unicode
+
+
+ Application
+ false
+ v143
+ true
+ Unicode
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Level3
+ true
+ WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions)
+ true
+
+
+ Console
+ true
+
+
+
+
+ Level3
+ true
+ true
+ true
+ WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions)
+ true
+
+
+ Console
+ true
+ true
+ true
+
+
+
+
+ Level3
+ true
+ _DEBUG;_CONSOLE;%(PreprocessorDefinitions)
+ true
+ stdcpp20
+ $(SolutionDir)common;%(AdditionalIncludeDirectories)
+
+
+ Console
+ true
+
+
+
+
+ Level3
+ true
+ true
+ true
+ NDEBUG;_CONSOLE;%(PreprocessorDefinitions)
+ true
+
+
+ Console
+ true
+ true
+ true
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/Common/Common.vcxproj.filters b/Common/Common.vcxproj.filters
new file mode 100644
index 0000000..4db1d4a
--- /dev/null
+++ b/Common/Common.vcxproj.filters
@@ -0,0 +1,39 @@
+
+
+
+
+ {4FC737F1-C7A5-4376-A066-2A32D752A2FF}
+ cpp;c;cc;cxx;c++;cppm;ixx;def;odl;idl;hpj;bat;asm;asmx
+
+
+ {67DA6AB6-F800-4c08-8B7A-83BB121AAD01}
+ rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms
+
+
+ {93995380-89BD-4b04-88EB-625FBE52EBFB}
+ h;hh;hpp;hxx;h++;hm;inl;inc;ipp;xsd
+
+
+
+
+ inclu
+
+
+ inclu
+
+
+ inclu
+
+
+ inclu
+
+
+ inclu
+
+
+
+
+ Source Files
+
+
+
\ No newline at end of file
diff --git a/Common/Console.h b/Common/Console.h
new file mode 100644
index 0000000..6feeb46
--- /dev/null
+++ b/Common/Console.h
@@ -0,0 +1,27 @@
+#pragma once
+
+#include
+
+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);
+}
diff --git a/Common/src/Console.cpp b/Common/src/Console.cpp
new file mode 100644
index 0000000..1513663
--- /dev/null
+++ b/Common/src/Console.cpp
@@ -0,0 +1,22 @@
+#include
+
+#include
+#include
+
+namespace LX
+{
+ void PrintStringAsColor(const std::string& str, Color c)
+ {
+ // Gets a handle to the console //
+ HANDLE hConsole = GetStdHandle(STD_OUTPUT_HANDLE);
+
+ // Sets the color of the console to the desired color //
+ SetConsoleTextAttribute(hConsole, (WORD)c);
+
+ // Outputs the text //
+ std::cout << str;
+
+ // Resets the color //
+ SetConsoleTextAttribute(hConsole, (WORD)Color::LIGHT_GRAY);
+ }
+}
diff --git a/LX-Compiler.sln b/LX-Compiler.sln
index f51b97d..3838c05 100644
--- a/LX-Compiler.sln
+++ b/LX-Compiler.sln
@@ -5,6 +5,7 @@ VisualStudioVersion = 17.13.35931.197
MinimumVisualStudioVersion = 10.0.40219.1
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "LX-Compiler", "LX-LLVM.vcxproj", "{CC37E36F-B3B3-41B0-A887-01E8EFE84994}"
ProjectSection(ProjectDependencies) = postProject
+ {3125CA11-9F6D-4A4F-AFC1-37FEB3BBD9FA} = {3125CA11-9F6D-4A4F-AFC1-37FEB3BBD9FA}
{4E4019F5-12E0-4EE2-9658-A0DD3038EEDA} = {4E4019F5-12E0-4EE2-9658-A0DD3038EEDA}
{D6EAFB31-4AFD-4989-9522-D6609AC4ED64} = {D6EAFB31-4AFD-4989-9522-D6609AC4ED64}
EndProjectSection
@@ -15,6 +16,10 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Frontend-Modules", "Fronten
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Parser", "Parser\Parser.vcxproj", "{D6EAFB31-4AFD-4989-9522-D6609AC4ED64}"
EndProject
+Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Util", "Util", "{0E83E43A-13FB-422F-B903-96E3E8F74DC2}"
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Common", "Common\Common.vcxproj", "{3125CA11-9F6D-4A4F-AFC1-37FEB3BBD9FA}"
+EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|x64 = Debug|x64
@@ -47,6 +52,14 @@ Global
{D6EAFB31-4AFD-4989-9522-D6609AC4ED64}.Release|x64.Build.0 = Release|x64
{D6EAFB31-4AFD-4989-9522-D6609AC4ED64}.Release|x86.ActiveCfg = Release|Win32
{D6EAFB31-4AFD-4989-9522-D6609AC4ED64}.Release|x86.Build.0 = Release|Win32
+ {3125CA11-9F6D-4A4F-AFC1-37FEB3BBD9FA}.Debug|x64.ActiveCfg = Debug|x64
+ {3125CA11-9F6D-4A4F-AFC1-37FEB3BBD9FA}.Debug|x64.Build.0 = Debug|x64
+ {3125CA11-9F6D-4A4F-AFC1-37FEB3BBD9FA}.Debug|x86.ActiveCfg = Debug|Win32
+ {3125CA11-9F6D-4A4F-AFC1-37FEB3BBD9FA}.Debug|x86.Build.0 = Debug|Win32
+ {3125CA11-9F6D-4A4F-AFC1-37FEB3BBD9FA}.Release|x64.ActiveCfg = Release|x64
+ {3125CA11-9F6D-4A4F-AFC1-37FEB3BBD9FA}.Release|x64.Build.0 = Release|x64
+ {3125CA11-9F6D-4A4F-AFC1-37FEB3BBD9FA}.Release|x86.ActiveCfg = Release|Win32
+ {3125CA11-9F6D-4A4F-AFC1-37FEB3BBD9FA}.Release|x86.Build.0 = Release|Win32
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
@@ -54,6 +67,7 @@ Global
GlobalSection(NestedProjects) = preSolution
{4E4019F5-12E0-4EE2-9658-A0DD3038EEDA} = {02EA681E-C7D8-13C7-8484-4AC65E1B71E8}
{D6EAFB31-4AFD-4989-9522-D6609AC4ED64} = {02EA681E-C7D8-13C7-8484-4AC65E1B71E8}
+ {3125CA11-9F6D-4A4F-AFC1-37FEB3BBD9FA} = {0E83E43A-13FB-422F-B903-96E3E8F74DC2}
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {411AFEC9-4075-4FCC-B95A-9288BC822E90}
diff --git a/LX-LLVM.vcxproj b/LX-LLVM.vcxproj
index b747bea..2bf7af3 100644
--- a/LX-LLVM.vcxproj
+++ b/LX-LLVM.vcxproj
@@ -112,7 +112,7 @@
Consoletrue
- Lexer.lib;Parser.lib;Ws2_32.lib;%(AdditionalDependencies)
+ Lexer.lib;Parser.lib;Common.lib;Ws2_32.lib;%(AdditionalDependencies)$(SolutionDir)$(Platform)\$(Configuration)\;%(AdditionalLibraryDirectories)
@@ -139,11 +139,6 @@
-
-
-
-
-
diff --git a/LX-LLVM.vcxproj.filters b/LX-LLVM.vcxproj.filters
index 87e8a8f..d3e9077 100644
--- a/LX-LLVM.vcxproj.filters
+++ b/LX-LLVM.vcxproj.filters
@@ -1,22 +1,5 @@
-
-
- {93995380-89BD-4b04-88EB-625FBE52EBFB}
- h;hh;hpp;hxx;h++;hm;inl;inc;ipp;xsd
-
-
-
-
- Common
-
-
- Common
-
-
- Common
-
-
diff --git a/Lexer/src/Lexer.cpp b/Lexer/src/Lexer.cpp
index ee4fc86..65afcb6 100644
--- a/Lexer/src/Lexer.cpp
+++ b/Lexer/src/Lexer.cpp
@@ -7,6 +7,7 @@
#include
#include
+#include
namespace LX
{
@@ -32,12 +33,41 @@ namespace LX
TOKEN_CASE(Token::MUL);
TOKEN_CASE(Token::DIV);
TOKEN_CASE(Token::NUMBER_LITERAL);
+ TOKEN_CASE(Token::RETURN);
default:
return "Unknown: " + std::to_string(type);
}
}
+ // 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;
+ };
+
// All the keywords the lexer currently supports with their token-enum equivalents //
static const std::unordered_map keywords =
{
@@ -61,46 +91,21 @@ namespace LX
};
// Checks if the given word is a keyword before adding it to the tokens //
- static void TokenizeWord(const std::string& word, std::vector& tokens)
+ static void TokenizeWord(const std::string& word, std::vector& tokens, LexerInfo& info)
{
// Checks the map for a check and if so adds it with its enum equivalent //
if (auto keyword = keywords.find(word); keyword != keywords.end())
{
- tokens.push_back({ keyword->second, "" });
+ tokens.push_back({ keyword->second, "", info.line, info.column - (std::streamsize)word.size(), (std::streamsize)word.size()});
}
// Else adds it as a type of IDENTIFIER //
else
{
- tokens.push_back({ Token::IDENTIFIER, word });
+ tokens.push_back({ Token::IDENTIFIER, word, info.line, info.column - (std::streamsize)word.size(), (std::streamsize)word.size()});
}
}
- // Struct to store the current information of the lexer //
- struct LexerInfo
- {
- // Current index within the lexer //
- std::streamsize index = 0;
-
- // 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;
- };
-
const std::vector LX::LexicalAnalyze(std::ifstream& src, std::ofstream* log)
{
// Logs the start of the lexical analysis
@@ -168,7 +173,7 @@ namespace LX
{
// Adds the string literal token to the token vector //
std::string lit(contents.data() + info.startOfStringLiteral, info.index - info.startOfStringLiteral);
- tokens.push_back({ Token::STRING_LITERAL, lit });
+ tokens.push_back({ Token::STRING_LITERAL, lit, info.line, info.column - (std::streamsize)lit.length(), (std::streamsize)lit.length() });
// Updates trackers //
info.inStringLiteral = false;
@@ -197,7 +202,7 @@ namespace LX
if (info.isNextCharAlpha == false)
{
// Calls the function designed to handle the tokenisation of words //
- TokenizeWord({ contents.data() + info.startOfWord, 1 }, tokens);
+ TokenizeWord({ contents.data() + info.startOfWord, 1 }, tokens, info);
}
}
@@ -205,7 +210,7 @@ namespace LX
else if (info.isAlpha == true && info.isNextCharAlpha == false)
{
// Calls the function designed to handle the tokenisation of words //
- TokenizeWord({ contents.data() + info.startOfWord, (unsigned __int64)((info.index + 1) - info.startOfWord) }, tokens);
+ TokenizeWord({ contents.data() + info.startOfWord, (unsigned __int64)((info.index + 1) - info.startOfWord) }, tokens, info);
}
// During a word //
@@ -222,7 +227,7 @@ namespace LX
{
// Pushes the number to the token vector. Number literals are stored as string in the tokens //
std::string num(contents.data() + info.startOfNumberLiteral, (unsigned __int64)(info.index + 1) - info.startOfNumberLiteral);
- tokens.push_back({ Token::NUMBER_LITERAL, num });
+ tokens.push_back({ Token::NUMBER_LITERAL, num, info.line, info.column - (std::streamsize)num.size(), (std::streamsize)num.size()});
}
}
@@ -231,7 +236,7 @@ namespace LX
{
// Pushes the number to the token vector. Number literals are stored as string in the tokens //
std::string num(contents.data() + info.startOfNumberLiteral, (unsigned __int64)(info.index + 1) - info.startOfNumberLiteral);
- tokens.push_back({ Token::NUMBER_LITERAL, num });
+ tokens.push_back({ Token::NUMBER_LITERAL, num, info.line, info.column - (std::streamsize)num.size(), (std::streamsize)num.size()});
}
// During a number //
@@ -240,21 +245,49 @@ namespace LX
// Operators (+, -, /, *) //
else if (auto op = operators.find(current); op != operators.end())
{
- tokens.push_back({ op->second, "" });
+ tokens.push_back({ op->second, "", info.line, info.column, 1});
}
// If it is here and not whitespace that means it's an invalid character //
- else if (current == ' ' || current == '\t' || current == '\r' || current == '\n');
+ else if (current == ' ' || current == '\r');
+
+ // Skips over an extra 3 spaces as tabs SHOULD ALWAYS take up 4 spaces //
+ // Only for the column and not index //
+ else if (current == '\t')
+ {
+ info.column = info.column + 3;
+ }
+
+ // Increments the line number and resets the column on entering a new line //
+ else if (current == '\n')
+ {
+ info.column = 0;
+ info.line++;
+ }
else
{
+ // Finds the start of the line //
+ size_t start = contents.rfind('\n', info.index);
+ if (start == std::string::npos) { start = 0; } // std::npos means none was found so defaults to 1
+ else { start = start + 1; } // Skips the new line character
+
+ // Finds the end of the line //
+ size_t end = contents.find('\n', info.index);
+ if (end == std::string::npos) { end = contents.size(); } // If it reaches the end with no /n it defaults to the length of the string
+
+ // The line where the invalid character is //
+ std::string line = contents.substr(start, end - start);
+
// Throws an error to alert the user of the invalid character //
- throw InvalidCharInSource(info.index, current);
+ throw InvalidCharInSource(info.column, info.line, line, contents[info.index]);
}
// Updates trackers to their default state of a new character //
info.index++;
+ info.column++;
+
info.wasLastCharAlpha = info.isAlpha;
info.wasLastCharNumeric = info.isNumeric;
}
@@ -266,12 +299,12 @@ namespace LX
{
if (token.contents.empty() == false)
{
- SafeLog(log, ToString(token.type), ":\t", token.contents);
+ SafeLog(log, "{ Line: ", std::left, std::setw(3), token.line, ", Column: ", std::setw(3), token.index, ", Length: ", std::setw(2), token.length, "} ", std::setw(30), ToString(token.type) + ":", "{", token.contents, "}");
}
else
{
- SafeLog(log, ToString(token.type));
+ SafeLog(log, "{ Line: ", std::left, std::setw(3), token.line, ", Column: ", std::setw(3), token.index, ", Length: ", std::setw(2), token.length, "} ", ToString(token.type));
}
}
}
diff --git a/Lexer/src/Token.cpp b/Lexer/src/Token.cpp
index 243b0e3..9f018c4 100644
--- a/Lexer/src/Token.cpp
+++ b/Lexer/src/Token.cpp
@@ -6,7 +6,7 @@
namespace LX
{
// Passes the constructor args to the values //
- Token::Token(const TokenType _type, std::string _contents)
- : type(_type), contents(_contents)
+ Token::Token(const TokenType _type, std::string _contents, std::streamsize _line, std::streamsize _index, std::streamsize _length)
+ : type(_type), contents(_contents), line(_line), index(_index), length(_length)
{}
}
diff --git a/Main.cpp b/Main.cpp
index 39b4d26..2cd467f 100644
--- a/Main.cpp
+++ b/Main.cpp
@@ -4,6 +4,7 @@
#include
#include
+#include
#include
#include
#include
@@ -20,44 +21,49 @@ namespace LX
int main(int argc, char** argv)
{
+ // Creates the file paths outside of the try-catch so they can be used in errors //
+ std::filesystem::path inpPath;
+ std::filesystem::path outPath;
+
+ // Creates the log-file out of the try-catch so it can be closed propely if an error is thrown //
+ std::unique_ptr log = nullptr;
+
try
{
- // Checks there is the correct ammount of arguments
+ // Checks there is the correct ammount of arguments //
LX::ThrowIf((argc == 3 || argc == 4) == false);
- // Turns the file paths into the C++ type for handling them
- std::filesystem::path inpPath = argv[1];
- std::filesystem::path outPath = argv[2];
+ // Turns the file paths into the C++ type for handling them //
+ inpPath = argv[1];
+ outPath = argv[2];
- // Prints the full paths to the console to let the user know compiling is being done
+ // Prints the full paths to the console to let the user know compiling is being done //
std::cout << std::filesystem::absolute(inpPath) << " -> " << std::filesystem::absolute(outPath) << std::endl;
- // Checks the input file exists and opens it
+ // Checks the input file exists and opens it //
LX::ThrowIf(std::filesystem::exists(inpPath) == false);
- std::ifstream inpFile(inpPath, std::ios::binary | std::ios::ate); // Opens in binary at the end for microptimisation
+ std::ifstream inpFile(inpPath, std::ios::binary | std::ios::ate); // Opens in binary at the end for microptimisation //
LX::ThrowIf(inpFile.is_open() == false);
- // Opens / Creates the output file
+ // Opens / Creates the output file //
std::ofstream outFile(outPath);
LX::ThrowIf(outFile.is_open() == false);
- // Opens / Creates the log file
- std::unique_ptr log = nullptr;
-
+ // Opens the log file (if there is one specified //
if (argc == 4)
{
log = std::make_unique(argv[3]);
LX::ThrowIf(log->is_open() == false);
}
- // Create tokens out of the input file
+ // Create tokens out of the input file //
std::vectortokens = LX::LexicalAnalyze(inpFile, log.get());
- // Turns the tokens into an AST
+ // Turns the tokens into an AST //
LX::FileAST AST = LX::TurnTokensIntoAbstractSyntaxTree(tokens, log.get());
- //
- LX::GenerateIR(AST);
+ // Turns the AST into LLVM IR //
+ LX::GenerateIR(AST, inpPath.filename().string());
// Returns success
return 0;
@@ -89,9 +95,27 @@ int main(int argc, char** argv)
catch (LX::InvalidCharInSource& e)
{
- //
- std::cout << "\nInvalid character found in source file: {" << e.invalid << "} at index: " << e.index << "\n";
+ // Adds the error to the log and closes it to save all the output //
+ LX::SafeLog(log.get(), LX::LOG_BREAK, "Error thrown from Lexer:\n\tInvalid character: ", e.invalid, " on line: ", e.line, LX::LOG_BREAK);
+ if (log != nullptr) { log->close(); }
+ // Calculates the length of the line number in the console so it is formatted correctly //
+ std::ostringstream oss;
+ oss << std::setw(3) << e.line;
+ size_t lineNumberWidthInConsole = std::max(oss.str().size(), (size_t)3);
+
+ // Prints the error with the relevant information to the console //
+ std::cout << "\n";
+ LX::PrintStringAsColor("Error: ", LX::Color::LIGHT_RED);
+ std::cout << "invalid character found in ";
+ LX::PrintStringAsColor(inpPath.filename().string(), LX::Color::WHITE);
+ std::cout << ":\n";
+ std::cout << "Line: " << std::setw(lineNumberWidthInConsole) << e.line << " | " << e.lineContents << "\n";
+ std::cout << " " << std::setw(lineNumberWidthInConsole) << "" << " | " << std::setw(e.index);
+ LX::PrintStringAsColor("^", LX::Color::LIGHT_RED);
+ std::cout << "\n";
+
+ // Returns Exit-id of 4 so other process can be alerted of the error //
return 4;
}
diff --git a/Parser/src/AST-Constructors.cpp b/Parser/src/AST-Constructors.cpp
index e537198..2652900 100644
--- a/Parser/src/AST-Constructors.cpp
+++ b/Parser/src/AST-Constructors.cpp
@@ -11,7 +11,7 @@ namespace LX
// Reserves space for nodes (stops excess allocations) //
FunctionDefinition::FunctionDefinition()
- : body{}
+ : body{}, name{}
{ body.reserve(32); }
// Reserves space for functions (stops excess allocations) //
diff --git a/Parser/src/GenIR.cpp b/Parser/src/GenIR.cpp
index bbe351f..70baf07 100644
--- a/Parser/src/GenIR.cpp
+++ b/Parser/src/GenIR.cpp
@@ -8,7 +8,7 @@
namespace LX
{
// Tells the generator if the current node is allowed to be within a top-level context //
- // TODO: Make this function do something other than return true
+ // TODO: Make this function do something other than return true //
static constexpr bool IsValidTopLevelNode(AST::Node::NodeType type)
{
return true;
@@ -20,7 +20,7 @@ namespace LX
// Creates the functions signature and return type //
llvm::FunctionType* retType = llvm::FunctionType::get(llvm::Type::getInt32Ty(LLVM.context), false); // <- Defaults to int currently
- llvm::Function* func = llvm::Function::Create(retType, llvm::Function::ExternalLinkage, "main", LLVM.module); // Defaults to main currently
+ llvm::Function* func = llvm::Function::Create(retType, llvm::Function::ExternalLinkage, funcAST.name, LLVM.module);
llvm::BasicBlock* entry = llvm::BasicBlock::Create(LLVM.context, "entry", func);
LLVM.builder.SetInsertPoint(entry);
@@ -42,10 +42,10 @@ namespace LX
}
// Turns an abstract binary tree into LLVM intermediate representation //
- void GenerateIR(FileAST& ast)
+ void GenerateIR(FileAST& ast, const std::string& name)
{
// Creates the LLVM variables needed for generating IR that are shared between functions //
- InfoLLVM LLVM("add_itns");
+ InfoLLVM LLVM(name);
// Loops over the functions to generate their LLVM IR //
for (auto& func : ast.functions)
diff --git a/Parser/src/Parser.cpp b/Parser/src/Parser.cpp
index fd108c0..28c91ee 100644
--- a/Parser/src/Parser.cpp
+++ b/Parser/src/Parser.cpp
@@ -7,6 +7,12 @@
namespace LX
{
+ template
+ static inline void ExpectToken(const Token& t)
+ {
+ ThrowIf(type != t.type);
+ }
+
// Local struct so everything can be public //
struct Parser
{
@@ -118,14 +124,17 @@ namespace LX
{
case Token::FUNCTION:
{
- // Skips over function token + name token
- // TODO: Store function name in the type
- p.index++; p.index++;
+ // Skips over function token + name token //
+ p.index++;
// Pushes a new function to the vector and gets a reference to it for adding the body //
output.functions.emplace_back();
FunctionDefinition& func = output.functions.back();
+ // Assigns the function name //
+ ExpectToken(p.tokens[p.index]);
+ func.name = p.tokens[p.index++].contents;
+
// Loops over the body until it reaches the end //
// TODO: Detect the end instead of looping over the entire token vector
while (p.index < p.len)
@@ -144,7 +153,8 @@ namespace LX
// Lets the user know there is an error //
// TODO: Makes this error actually output useful information //
default:
- std::cout << "UNKNOWN TOKEN FOUND" << std::endl;
+ std::cout << "UNKNOWN TOKEN FOUND: " << p.tokens[p.index].type << std::endl;
+ return output;
}
}
diff --git a/common/Lexer.h b/common/Lexer.h
index 44a00e1..02dc405 100644
--- a/common/Lexer.h
+++ b/common/Lexer.h
@@ -28,13 +28,17 @@ namespace LX
struct InvalidCharInSource
{
std::streamsize index;
+ std::streamsize line;
+
+ std::string lineContents;
+
char invalid;
};
// Data type to store a more computer readable version of files
struct __declspec(novtable) Token final
{
- // Enum to hold the type of the token
+ // Enum to hold the type of the token //
enum TokenType : short
{
// General tokens //
@@ -60,18 +64,27 @@ namespace LX
UNDEFINED = -1
};
- // Constructor of the tokens to set their info
- Token(const TokenType _type, std::string _contents);
+ // Constructor of the tokens to set their info //
+ Token(const TokenType _type, std::string _contents, std::streamsize _line, std::streamsize _index, std::streamsize _length);
- // Contents of the token (may be empty if not needed)
- // Const to avoid external changes
+ // Contents of the token (may be empty if not needed) //
+ // Const to avoid external changes //
const std::string contents;
- // Type of the token
- // Const to avoid external changes
+ // Type of the token //
+ // Const to avoid external changes //
const TokenType type;
+
+ // The line where the token is located in the source //
+ const std::streamsize line;
+
+ // Index on the line where the token starts //
+ const std::streamsize index;
+
+ // The length of the token on the line, may be different to the length of contents //
+ const std::streamsize length;
};
- // Lexer function to take in a file and output a vector of tokens
+ // Lexer function to take in a file and output a vector of tokens //
const std::vector LexicalAnalyze(std::ifstream& src, std::ofstream* log);
}
diff --git a/common/Parser.h b/common/Parser.h
index 9463715..5d19845 100644
--- a/common/Parser.h
+++ b/common/Parser.h
@@ -64,6 +64,9 @@ namespace LX
{
// Defualt constructor (none other given) //
FunctionDefinition();
+
+ // The name of the function //
+ std::string name;
// The instructions of the body of the function //
std::vector> body;
@@ -82,5 +85,5 @@ namespace LX
FileAST TurnTokensIntoAbstractSyntaxTree(std::vector& tokens, std::ofstream* log);
// Turns an abstract binary tree into LLVM intermediate representation //
- void GenerateIR(FileAST& ast);
+ void GenerateIR(FileAST& ast, const std::string& name);
}