diff --git a/IR-Generator/inc/Lexer.h b/IR-Generator/inc/Lexer.h index c452108..3784d2e 100644 --- a/IR-Generator/inc/Lexer.h +++ b/IR-Generator/inc/Lexer.h @@ -75,6 +75,10 @@ namespace LX IDENTIFIER, RETURN, + // Built-in types // + + INT_DEC, + // Symbols // OPEN_BRACKET, CLOSE_BRACKET, @@ -83,6 +87,10 @@ namespace LX COMMA, + // + + ASSIGN, + // Operators // ADD, SUB, MUL, DIV, diff --git a/IR-Generator/inc/Parser.h b/IR-Generator/inc/Parser.h index 7a8ebfa..f66cfa6 100644 --- a/IR-Generator/inc/Parser.h +++ b/IR-Generator/inc/Parser.h @@ -3,6 +3,7 @@ // Lexer foward declares fstream components so we can use them here // #include +#include #include // Foward declares STD stuff that is passed around // @@ -77,8 +78,51 @@ namespace LX Token got; }; + class Scope + { + public: + // Struct to store all the info of a variable (excluding name as that is stored in the map) // + struct __declspec(novtable) Variable final + { + // Default constructor // + Variable() {} + + // Will hold the type as part of the type here // + + // The value of the variable // + llvm::Value* val = nullptr; + }; + + // Error thrown if the user tried to create a variable that already existed // + struct __declspec(novtable) VariableAlreadyExists final {}; + + // Error thrown if user tries to access variable that does not exist // + struct __declspec(novtable) VariableDoesntExist final {}; + + // Default constructor // + Scope() + : m_LocalVariables{}, m_Child(nullptr) + {} + + // Gets a variable from the scope by it's name // + Variable* GetVarOfName(const std::string& name); + + // Creates a variable of the given name, returns nullptr if a variable with that name already exists // + Variable* CreateVar(const std::string& name); + + private: + // Base logic for getting a variable by it's name without any error checking // + Variable* GetVarOfNameImpl(const std::string& name); + + // Holds all the variables in the scope (excluding ones owned by the children // + std::unordered_map m_LocalVariables; + + // Holds a section of the scope, for example the variables created in a while loop // + std::unique_ptr m_Child; + }; + // Holds all needed info about a function // - // Currently only holds the body but in the future will hold: name, params, namespace/class-member + // Currently only holds the body but in the future will hold: params, namespace/class-member // struct FunctionDefinition { // Defualt constructor (none other given) // @@ -86,6 +130,9 @@ namespace LX // The name of the function // std::string name; + + // The scope off the function // + Scope scope; // The instructions of the body of the function // std::vector> body; diff --git a/IR-Generator/src/main.cpp b/IR-Generator/src/main.cpp index 0d86555..d959dfa 100644 --- a/IR-Generator/src/main.cpp +++ b/IR-Generator/src/main.cpp @@ -182,7 +182,7 @@ int main(int argc, char** argv) LX::PrintStringAsColor(std::string(1, e.invalid), LX::Color::LIGHT_RED); std::cout << "}:\n"; std::cout << "Line: " << std::setw(lineNumberWidthInConsole) << e.line << " | " << line << "\n"; - std::cout << " " << std::setw(lineNumberWidthInConsole) << "" << " | " << std::setw(e.col + 1); + std::cout << " " << std::setw(lineNumberWidthInConsole) << "" << " | " << std::setw(e.col - 1) << ""; LX::PrintStringAsColor("^", LX::Color::LIGHT_RED); std::cout << "\n"; @@ -217,7 +217,7 @@ int main(int argc, char** argv) // Prints the code with the error to the console // std::string errorSquiggle(e.got.length, '~'); std::cout << "Line: " << std::setw(lineNumberWidthInConsole) << e.got.line << " | " << line << "\n"; - std::cout << " " << std::setw(lineNumberWidthInConsole) << "" << " | " << std::setw(e.got.column + 1) << ""; + std::cout << " " << std::setw(lineNumberWidthInConsole) << "" << " | " << std::setw(e.got.column) << ""; LX::PrintStringAsColor(errorSquiggle, LX::Color::LIGHT_RED); std::cout << "\n"; diff --git a/Lexer/src/Lexer.cpp b/Lexer/src/Lexer.cpp index a64a203..ce25689 100644 --- a/Lexer/src/Lexer.cpp +++ b/Lexer/src/Lexer.cpp @@ -40,6 +40,8 @@ namespace LX TOKEN_CASE(Token::CLOSE_BRACKET); TOKEN_CASE(Token::OPEN_PAREN); TOKEN_CASE(Token::CLOSE_PAREN); + TOKEN_CASE(Token::ASSIGN); + TOKEN_CASE(Token::INT_DEC); default: return "Unknown: " + std::to_string(type); @@ -102,7 +104,8 @@ namespace LX { "else" , Token::ELSE }, { "elif" , Token::ELIF }, { "func" , Token::FUNCTION }, - { "return" , Token::RETURN } + { "return" , Token::RETURN }, + { "int" , Token::INT_DEC } }; // All the symbols supported by the lexer // @@ -114,7 +117,8 @@ namespace LX { ']', Token::CLOSE_BRACE }, { '(', Token::OPEN_PAREN }, { ')', Token::CLOSE_PAREN }, - { ',', Token::COMMA } + { ',', Token::COMMA }, + { '=', Token::ASSIGN } }; // All the single-char operators currently supported by the lexer with their token-enum equivalents // diff --git a/Parser/Parser.vcxproj b/Parser/Parser.vcxproj index 34fa5eb..95d4545 100644 --- a/Parser/Parser.vcxproj +++ b/Parser/Parser.vcxproj @@ -144,6 +144,7 @@ + diff --git a/Parser/Parser.vcxproj.filters b/Parser/Parser.vcxproj.filters index e4d3224..4a73ab0 100644 --- a/Parser/Parser.vcxproj.filters +++ b/Parser/Parser.vcxproj.filters @@ -26,6 +26,9 @@ Source Files + + Source Files + diff --git a/Parser/inc/AST.h b/Parser/inc/AST.h index c1d4c22..9df97b8 100644 --- a/Parser/inc/AST.h +++ b/Parser/inc/AST.h @@ -65,7 +65,7 @@ namespace LX::AST class ReturnStatement : public Node { public: - // Constructor to set values and automatically set type + // Constructor to set values and automatically set type // ReturnStatement(std::unique_ptr val); // Function for generating LLVN IR (Intermediate representation) // @@ -78,4 +78,24 @@ namespace LX::AST // What it is returning (can be null) // std::unique_ptr m_Val; }; + + // Node to represent the declaration of a variable within the AST // + class VariableDeclaration : public Node + { + public: + // Constructor to set values and automatically set type // + VariableDeclaration(const std::string& name); + + // Function for generating LLVN IR (Intermediate representation) // + llvm::Value* GenIR(InfoLLVM& LLVM) override; + + // Function to log the node to a file // + void Log(std::ofstream* log, unsigned depth) override; + + private: + // Name of the variable // + std::string m_Name; + + // Doesnt need to store type as everything is currently int // + }; } \ No newline at end of file diff --git a/Parser/src/AST-LLVM.cpp b/Parser/src/AST-LLVM.cpp index b02215e..5524cff 100644 --- a/Parser/src/AST-LLVM.cpp +++ b/Parser/src/AST-LLVM.cpp @@ -66,4 +66,9 @@ namespace LX::AST return out; } } + + // Function for generating LLVN IR (Intermediate representation) // + llvm::Value* VariableDeclaration::GenIR(InfoLLVM& LLVM) + { + } } diff --git a/Parser/src/Scope.cpp b/Parser/src/Scope.cpp new file mode 100644 index 0000000..263f6e2 --- /dev/null +++ b/Parser/src/Scope.cpp @@ -0,0 +1,67 @@ +#include + +#include + +namespace LX +{ + // Util function for getting a pointer to an item from a map // + static inline Scope::Variable* GetFromMap(const std::string& name, std::unordered_map& map) + { + // Checks if it is in a map and if so returns it // + if (auto it = map.find(name); it != map.end()) { return &it->second; } + + // Else returns null // + else { return nullptr; } + } + + // Base logic for getting a variable by it's name without any error checking // + Scope::Variable* Scope::GetVarOfNameImpl(const std::string& name) + { + // Stores the current scope that is being checked for the variable // + Scope* current = this; + + // Loops over the scope and it's child to find the variable // + do + { + // Gets the variable (if it exists) // + Variable* var = GetFromMap(name, current->m_LocalVariables); + + // Returns the variable if it exists // + if (var != nullptr) { return var; } + + // Assigns current to the child to recursively check // + // Doing it like this avoids recursive functions // + current = current->m_Child.get(); + + } while (current != nullptr); + + // Else returns a nullptr and lets the caller handle the error checking // + return nullptr; + } + + // Gets a variable from the scope by it's name // + Scope::Variable* Scope::GetVarOfName(const std::string& name) + { + // Gets the variable (if it exists) // + Variable* var = GetVarOfNameImpl(name); + + // Throws an error if the variable doesn't exist // + ThrowIf(var == nullptr); + + // Else it can return the variable // + return var; + } + + // Creates a variable of the given name, returns nullptr if a variable with that name already exists // + Scope::Variable* Scope::CreateVar(const std::string& name) + { + // Checks if a variable with the same name already exists // + Variable* alreadyExist = GetVarOfNameImpl(name); + + // Throws an error if the variable already exists // + ThrowIf(alreadyExist != nullptr); + + // Else creates the variable and returns it // + return &m_LocalVariables[name]; + } +} diff --git a/example/main.lx b/example/main.lx index 487384e..63ad11d 100644 --- a/example/main.lx +++ b/example/main.lx @@ -1,4 +1,4 @@ func main() { - return 1 + 2 + int a = 5 }