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 @@ Console true - 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); }